千万级数据并发解决方案

数据多、并发高:mysql

  • 程序用到哪几个字段就查询哪几个字段,尽量避免select * 查询

  • 一次用多少数据,就返回多少数据:加limit限制

 

Mysql数据库索引添加原则

  • 针对热点字段添加索引

  • 索引不一定是越多越好,因为会影响insert、update、delete的效率(修改表数据的时候,mysql需要同步更新索引)

  • 索引最好在开发的时候创建好,尽量避免在生产环境中创建索引(数据量大的时候,创建耗时较长,会影响业务)

 

大数据量情况下,执行sql前最好执行一下【执行计划】

EXPLAIN select * from article where author='xxx'

 

 

Cache-Aside(旁路缓存策略)

  • 读:

    • 先从缓存里读数据,如果读到了就直接返回数据。

    • 如果读不到数据,从数据库中读数据,然后存到Cache里

  • 写:

    • 方案一:更新完数据后,删除Cache

    • 方案二:更新完数据后,不删除Cache,直接更新它

缺陷1:首次请求数据一定不在Cache里,需要到数据库中查询一下。

解决方案:可以提前把相关数据放到Cache中,称为“预热”数据

 

缺陷2:对于写操作比较频繁的数据,直接造成缓存命中率较低。这时候缓存的意义就不大了。

1、要么不缓存这种数据,要么换缓存策略
2、数据库数据和Cache中的数据不要求强一致:异步更新DB和Cache
3、数据库数据和Cache中的数据必须强一致:分布式锁

 

Read/Write-Through(读写穿透策略)

  • 读:

    • 从Cache读数据,如果读到数据就直接返回;如果读不到数据的话,从数据库中加载,然后写入到Cache里

  • 写:

    • 先查一下Cache,如果Cache中不存在的话,直接更新数据库;如果Cache中存在,先更新Cache,然后Cache自己更新数据库(相当于同步更新数据库和Cache)

缺点:参考【Cache-Aside(旁路缓存策略)】

 

Write-Behind(异步缓存写入策略)

  • 写:只操作Cache,不操作数据库。什么时候写到数据库?异步写入数据库(可以写一个命令行程序定时把Cache中的数据更新到数据库)

应用场景:文章或商品的浏览量、点赞量、关注量等对数据的实时性要求不高的场景。

 

什么样的数据不适合放到Cache里?

  • 体积太大的数据不适合。(1、消耗内存。2、网络负载比较高(web和redis不在同一台机器上))

  • 频繁变动的数据,考虑一下是否需要放到缓存中

 

 

ab压力测试(apachebench的缩写)

原理:ab程序会创建多个并发的访问线程,模拟多个访问者同时对某一个url进行访问。所以,它可以测试的服务器类型可以是apache,也可以是nginx、tomcat服务器,也可以是IIS服务器

注意:ab程序对发出负载的机器要求很低,也就是说它占用的cpu和内存非常低。但是因为它模拟大量的用户请求,所以会给目标服务器造成巨大的负载。比较类似CC攻击。所以我们自己测试的时候,注意控制好请求量

ab的安装

  • windows:apache的bin目录里的ab.exe

  • linux:apache的/usr/bin/ab

  • 只想用ab工具,不想安装Apache,怎么办?

1、服务器是windows server:在开发机上,到apache的bin目录下,拷贝ab.exe到服务器上就行。
2、服务器是centos:安装httpd-tools,yum -y install httpd-tools

 

 

ab的版本:ab -V

ab程序的参数说明

-n在测试会话中所执行的请求个数。默认时,仅执行一个请求。
-c一次产生的请求个数。默认是一次一个。
-t测试所进行的最大秒数。其内部隐含值是-n 50000,它可以使对服务器的测试限制在一个固定的总时间以内。默认时,没有时间限制。
-p包含了需要POST的数据的文件。
-P对一个中转代理提供BASIC认证信任。用户名和密码由一个:隔开,并以base64编码形式发送。无论服务器是否需要(即, 是否发送了401认证需求代码),此字符串都会被发送。
-T POST数据所使用的Content-type头信息。
-v设置显示信息的详细程度-4或更大值会显示头信息,3或更大值可以显示响应代码(404,200等),2或更大值可以显示警告和其他信息。
-V显示版本号并退出。
-w以HTML表的格式输出结果。默认时,它是白色背景的两列宽度的一张表。
-i执行HEAD请求,而不是GET。
-x设置<table>属性的字符串。
-X对请求使用代理服务器。
-y设置<tr>属性的字符串。
-z设置<td>属性的字符串。
-C对请求附加一个Cookie:行。其典型形式是name=value的一个参数对,此参数可以重复。
-H对请求附加额外的头信息。此参数的典型形式是一个有效的头信息行,其中包含了以冒号分隔的字段和值的对(如,"Accept-Encoding:zip/zop;8bit")。
-A对服务器提供BASIC认证信任。用户名和密码由一个:隔开,并以base64编码形式发送。无论服务器是否需要(即,是否发送了401认证需求代码),此字符串都会被发送。
-h显示使用方法。
-d不显示"percentage served within XX [ms] table"的消息(为以前的版本提供支持)。
-e产生一个以逗号分隔的(CSV)文件,其中包含了处理每个相应百分比的请求所需要(从1%到100%)的相应百分比的(以微妙为单位)时间。由于这种格式已经“二进制化”,所以比'gnuplot'格式更有用。
-g把所有测试结果写入一个'gnuplot'或者TSV(以Tab分隔的)文件。此文件可以方便地导入到Gnuplot,IDL,Mathematica,Igor甚至Excel中。其中的第一行为标题。
-i执行HEAD请求,而不是GET。
-k启用HTTP KeepAlive功能,即在一个HTTP会话中执行多个请求。默认时,不启用KeepAlive功能。
-q如果处理的请求数大于150,ab每处理大约10%或者100个请求时,会在stderr输出一个进度计数。此-q标记可以抑制这些信息。

 

ab测试结果

如:ab -c 10 -n 1000 http://lv.php.com/index/index

Concurrency Level:  10
模拟的客户端的数量(10个客户端)
Time taken for tests:   19.113 seconds
处理完1000个请求所话费的总时间
Complete requests:      1000
总共完成了多少个请求
Failed requests:        0
失败的请求数
Total transferred:      896000 bytes
所有请求的响应数据长度的总长度,包含每个http请求的头信息(header)和正文数据(body)
HTML transferred:       673000 bytes
所有请求数据的正文的长度
Requests per second:    52.32 [#/sec] (mean)
每秒钟执行的请求数---吞吐率。值越大越好
(第一个)Time per request:       191.131 [ms] (mean)
客户端平均每个请求的等待时间
(第二个)Time per request:       19.113 [ms] (mean, across all concurrent requests)
服务器端平均每个请求的等待时间
Transfer rate:          45.78 [Kbytes/sec] received
数据传输速率。值越大越好
​
Connection Times (ms)
                      min  mean[+/-sd] median   max
(连接时间)Connect:        0    0   0.4      0       1
(处理时间)Processing:    98  189 103.5    179    1342
(等待时间)Waiting:       98  189 103.5    179    1342
(总时间 )Total:         98  190 103.5    179    1342
​
​
Percentage of the requests served within a certain time (ms)
  50%    179
  66%    182
  75%    184
  80%    186
  90%    194
  95%    200
  98%    245
  99%    284
 100%   1342 (longest request)
 完成本次测试的时间分布,一般关注90%的处理时间

 

 

Elasticsearch搜索引擎

  • 索引(和mysql的索引是完全不同的概念)。类似于mysql的表

  • 文档(类似于mysql表中的一条条记录)

如果操作Elasticsearch?

1、初始化:

$hosts = ['127.0.0.1:9200'];
$client = \Elasticsearch\ClientBuilder::create()->setHosts($hosts)->build();

 

2、创建索引

$params = [
            'index' => 'article',   // 索引的名称(相当于mysql中的表名)  
            'body' =>[
                'settings' => [
                    'number_of_shards' => 5,    // 设置数据的分片数,默认值是5
                    'number_of_replicas'=>0,    // 数据的备份数(如果只有一台机器,设置为0)
                ],
                'mappings' => [
                    'properties'=>[
                        'id' => [
                            'type' => 'integer',
                        ],
                        'cid' => [
                            'type' => 'integer',
                        ],
                        'title' => [
                            'type' => 'text',               // text类型,做模糊搜索用
                            'analyzer'=>'ik_max_word',      // 较细粒度分词,写入数据用
                            'search_analyzer'=>'ik_smart',  // 较粗粒度分词,查询数据用
                        ],
                        'descs' => [
                            'type' => 'text',
                            'analyzer'=>'ik_max_word',
                            'search_analyzer'=>'ik_smart',
                        ],
                        'author' => [
                            'type' => 'keyword',            // keyword类型,做精确搜索用
                        ],
                    ],
                ],
            ],
        ];
        $res = $client->indices()->create($params);
        注意:索引不存在,就创建它。如果已存在,会报异常

 

3、创建文档

$params = [
    'index' => 'article',
    'type' =>'_doc',
    'id' => $item->id,
    'body' =>[
    'id' => $item->id,
    'cid' => $item->cid,
    'title'=> $item->title,
    'descs'=>$item->descs,
    'author' => $item->author,
    ]
];
$res = $client->index($params);
注意:该文档不存在就创建一个,存在的话,就更新它

 

4、搜索文档

$eswhere = [];
        // 搜索条件
        $eswhere['bool']['must'][] = ['match_phrase'=>['title'=>$keyword]];
        $eswhere['bool']['must'][] = ['match_phrase'=>['descs'=>$keyword]];
        // 排序条件
        $esorder = ['id'=>'DESC'];
​
        $where = [
            // size和from组合可以用于分页
            'size'=>10, // 取10条数据
            'from'=>0,  // 从第几条开始取
            'index' =>'article',    // 从哪个索引中查
            'type'=>'_doc',
            'body'=>[
                'query'=>$eswhere,  // 查询条件
                'sort'=>$esorder,   // 排序条件,注意,加上以后,_score没有值
                // 高亮显示
                'highlight'=>[
                    'fields'=>[
                        'title'=>[
                            'pre_tags'=>['<span style="color:red">'],
                            'post_tags'=>['</span>'],
                        ],
                        'descs'=>[
                            'pre_tags'=>['<span style="color:red">'],
                            'post_tags'=>['</span>'],
                        ]
                    ]
                ]
            ]
        ];
        $res = $client->search($where);

 

5、删除文档

$client->delete(['index'=>'article','id'=>$i]);

 

6、删除索引

$client->indices()->delete(['index'=>'article']);
注意:如果该索引已经删除了,重复删除会报异常

 

 

在linux(centos7)中安装elasticsearch

  • centos7系统设置

注意:visualbox中,要先在“设置”中把网卡的连接方式改为“桥接网卡”(默认是网络地址转换NAT模式)
1、网卡设置为“桥接模式”
2、cd /etc/sysconfig/network-scripts
3、vi ifcfg-enp0s3
修改两个参数:
ONBOOT=no 改为:ONBOOT=yes
BOOTPROTO=dhcp 改为:BOOTPROTO=static
增加以下IP配置
IPADDR=192.168.31.34
NETMASK=255.255.255.0
GATEWAY=192.168.31.1
DNS1=114.114.114.114
保存退出后,重启网络(service network restart)
验证一下网络:ping www.baidu.com。如果能ping通,说明网络配置OK了
​

 

  • 下载elasticsearch

如果centos7是纯净系统(minimal版本的)
1、安装wget下载工具:yum -y install wget
2、进入一个目录里,如:cd /home 注意:最好不要在系统目录里下载文件
3、wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.16.1-linux-x86_64.tar.gz

 

  • 安装elasticsearch

注意:先把系统的防火墙关掉
service firewalld stop
​
1、解压压缩包
tar -xzvf elasticsearch-7.16.1-linux-x86_64.tar.gz
cd elasticsearch-7.16.1/config
2、修改配置文件
vi elasticsearch.yml
network.host:0.0.0.0
http.port:9200
node.name:node-1
cluster.initial_master_nodes:["node-1"]
3、cd /home/elasticsearch-7.16.1/bin
4、创建一个新的用户
useradd es
5、切换到es帐号下
su es
6、启动elasticsearch
./elasticsearch
==========================可能会报异常========================
一般需要设置一下centos的系统文件
vi /etc/security/limits.conf
直接在文件的最后增加以下几行参数
* soft nofile 65536
* hard nofile 65536
* soft nproc 65536
* hard nproc 65536
保存后退出
vi /etc/sysctl.conf
直接在文件的最后增加下面的参数
vm.max_map_count=655360
保存后退出
​
执行sysctl -p
然后再次到elasticsearch的bin目录下执行./elasticsearch
在局域网(当前的windows电脑)的浏览器中输入 192.168.31.34:9200,能访问,说明安装配置OK了

 

  • 安装ik分词插件

1、进入到/home/elasticsearch-7.16.1/plugins目录
2、创建一个目录,如:mkdir ik
3、进入ik目录中。cd ik
4、wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.16.1/elasticsearch-analysis-ik-7.16.1.zip --no-check-certificate
5、解压
unzip elasticsearch-analysis-ik-7.16.1.zip
6、重启elasticsearch
注意:不要在plugins目录里留无关的目录或文件

 

 

高并发/大数据量下,代码编写原则

  • 尽量少用或不用join查询,如果确实要用的话,注意时间开销

  • 尽量不在循环里操作数据库

posted @ 2023-06-19 15:10  Mrterrific  阅读(228)  评论(0编辑  收藏  举报