千万级数据并发解决方案
数据多、并发高: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查询,如果确实要用的话,注意时间开销
-