千萬級數據併發解決方案(理論+實戰) 高併發解決思路 方案

来源:https://www.cnblogs.com/henordinary/archive/2023/10/13/17757089.html
-Advertisement-
Play Games

在資料庫處理中,Join操作是最基本且最重要的操作之一,它能將不同的表連接起來,實現對數據集的更深層次分析 ...


千萬級數據併發解決方案(理論+實戰)

課程地址


項目地址

場景

秒殺 高併發

新聞系統 超大數據量

一般的網站 寫入的少 讀取的次數多

模糊查詢
數據量少的時候可以用 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查詢原則

數據多 併發高

Alt text

欄位越多 體積越大

  • 程式用到哪幾個欄位就查詢哪幾個欄位,儘量避免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:對於寫操作比較頻繁的數據,直接造成緩存命中率較低。這時候緩存的意義就不大了。

解決方案:

  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%的處理時間

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緩存

Alt text

修改 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 ;

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在DBS-集群列表-更多-連接查詢-死鎖中,看到9月22日有資料庫死鎖日誌,後排查發現是因為mysql的優化-index merge(索引合併)導致資料庫死鎖。 ...
  • 本文分享自華為雲社區《【SQL優化】為什麼有時候無法走執行性能更優的hashjoin》,作者: leapdb。 1. hash join通常優於nestloop join 通常nestloop join的複雜度是O(N方),hash join時間複雜度是O(N),所以我們一般傾向於使用hash jo ...
  • 驅動表與被驅動表的含義 在MySQL中進行多表聯合查詢時,MySQL會通過驅動表的結果集作為基礎數據,在被驅動表中匹配對應的數據,匹配成功合併後的臨時表再作為驅動表或被驅動表繼續與第三張表進行匹配合併,直到所有表都已匹配完畢,最後將結果返回出來。匹配演算法:Nested-Loop Join(嵌套迴圈連 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 背景 某一天,前端小餘同學和後端別問我小哥在做登錄業務介面對接,出於業務的特殊性和安全性的考慮,她和後端小哥約定“user”相關信息參數需要通過HTTP協議的header傳遞過來,利用HTTPS協議的頭部中的參數可以通過加密傳輸,從而保證 ...
  • 自動化3D機房、微模塊、3D機房、3D數據中心、科技感數據中心、三維機房、3d建築,3d消防,消防演習模擬,3d庫房,3d檔案室,3d密集架,webGL,threejs,3d機房,bim管理系統 ...
  • 圖片壓縮 借用了images、imagemin等第三方庫,壓縮jpg、Png圖片 viteImagemin也可以實現,代碼量更加少,squoosh就沒用過了 輸入需要壓縮的文件 //判斷是否已經有這個文件路徑 function setInputName() { return new Promise( ...
  • 遞歸函數 含義介紹: 遞歸函數,實際上就是將一個自定義的函數在運行過程中反覆調用他自己,直到遇到結束條件就停止 案例一:求階乘 int len(int n) { if(n == 1) { return 1;//如果階乘運算到最後一位(即1),就結束迴圈 } int sum = n*len(n-1); ...
  • Python - 合併集合 在 Python 中,有幾種方法可以合併兩個或多個集合。您可以使用union()方法,該方法返回一個包含兩個集合中所有項的新集合,或使用update()方法,將一個集合中的所有項插入另一個集合中: 示例,union()方法返回一個包含兩個集合中所有項的新集合: set1 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...