書的重點內容逐漸到了,我們的寫作方式也該換一下了,不會像(一)一樣流水賬式了的解釋幾種資料結構了
在第一篇文章中,我簡略的解釋下有關的資料結構,現在我們開始想想如何實現
先提幾個問題
- 如何實現多資料庫
- redis資料是存在記憶體中的,但是這樣資料存在丟失的風險,那我們怎樣化解決這個問題
- redis伺服器和多個客戶端的互動是怎樣實現的呢
在我看來,該書第二部分<單機資料庫的實現>就是圍繞上面的幾個問題,來用列舉式行文寫下相應部分知識點的。
伺服器中的多
資料庫
看到這個多字,其實我們很容易就想到用連結串列的方式去儲存
一個伺服器,先假設是一個簡單的struct結構來維護的,我們想在其中實現多資料庫,自然想到,在其中新增一個鍵值對,而這個值我們使用一個連結串列
這個連結串列中存放一個又一個的指標,每個指標指向一個struct結構(維護著資料庫結構的struct)
好,這樣,我們就簡單的實現這個多
。
然後我們再去實現單資料庫
伺服器中的多資料庫
每個資料庫中那有該如何存放資料呢
由於redis是kv資料庫,資料都是以kv形式存在的,那我們完全就可以用字典去實現
鍵值對中的值可以是(一)中的多種形式,那麼,
下圖的形式就能得出了
到了這裡後,書上將過期問題在後續進行了說明。
過期問題
書籍主要是解釋了 列舉式解釋了相關命令
我覺得比較重要是redis的過期鍵刪除策略
一個經典的問題是:如果一個鍵過期了,那麼它什麼時候會被刪除呢?
這個問題有三種可能的答案,它們分別代表了三種不同的刪除策略:
-
定時刪除:在設定鍵的過期時間的同時,建立一個定時器(timer),讓定時器在鍵的過期時間來臨時,立即執行對鍵的刪除操作。
- 優點:對記憶體是最友好的:通過使用定時器,定時刪除策略可以保證過期鍵會盡可能快地被刪除,並釋放過期鍵所佔用的記憶體。
- 缺點:它對CPU時間是最不友好的:在過期鍵比較多的情況下,刪除過期鍵這一行為可能會佔用相當一部分CPU時間 | 建立一個定時器需要用到Redis伺服器中的時間事件,而當前時間事件的實現方式——無序連結串列,查詢一個事件的時間複雜度為O(N)
-
惰性刪除:放任鍵過期不管,但是每次從鍵空間中獲取鍵時,都檢查取得的鍵是否過期,如果過期的話,就刪除該鍵;如果沒有過期,就返回該鍵。
- 對CPU時間來說是最友好的。 這個策略不會在刪除其他無關的過期鍵上花費任何CPU時間
- 它對記憶體是最不友好的:如果一個鍵已經過期,而這個鍵又仍然保留在資料庫中,那麼只要這個過期鍵不被刪除,它所佔用的記憶體就不會釋放
-
定期刪除:每隔一段時間,程式就對資料庫進行一次檢查,刪除裡面的過期鍵。至於要刪除多少過期鍵,以及要檢查多少個資料庫,則由演算法決定
- 定期刪除策略是前兩種策略的一種整合和折中
- 定期刪除策略的難點是確定刪除操作執行的時長和頻率。
上面大概性的介紹了資料庫的儲存實現,但是現在資料仍然保持在記憶體中的,但是這樣資料存在丟失的風險,這個時候我們應該設計持久化的策略了。
Redis的持久化
Redis 分別提供了 RDB 和 AOF 兩種持久化機制:
RDB 將資料庫的快照(snapshot)以二進位制的方式儲存到磁碟中。 AOF 則以協議文字的方式,將所有對資料庫進行過寫入的命令(及其引數)記錄到 AOF 檔案,以此達到記錄資料庫狀態的目的
我們繼續想第三個問題,客戶端和伺服器是如何互動的?
Redis客戶端和伺服器的互動
關於這一點,書上用了三個章節來講解。
分別是 伺服器事件
,客戶端
,伺服器
Redis的事件處理器是單執行緒
的,但並不意味著Redis就是單執行緒的!
I/O多路服用程式
Redis的事件處理機制是I/O多路複用的。多個檔案事件可能併發的出現,但是I/O多路複用程式會將所有的產生的套接字放到一個佇列裡。
以有序,同步的方式,I/O多路複用程式向檔案事件分派器傳送套接字,當一個套接字處理完,才會傳送下一個。
I/O多路複用程式底層有多種實現可以選擇,epoll
,select
,evport
,kqueue
.
檔案事件處理器
-
連線應答處理器
為了對連線伺服器的客戶端進行應答,伺服器為套接字連線進行應答的處理器 複製程式碼
-
命令處理器
-
命令回覆處理器
後面主要就是 伺服器和客戶端的通訊協議部分,這部分我不準備講解,也不是什麼特別重要和難點的部分,就略過了