千万级数据并发解决方案(理论+实战)

课程地址

项目地址

场景

秒杀 高并发

新闻系统 超大数据量

一般的网站 写入的少 读取的次数多

模糊查询
数据量少的时候可以用 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) 简单查询

idselect_typepossible_keyskeyrows
1SIMPLEcid,authorauthor700

大数据量下进行的查询 最好先查看执行计划

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:对于写操作比较频繁的数据,直接造成缓存命中率较低。这时候缓存的意义就不大了。

解决方案:

  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设置属性的字符串。-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视图

    @foreach($list as $v)        @endforeach
id 文章分类 文章标题 添加时间
{{$v->id}} {{$cates[$v->cid]->title}} {{$v->title}} {{$v->add_time }}

给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 ;
Copyright © maxssl.com 版权所有 浙ICP备2022011180号