優化頁面訪問速度(三)
——服務端優化
一、概述
服務端的優化,主要可以通過訊息佇列、減少資料庫請求(快取)、并發處理、頁面靜態化等方式處理,
二、訊息佇列
1、解決問題
訊息佇列(Message Queue,MQ)有許多不同的實作方式,可以用rabbitmq、activemq、rocketmq,也可以用任務分發系統gearman,
訊息佇列主要是解決訊息的異步發送,即對于某個系統不需要關心的內容,只需要發布一個處理完畢的訊息,帶上一些引數,有需要的系統自行訂閱,例如一些任務執行完成的回呼函式,就可以用mq來實作異步回呼,
2、處理方式
以rabbitmq為例,Rabbitmq的服務器,可以認為是訊息的生產者和消費者的中轉平臺,生產者發布訊息給rabbitmq服務器的交換機(exchange),發布的時候會定義一些路由規則(routing key),Rabbitmq服務器根據路由規則,將訊息從exchange轉發到對應的佇列(queue)中,再由消費者從queue中取訊息,進行處理,如下圖所示:
為了加快處理速度,防止佇列的堆積,可以同時起多個消費者行程,用于消費佇列的內容,
3、確保消費
Rabbitmq有重試機制,在沒有發布成功時,會自動重試發送,當然,如果要確保訊息被消費,可以設定類似TCP的三次握手方式,要求消費者完成訊息的處理后,再發布一條訊息,告知生產者,
生產者可以將發送的訊息單獨記錄到資料庫的一張表中,并且在接到消費者確認處理的訊息后,把對應的資料置狀態,
同時,可以撰寫一個crontab,定時來掃描這個表,將超過一定時間(如10分鐘)未被置成功狀態的記錄,重新發布一次,
用單獨的表來記錄資訊,好處在于,只要表中有資料,表明訊息已經發布出去,這樣當出現訊息為被處理的問題的時候,易于確認是訊息未發布還是訊息接收處理存在問題,
當然,這要求訊息接收方的處理方法是冪等的,即對同一條訊息,無論接到多少次,只處理一次,
4、rabbitmq的routing key
Rabbitmq有好幾種處理方式,如下:
1)廣播
將訊息發布到所有佇列中,由消費者去接收感興趣的訊息,對于不感興趣的訊息直接丟棄,
2)direct
指定發送到某個佇列中,
3)topic
采用正則的方式,將訊息發布到某些佇列中,例如a.*,發布到所有名為a.開頭的佇列,
三、快取
1、解決問題
快取的目的,主要在于減少對資料庫的操作,資料庫的請求,需要占用I/O資源,而快取是存在記憶體中的,速度會快的多,
因此,對于頻繁訪問的資料,且實時性要求沒那么高的,可以通過快取來減少對資料庫的壓力,
另外,對于需要頻繁修改資料的(如文章點擊量)、短時間內大量訪問的(秒殺系統),用快取也是比較好的解決方案,
快取常用的就是redis和memcache,
2、redis和memcache的區別
Memcache是純粹的快取,只有一種key-value形式的存盤,
Redis功能更加強大,支持五種資料結構,包括string、list、hash、set、sorted-set,支持資料的持久化(AOF、快照),支持事務處理,支持哨兵監控,且可以臨時突破記憶體限制(通過持久化的方式),
3、key的設定方式
通常,用 方法名:id 的方式來作為key,這樣比較方便來查找,
4、快取會出現的問題
快取會出現快取穿透、快取雪崩、快取擊穿,
1)快取穿透
當大量查詢不存在的key,由于正常情況下查詢結果不存在的不會存到快取中,這樣會導致大量的查詢繞過快取直接查詢資料庫,
解決方案:對于資料庫不存在的內容,也可以保存一小段時間隨機的時間,如3分鐘,這樣可以避免繞過資料庫的行為,
2)快取雪崩
當所有的key都設定成同一個時間,會出現同一個時間所有key都過期,這樣會發生一瞬間大量請求資料庫的情況,
解決方案:對不同的key,設定一個隨機的時間范圍,比如4分58秒~5分3秒的過期時間,這樣可以避免同一時間都過期,
3)快取擊穿
對于某個key,在一個很短的時間內并發大量訪問,則所有的請求都繞過快取去資料庫取資料,
解決方案:可以設定互斥鎖來解決問題,即請求快取不存在的時候,先去訪問互斥鎖,redis的setnx、memcache的add 某個key,此時,請求資料庫,并將請求結果存入快取,
這樣,下一個請求來的時候,由于存在互斥鎖,key存在的時候無法添加,則表示資料被鎖了,可以隨機等待一個短暫的時間再請求鎖,直到請求成功,再去訪問一次快取,通常此時快取已經有內容了,如果還沒有內容,可以再去請求資料庫,
5、快取過期策略——LRU
快取內容太多,超過機器的記憶體時,需要一個策略剔除部分快取內容,最常用的是LRU策略,即最近最少使用,
具體實作方式,是使用一個佇列來維護快取,當某個快取被訪問,則從佇列底部去除,再添加到佇列的頭部,這樣需要剔除的資料都是最久沒有訪問的資料,
存在問題:
當某個時間有大量的不同的key的訪問,會把佇列弄臟,造成需要的資料被剔除,
解決方案:
1)可以用兩個佇列,當資料訪問一次放到第一個佇列,再次訪問挪到第二個佇列去,然后LRU規則先清理第一個佇列,
2)也可以用多個權重佇列,把重要的內容、可能常訪問的內容,都快取到高級別的佇列中去,把一些不怎么用的內容放到低級的佇列中,
四、并發處理
PHP的并發處理,可以用swoole框架來解決,其可以控制并發消費內容,例如一個頁面的展示,需要從幾個不同的系統取資料,則可以異步取多個地方的資料,在最侄訓總后一起處理,
Swoole框架我也不太熟,后面學習了再分享這部分內容,
五、頁面靜態化
Nginx沒有處理PHP的能力,遇到PHP檔案都要轉發給php-fpm來處理,而遇到html、js、css等,可以直接處理回傳給瀏覽器,
因此,在沒有實作前后端完全分離的頁面,可以使用靜態化的方式,將不常變動的內容,在第一次訪問php檔案的時候,將其轉存為html檔案,并且設定一個過期時間,
后面訪問的時候,根據Linux檔案創建的時間,判斷是否過期,當未到過期時間,可以由Nginx直接取對應的html檔案進行回傳,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/131450.html
標籤:PHP
上一篇:以php中的自增自自減運算子操作(整型,浮點型,字串型,布爾型,空型別)資料
下一篇:下載安裝Git,學習筆記
