概述
在我們把系統做好反向代理和負載均衡之後, 還有一個性能問題沒有解決,就是我們的數據庫,此時如果併發量大了,數據庫將是一個很大的瓶頸。假如我們有一臺4核8G的服務器, 它能承受的併發數通常也就在2000左右。以電商系統爲例, 如果所有的商品信息都是直接從數據庫中讀取, 首先掛掉的將會是我們的數據庫。爲了解決這個問題,在DB層和業務邏輯層之間, 會加入一層緩存, 利用緩存可以很好分擔數據庫的壓力。
緩存的分類
- DNS
- 瀏覽器
- App
- 代理緩存
- 服務端緩存
服務端緩存中的內存緩存
- 我們主要針對服務端緩存中的內存緩存來分析
- 在RDB中,也就是我們所說的關係型數據庫,如MySQL、SQLServer等,數據保存在服務器的硬盤之中, 硬盤對數據存取比較慢
- 普通筆記本轉速是5.4K轉/分鐘, 一般服務器硬盤轉速可以達到1.5W轉/分鐘, 這個速度和內存讀取來說也是非常慢的
- 隨機訪問情況下, 內存訪問速度比硬盤訪問速度快上10萬倍以上
- 然而內存對計算機來說是緊缺的資源, 我們無法將所有數據都放在內存中, 所以程序員開發了一些緩存算法來解決這些問題
緩存算法
-
LRU(Least Recently Used)
- 最近最少使用
Memcached
主要採用此算法來淘汰數據
-
LFU(Least Frequently Used)
- 根據數據的歷史訪問頻率來淘汰數據
關於Memcached緩存
- Memcached 是高性能的分佈式內存緩存系統,一般用來緩存訪問的熱點數據,以減輕數據庫負擔
- 全球最大的Memcached用戶是facebook, 已經超過28T的數據存放在Memcached中, 使用了超過800臺的服務器
- 官網:https://memcached.org/
Ubantu上Memcached的安裝
- $
apt update
- $
apt install -y memcached
Memcached的服務管理
- $
service memcached stop
- $
service memcached start
- $
service memcached restart
Memcached的配置
- $
vi /etc/memcached.conf
-d
守護進程-m
內存, default 64MB , 這裏需要區分情況, 如果是專用的Memcached服務器可以把70%的系統內存分配-u
運行用戶-l
監聽的服務器IP地址-p
監聽端口, 默認是11211-c
併發連接數, 默認是1024
- 如果編輯了之後,需要重啓服務才能生效, $
service memcached restart
- 連接Memcached終端, $
telnet 127.0.0.1 11211
進入# 可以查看狀態 stats # ... 此處輸出很多信息 STAT pid 237784 # 進程ID STAT uptime 2070631 # 運行秒數 STAT version 1.4.25 # 版本 STAT libevent 2.0.21-stable # libevent版本 STAT pointer_size 64 # 系統指針(32bit/64bit) STAT curr_items 50237 # 當前實例存儲的items數量 STAT total_items 1337400 # 實例啓動以後存儲的items總數量 STAT bytes 35169108 # 實例存儲items佔用的字節數 STAT curr_connections 349 # 當前打開的連接數 【重要指標】 STAT total_connections 108429 # 實例啓動後打開的連接總數 STAT cmd_get 14005676 # get 命令總請求次數 STAT cmd_set 1337400 # set 命令總請求次數 STAT get_hits 12596511 # 總命中次數 【重要指標】 STAT get_misses 1409165 # 總未命中次數 【重要指標】 STAT evictions 0 # 爲獲取空閒內存而刪除的items數 STAT bytes_read 4918928094 # 總讀取字節數(請求字節數) STAT bytes_written 46027378599 # 總髮送字節數(結果字節數) STAT limit_maxbytes 1572864000 # 分配的緩存大小 STAT threads 4 # 當前線程數 # 退出 quit
- Memcached的使用比較簡單,我們很少在服務器上對它進行管理
- Memcached是基於內存的, 如果服務關閉,則數據全部丟失
通過python來操作Memcached
1 ) 安裝
$ pip3 install python-memcached
2 ) 使用
import memcache
# 鏈接
mc = memcache.Client(['127.0.0.1:11211'])
# 存入
mc.set('name', 'python', 60) # 過期時間 單位爲秒
# 讀取
res = mc.get('name')
# 刪除
mc.delete('name')
Memcached的控制檯演示
- 在windows上,如果我們想要啓動Memcached, 需要下載一個它的可執行程序
memcached Server
文件, 啓動它,開啓命令窗口 - 打開另一個命令行使用pip安裝它的python擴展, $
pip install python-memcached
, 這裏是window一般使用pip命令即可 - 然後開始進入python環境進行相關操作
>>> import memcache >>> mc = memcache.Client(['127.0.0.1:11211']) >>> mc.set('name', 'jack') True >>> mc.get('name') 'jack' >>> mc.delete('name') 1 >>> mc.get('name') >>> >>> mc.set('name', 'jack', 10) True >>> mc.get('name') 'jack' >>> mc.get('name') # 10s之後再次get, 發現沒了 >>>
Memcached的項目演示
1 ) 新建一個cache.py文件
- 注意名稱不能和將要導入的memcache重名
2 ) 一般的數據庫操作
import pymysql
def get_data():
conn = pymysql.connect(host='localhost', user='root', password='你自己設置的密碼', database='test', charset='utf8)
cursor = conn.cursor
sql = 'select * from product limit 3'
cursor.execute(sql)
data = cursor.fetchall()
cursor.close()
conn.close()
return data
3 ) 改造後的帶Memcached緩存的數據庫操作
import pymysql
import memcache
def get_data():
# 鏈接memcache
mc = memcache.Client(['127.0.0.1:11211'])
# 這裏定義一個公共變量, 防止後期修改一處, 忘記其他地方還有可能會造成的bug
cacheKey = 'product_list'
# 首先嚐試獲取,如果存在那麼直接使用
res = mc.get(cacheKey')
if res is not None:
return res
# 不存在則進行連接數據庫查詢
print('go db now >>>>')
conn = pymysql.connect(host='localhost', user='root', password='你自己設置的密碼', database='test', charset='utf8)
cursor = conn.cursor
sql = 'select * from product limit 3'
cursor.execute(sql)
data = cursor.fetchall()
cursor.close()
conn.close()
# 沒有數據時將數據放入memcache, 這裏設置10s的有效時間
# 這個時間設置很重要, 需要根據不同的業務設置不同的時間, 這樣就可以靈活控制
# 假如1s有300個併發, 那麼10s就是3000次的查詢, 這裏設置10s, 那麼在這10s內只會查詢1次的數據庫, 相比之下減少了2999次節約了很多資源
# 一般業務我們可能會設置更長的時間, 如果數據更新了, 那麼數據仍不會變化, 這會造成一個問題,
# 解決方案是:當數據更新時, 將緩存刪除或者放入新的緩存數據
mc.set(cacheKey, data, 10)
return data