千万级数据并发解决方案(理论+实战)
课程地址
项目地址
场景
秒杀 高并发
新闻系统 超大数据量
一般的网站 写入的少 读取的次数多
模糊查询
数据量少的时候可以用 like
数据量多的时候用 Elasticsearch搜索引擎 占用磁盘空间比较大
生成数据
SET FOREIGN_KEY_CHECKS=0;DROP TABLE IF EXISTS `article_tmp`;CREATE TABLE `article_tmp` ( `id` int(10) NOT NULL AUTO_INCREMENT, `title` varchar(255) NOT NULL, `url` varchar(255) NOT NULL, `descs` varchar(255) NOT NULL, `author` varchar(255) NOT NULL, `add_time` varchar(255) NOT NULL, `from` varchar(255) NOT NULL, PRIMARY KEY (`id`)) ENGINE=MyISAM AUTO_INCREMENT=201 DEFAULT CHARSET=utf8;INSERT INTO `article_tmp` VALUES ('1', '模型驱动设计的构造块(下)——DDD', 'https://www.cnblogs.com/afei-24/p/16985996.html', '3. 领域对象的生命周期 每个对象都有生命周期,如下图所示。对象自创建后,可能会经历各种不同的状态,直至最终消亡——要么存档,要么删除。当然很多对象是简单的临时对象,仅通过调用构造函数来创建,用来做一些计算,然后由垃圾收集器回收。这类对象没必要搞得那么复杂。但有些对象具有更长的生命周期,其中一部分时 ...', 'Ruby_Lu', '2023-01-06 07:22', 'https://www.cnblogs.com');INSERT INTO `article_tmp` VALUES ('2', 'IT编程相关内容汇总 - 进阶者系列 - 学习者系列文章', 'https://www.cnblogs.com/lzhdim/p/17028789.html', '笔者工作了十多年了,对于技术也有一定的经验,但是IT编程技术的更新是挺快的,特别是各种框架,各种中间件啥的都涌现出来了。这篇博文笔者打算将IT编程的前端、后端、数据库和移动端做一个博文知识汇总,让阅读笔者博客的读者能够有一个系统化学习编程技术的博文。前面已经有一个博文进行过相关的介绍,但是那个比较普 ...', 'lzhdim', '2023-01-06 00:00', 'https://www.cnblogs.com');INSERT INTO `article_tmp` VALUES ('3', '小白致力于成为前后端开发程序员', 'https://www.cnblogs.com/pocn/p/16857245.html', '小白有个烦恼,做前端项目的时候,遇到两种情况一种是在vue框架下,使用HTML写页面,script部分代码里面的方法基本上使用JS来写;一种同样在vue框架下,通过安装的框架来构建页面,script中使用的方法也多是安装的框架中封装好的方法。小白是个倒霉催的孩子,负责的项目比较多,常常在两种情况下切 ...', 'BOBO~', '2023-01-05 22:51', 'https://www.cnblogs.com');INSERT INTO `article_tmp` VALUES ('4', 'BST查找结构与折半查找方法的实现与实验比较', 'https://www.cnblogs.com/Az1r/p/17028980.html', '简介 作业:查找结构与排序方法 作业题目: BST 查找结构与折半查找方法的实现与实验比较 要求编写程序实现 BST 存储结构的建立(插入)、删除、查找和排序算法; 实现折半查找算法;比较 BST 查找与折半查找方法的时间性能。 作业要求: 1. 设计 BST 的左右链存储结构,并实现 BST 插入 ...', '江水为竭', '2023-01-05 22:12', 'https://www.cnblogs.com');INSERT INTO `article_tmp` VALUES ('5', 'Java开发学习(五十)----MyBatisPlus快速开发之代码生成器解析', 'https://www.cnblogs.com/xiaoyh/p/16468217.html', '1、代码生成器原理分析 造句: 我们可以往空白内容进行填词造句,比如: 在比如: 观察我们之前写的代码,会发现其中也会有很多重复内容,比如: 那我们就想,如果我想做一个Book模块的开发,是不是只需要将红色部分的内容全部更换成Book即可,如: 所以我们会发现,做任何模块的开发,对于这段代码,基本上 ...', '|旧市拾荒|', '2023-01-05 21:57', 'https://www.cnblogs.com');INSERT INTO `article_tmp` VALUES ('6', 'VMware搭建内网渗透环境', 'https://www.cnblogs.com/LeslieSec/p/17028722.html', '网络结构: 攻击机:kali 192.168.1.103 DMZ区域:防火墙 WAN:192.168.1.104 LAN:192.168.10.10 winserver03 LAN:192.168.10.11 用户办公区域:路由器 WAN:192.168.10.20 LAN:192.168.20.1 ...', '林烬', '2023-01-05 21:21', 'https://www.cnblogs.com');INSERT INTO `article_tmp` VALUES ('7', '自动增长配置不合理导致的性能抖动', 'https://www.cnblogs.com/zhuancloud/p/17028870.html', '背景 客户收到了SQL专家云告警邮件,在凌晨2点到3点之间带有资源等待的会话数暴增,请我们协助分析。 现象 登录SQL专家云,进入活动会话的趋势分析页面,下钻到2点钟一个小时内的数据,看到每分钟的等待数都在100左右,2点15分时达到200。 转到活动会话原始数据页面,看到大量会话都在等待,等待类型 ...', '格瑞趋势技术团队', '2023-01-05 21:07', 'https://www.cnblogs.com');INSERT INTO `article_tmp` VALUES ('8', 'C | 指针', 'https://www.cnblogs.com/lijiuliang/p/17028849.html', '1.什么是指针 指针是一种变量,也称指针变量,它的值不是整数、浮点数和字符,而是内存地址。指针的值就是变量的地址,而变量有拥有一个具体值。因此,可以理解为变量直接引用了一个值,指针间接地引用了一个值。一个存放变量地址的类型称为该变量的“指针”。 指针变量的大小? 以32位系统为例,每个字节(即一个内 ...', '就良同学', '2023-01-05 20:54', 'https://www.cnblogs.com');INSERT INTO `article_tmp` VALUES ('9', '07.synchronized都问啥?', 'https://www.cnblogs.com/wyz1994/p/17028834.html', '大家好,我是王有志。关注王有志,一起聊技术,聊游戏,从北漂生活谈到国际风云。最近搞了个抽奖送书的活动,欢迎点击链接参与。 如果Java面试有什么是必问的,synchronized必定占据一席之地。初出茅庐时synchronized的用法,成长后synchronized的原理,可谓是Java工程师的“ ...', '王有志', '2023-01-05 20:48', 'https://www.cnblogs.com');INSERT INTO `article_tmp` VALUES ('10', 'JavaScript 中如何拦截全局 Fetch API 的请求和响应?', 'https://www.cnblogs.com/wenruo/p/17028832.html', '本文翻译自 Intercepting JavaScript Fetch API requests and responses 拦截器是可用于预处理或后处理 HTTP 请求的代码块,有助于全局错误处理、身份验证、日志记录等。在本文中,你将学习如何拦截 JavaScript Fetch API 请求。 ...', '我不吃饼干呀', '2023-01-05 20:47', 'https://www.cnblogs.com');INSERT INTO `article_tmp` VALUES ('11', '.gitignore文件配置以及gitee提交报Push rejected...错误解决', 'https://www.cnblogs.com/wren/p/17028830.html', '.gitignore文件配置 .gitignore 文件可以用来忽略被指定的文件或文件夹的改动。记录在.gitignore文件里的文件或文件夹是不会被 git 跟踪到,也就是被忽略的文件是不会被上传到远程仓库的,如果文件已经存在于远程仓库中就无法通过.gitignore文件来忽略。 下面总结了一些可 ...', '请叫我阿杰', '2023-01-05 20:46', 'https://www.cnblogs.com');INSERT INTO `article_tmp` VALUES ('12', 'Ventoy制作启动盘和使用VMware测试启动盘(论文版)', 'https://www.cnblogs.com/alittlemc/p/17027815.html', 'Ventoy是可用于制作启动U盘的开源工具,在占用少量引导分区容量后,其他空间依旧可以正常当一般的U盘读写文件。它的最大特点是只要将iso、win、img、efi等之类的镜像文件和引导文件移动到U盘中。比如导出微PE、杏雨梨云的可启动iso镜像文件,移动到U盘中,在启动时选择微PE、杏雨梨云任意一个... ...', 'alittlemc', '2023-01-05 20:45', 'https://www.cnblogs.com');INSERT INTO `article_tmp` VALUES ('13', 'JUC并发编程详解(通俗易懂)', 'https://www.cnblogs.com/ZhangHao-Study/p/16994667.html', '一、JUC简介 在Java5.0提供了java.util.concurrent包,简称JUC,即Java并发编程工具包。JUC更好的支持高并发任务。 具体的有以下三个包: java.util.concurrent java.util.concurrent.atomic java.util.concu ...', '九八十', '2023-01-05 20:39', 'https://www.cnblogs.com');
在laravel中 创建
要提前配置好数据库
//创建新的命令类php artisan make:command Tests//创建后使用命令php artisan app:tests
在Tests文件中写入
use DB;public function handle(){ echo Date('Y-m-d H-i-s')."\r\n"; $lists = DB::table('article_tmp')->get()->toArray(); for ($i = 0; $i url; $data['cid']=rand(1,50); $data['title'] .=mb_substr($lists[$val]->title,0,rand(2,16)); $data['descs'] .=mb_substr($lists[$val]->descs,rand(0,16),rand(32,64)); $data['author']=$lists[$val]->author; $data['add_time']=$lists[$val]->add_time; $data['from']=$lists[$val]->from; } DB::table('article')->insert($data); }; echo Date('Y-m-d H-i-s')."\r\n";}
运行命令 php artisan app:tests
生成数据
mysql查询原则
数据多 并发高
字段越多 体积越大
- 程序用到哪几个字段就查询哪几个字段,尽量避免select * 查询
- 一次用多少数据,就返回多少数据:加limit限制
- 尽量用 = ,and 不要用 >,< ,,or
- 字段设计尽量 不为null
添加索引
- 针对热点字段添加索引
- 索引不一定是越多越好 因为会影响 insert,update,delete 的效率 (修改表数据的时候 ,mysql需要同步更新索引)
- 索引最好在开发的时候创建好,尽量避免在生产环境中创建索引(数据量大的时候,创建耗时较长,会影响业务)
一旦发生 扫表 效率是最低的
EXPLAIN 查看执行计划
EXPLAIN SELECT * FROM article
WHERE author = “就良同学” and cid = 50;
最重要的两个字段 possible_keys key 如果为空 说明发生扫表
possible_keys 可能会用都到的索引
key 实际会用到的索引
rows 预估值
select_type (SIMPLE) 简单查询
id | select_type | possible_keys | key | rows |
---|---|---|---|---|
1 | SIMPLE | cid,author | author | 700 |
大数据量下进行的查询 最好先查看执行计划
EXPLAIN SELECT * FROM
article WHERE author = "就良同学" and cid = 50;
使用缓存
一个简单使用本地文件来当缓存
public function index(){ $data= ''; $cache_file = 'article_cid.txt'; if(!file_exists($cache_file)){ //创建文件 file_put_contents($cache_file,''); } //读取数据 $data = file_get_contents($cache_file); if($data){ $data= json_decode($data); dump($data); return ; } //没有数据 $data=DB::table('article')->where('cid',21)->paginate(20); file_put_contents($cache_file,json_encode($data)); dump($data);}
缓存策略旁路缓存策略
Cache-Aside
- 读:
- 先到缓存里面读数据,如果读到了就直接返回数据
- 如果读不到数据,从数据库中读数据,然后存到 cache中
- 写:
- 方案一. 更新完数据后 ,删除缓存
- 方案一. 更新完数据后,不删除缓存,直接更新它
缺陷1:首次请求 数据一定不在 cache里面 ,需要到数据库中查询一下.
解决方方案 : 可以提前把数据放到 cache里面 , ‘预热数据’
缺陷2:对于写操作比较频繁的数据,直接造成缓存命中率较低。这时候缓存的意义就不大了。
解决方案:
- 要么不缓存这种数据,要么换缓存策略
- 数据库数据和Cache中的数据不要求强一致:异步更新DB和Cache,
- 数据库数据和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设置属性的字符串。-X对请求使用代理服务器。-y设置属性的字符串。-z设置属性的字符串。-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 1342Percentage 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%的处理时间
es扩展 (elasticsearch )
官网: https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html
文档:
https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/getting-started-php.html
软件下载: https://elasticsearch.cn/download/
扩展安装
composer require elasticsearch/elasticsearch
ElasticSearch重置密码步骤(忘记密码的情况)
1.停止Elasticsearch服务2.编辑elasticsearch.yml文件,设置以下两项为false;xpack.security.enabled: falsexpack.security.transport.ssl.enabled: false3.重启es服务,删除.security-7索引curl -XDELETE -u elastic:changeme http://localhost:9200/.security-73.关闭ES服务设置以下两项为true;xpack.security.enabled: truexpack.security.transport.ssl.enabled: true4.重启es服务,进入es的bin目录下./elasticsearch-setup-passwords interactive依次设置每个账号密码即可
获取密码:
进入es安装目录的bin文件中执行一下命令会返回最新的密码
命令 : elasticsearch-reset-password -u elastic
默认用户名: elastic
密码: QhW4NJSQGzP13o2kVI6o
修改密码的其他命令
https://devpress.csdn.net/cloud-native/65195642aae4e179c0b77cc4.html
开启各种安全验证后需要ssl证书才能正常登录
xpack.security.enabled: truexpack.security.enrollment.enabled: truexpack.security.http.ssl: enabled: true keystore.path: certs/http.p12xpack.security.transport.ssl: enabled: true verification_mode: certificate keystore.path: certs/transport.p12 truststore.path: certs/transport.p12
证书位置 config\certs\http_ca.crt
config/es.php
文件配置
return [ 'host'=>['https://127.0.0.1:9200'], 'user'=>'elastic', 'pwd'=>'VX_IuVXQ6_WcfmBO8Mxc',];
//初始化use Elastic\Elasticsearch\ClientBuilder;use Elastic\Elasticsearch\Exception\ClientResponseException;use Elastic\Elasticsearch\Exception\ServerResponseException;$client = ClientBuilder::create() ->setHosts(config('es.host')) ->setBasicAuthentication(config('es.user'), config('es.pwd')) ->setCABundle('cacrt/http_ca.crt') ->build();
分词器要下载对应的版本
https://github.com/medcl/elasticsearch-analysis-ik
下载地址
https://github.com/medcl/elasticsearch-analysis-ik/releases
下载后解压到 plugins/ik
目录下面 重启 es即可
//创建映射curl -XPOST http://localhost:9200/index/_mapping -H 'Content-Type:application/json' -d'{ "properties": { "content": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_smart" } }}'
案例 增删查改
client = $this->_init_es(); } public function index() { // 创建索引 // $res = $this->_create_index(); // dd($res); // $item = DB::table('article')->first(); // dd($item); // $article_list = DB::table('article')->where('id', 'get()->toArray(); // foreach ($article_list as $item) { // $this->insert_update($item); // } //把数据写入搜索引擎 // $res=$this->insert_update($item); // dd($res); //删除文档 // $this->del_doc(); //删除索引 $this->del_index(); //全文搜索 // $res = $this->dosearch('C'); // echo ""; // print_r($res); } //初始化es private function _init_es() { $es_config = [ 'host' => ['https://127.0.0.1:9200'], 'user' => 'elastic', 'pwd' => 'QhW4NJSQGzP13o2kVI6o', 'cacrt' => base_path() . '\private\certs\http_ca.crt', ]; $client = ClientBuilder::create() ->setHosts($es_config['host']) ->setBasicAuthentication($es_config['user'], $es_config['pwd']) ->setCABundle($es_config['cacrt']) ->build(); return $client; } //创建索引 private function _create_index() { $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', ], 'author' => [ 'type' => 'keyword', // keyword类型,做精确搜索用 ], ], ], ], ]; $res = $this->client->indices()->create($params); // 注意:索引不存在,就创建它。如果已存在,会报异常 return $res; } //写入文档数据(_doc 相当于 mysql表中的一条记录) private function insert_update($item) { $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 = $this->client->index($params); // 注意:该文档不存在就创建一个,存在的话,就更新它 return $res; } //全文搜索 private function dosearch($keyword) { $eswhere = []; $eswhere['bool']['must'][] = ['match' => ['title' => $keyword]]; $eswhere['bool']['must'][] = ['match' => ['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' => [''], 'post_tags' => [''] ], 'descs' => [ 'pre_tags' => [''], 'post_tags' => [''] ], ], ], ] ]; $results = $this->client->search($where); // $milliseconds = $results['took']; // $maxScore = $results['hits']['max_score']; // $score = $results['hits']['hits'][0]['_score']; // $doc = $results['hits']['hits'][0]['_source']; return $results->asArray(); } //删除文档 private function del_doc() { for ($i = 1; $i client->delete(['index' => 'article', 'id' => $i]); } // 注意:如果该文档已经删除了,重复删除会报异常 exit('删除完成'); } //删除索引 private function del_index() { $this->client->indices()->delete(['index' => 'article']); // 注意:如果该索引已经删除了,重复删除会报异常 }}
es扩展 linux(centos7)中安装
- centos7系统设置
注意:visualbox中,要先在“设置”中把网卡的连接方式改为“桥接网卡”(默认是网络地址转换NAT模式)1、网卡设置为“桥接模式”2、cd /etc/sysconfig/network-scripts3、vi ifcfg-enp0s3修改两个参数:ONBOOT=no 改为:ONBOOT=yesBOOTPROTO=dhcp 改为:BOOTPROTO=static增加以下IP配置IPADDR=192.168.31.34NETMASK=255.255.255.0GATEWAY=192.168.31.1DNS1=114.114.114.114保存退出后,重启网络(service network restart)验证一下网络:ping www.baidu.com。如果能ping通,说明网络配置OK了
- 下载elasticsearch
如果centos7是纯净系统(minimal版本的)1、安装wget下载工具:yum -y install wget2、进入一个目录里,如:cd /home 注意:最好不要在系统目录里下载文件3、wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.16.1-linux-x86_64.tar.gz
- 安装elasticsearch
注意:先把系统的防火墙关掉service firewalld stop1、解压压缩包tar -xzvf elasticsearch-7.16.1-linux-x86_64.tar.gzcd elasticsearch-7.16.1/config2、修改配置文件vi elasticsearch.ymlnetwork.host:0.0.0.0http.port:9200node.name:node-1cluster.initial_master_nodes:["node-1"]3、cd /home/elasticsearch-7.16.1/bin4、创建一个新的用户useradd es5、切换到es帐号下su es6、启动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 ik3、进入ik目录中。cd ik4、wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.16.1/elasticsearch-analysis-ik-7.16.1.zip --no-check-certificate5、解压unzip elasticsearch-analysis-ik-7.16.1.zip6、重启elasticsearch注意:不要在plugins目录里留无关的目录或文件
高并发/大数据量下,代码编写原则
- 尽量少用或不用join查询,如果确实要用的话,注意时间开销
- 尽量不在循环里操作数据库
开启OPCache缓存
修改 php.ini 文件 添加这部分内容
zend_extension=php_opcacheopcache.enable=1opcache.enable_cli=1opcache.memory_consumption=128opcache.interned_strings_buffer=8opcache.max_accelerated_files=10000opcache.max_wasted_percentage=5opcache.revalidate_freq=3opcache.use_cwd=1opcache.validate_timestamps=1opcache.save_comments=1opcache.enable_file_override=Offopcache.fast_shutdown=1opcache.mmap_base=0x20000000
查询案例
不使用join查询
// 关联数据查询public function article_4(): array{ //查询 文章表 关联字段为 cid $pages = DB::table('article')->orderBy('id', 'desc')->paginate(2000); $list = $pages->items(); // 将所有的 cid 合并 foreach ($list as $item) { $cidList[] = $item->cid; } // cid去重 $cidList = array_unique($cidList); // 用whereIn 查出所需要的cid对应的 分类数据 $cate_list = $cate = DB::table('article_cate')->whereIn('id', $cidList)->get()->toArray(); $cates = []; // 修改 cate_list 分类 索引为 数据的 id foreach ($cate_list as $val) { $cates[$val->id] = $val; } return compact('list', 'cates');}
view视图
id 文章分类 文章标题 添加时间 @foreach($list as $v) {{$v->id}} {{$cates[$v->cid]->title}} {{$v->title}} {{$v->add_time }} @endforeach
给laravel DB操作添加扩展
php artisan make:provider DBServiceProvider
文件路径在 app/provider
use Illuminate\Database\Query\Builder as QueryBuilder;public function boot(): void{ // 将数据的索引设置 $index QueryBuilder::macro('abbbc', function ($index) { // echo '扩展的方法'; $res = $this->get()->toArray(); $result = []; foreach($res as $val){ $result[$val->$index] = $val; } return $result; });}
注册到 config\app
里面
'providers' => ServiceProvider::defaultProviders()->merge([// ... App\Providers\DBServiceProvider::class,])->toArray(),
使用示例
$cates=DB::table('article_cate')->abbbc('id');// 将数据的索引设置为 id ;