千万级数据并发解决方案(理论+实战)
场景
秒杀 高并发
新闻系统 超大数据量
一般的网站 写入的少 读取的次数多
模糊查询
数据量少的时候可以用 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 < 10000000; $i++) {
$randindexArr = array_rand($lists,2);
$data['title'] = $data['descs'] = '';
foreach($randindexArr as $val){
$data['url']=$lists[$val]->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设置<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%的处理时间
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: false
xpack.security.transport.ssl.enabled: false
3.重启es服务,删除.security-7索引
curl -XDELETE -u elastic:changeme http://localhost:9200/.security-7
3.关闭ES服务设置以下两项为true;
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
4.重启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: true
xpack.security.enrollment.enabled: true
xpack.security.http.ssl:
enabled: true
keystore.path: certs/http.p12
xpack.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"
}
}
}'
案例 增删查改
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Elastic\Elasticsearch\ClientBuilder;
use Elastic\Elasticsearch\Exception\ClientResponseException;
use Elastic\Elasticsearch\Exception\ServerResponseException;
use Illuminate\Support\Facades\DB;
class MyesController extends Controller
{
protected $client;
public function __construct()
{
//初始化es
$this->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', '<', 300)->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 "<pre>";
// 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' => ['<span style="color:red">'],
'post_tags' => ['</span>']
],
'descs' => [
'pre_tags' => ['<span style="color:red">'],
'post_tags' => ['</span>']
],
],
],
]
];
$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 < 1000; $i++) {
$this->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-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查询,如果确实要用的话,注意时间开销
- 尽量不在循环里操作数据库
开启OPCache缓存
修改 php.ini 文件 添加这部分内容
zend_extension=php_opcache
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.max_wasted_percentage=5
opcache.revalidate_freq=3
opcache.use_cwd=1
opcache.validate_timestamps=1
opcache.save_comments=1
opcache.enable_file_override=Off
opcache.fast_shutdown=1
opcache.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视图
<table class="layui-table">
<tr>
<th>id</th>
<th>文章分类</th>
<th>文章标题</th>
<th>添加时间</th>
</tr>
@foreach($list as $v)
<tr>
<td>{{$v->id}}</td>
<td>{{$cates[$v->cid]->title}}</td>
<td>{{$v->title}}</td>
<td>{{$v->add_time }}</td>
</tr>
@endforeach
</table>
给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 ;