已通过os信号请求关闭服务器,redis(一)内部机制的介绍和启动过程
redis(一)內部機制的介紹和啟動過程
redis的基本介紹
redis服務端
redis客戶端
redis的持久化
redis中的文件事件和時間時間
redis的啟動過程
redis的基本介紹
redis是一種非關系型數據庫,采用=key,value的形式來存儲數據。key是二進制數據,對于value的數據類型,redis支持string、hash、list、set、sorted set五種類型。
對于單個redis實例,內部使用多線程通信,但是對外采用RESP單線程通信協議,在TCP層通過二進制方式進行傳輸數據,單線程采用同步的請求方式。
redis服務端
redis服務端內部結構為struct redisServer和struct redisDb。redis中默認16個數據庫,可以通過配置來修改數據庫數量,每一個數據庫對應一個redisDb。數據庫之間的數據是相互獨立的。查詢數據的時候,可以通過select指定具體某個數據庫。
1 struct redisServer {2 int dbnum;//服務器的數據庫數量,值由服務器配置的“databases”選項決定,默認為16
3 redisDb *db;//數組,保存著服務器中的所有數據庫
4
5 list *clients;//一個鏈表,保存了所有客戶端狀態,每個鏈表元素都是“redisClient”結構
6
7 time_t unixtime;//保存秒級精度的系統當前UNIX時間戳,減少獲取系統當前時間的系統調用次數,100毫秒更新一次
8 long long mstime;//保存毫秒級精度的系統當前UNIX時間戳
9 unsigned lruclock;//默認每10秒更新一次,用于計算數據庫鍵的空轉時長,數據庫鍵的空轉時長 = 服務器的“lruclock”屬性值 - 數據庫鍵值對象的“lru”屬性值
10
11 long long ops_sec_last_sample_time;//上一次進行服務器每秒執行命令數量抽樣的時間
12 long long ops_sec_last_sample_ops;//上一次進行服務器每秒執行命令數量抽樣時,服務器已執行命令的數量
13 long long ops_sec_samples[REDIS_OPS_SEC_SAMPLE];//環形數組,每個元素記錄一次服務器每秒執行命令數量抽樣結果,估算服務器在最近一秒鐘處理的命令請求數量(數組長度默認為16,100毫秒更新一次)
14 int ops_sec_idx;//ops_sec_samples數組的索引值,每次抽樣后值增1,等于16時重置為0
15
16 size_t stat_peak_memory;//已使用內存峰值
17
18 int shutdown_asap;//關閉服務器的標識,1表示關閉,0不關閉
19
20 pid_t rdb_child_pid;//記錄執行BGSAVE命令的子進程的ID,-1表示服務器沒有正在執行BGSAVE
21 pid_t aof_child_pid;//記錄執行BGREWRITEAOF命令的子進程的ID,-1表示服務器沒有正在執行BGREWRITEAOF
22 int aof_rewrite_scheduled;//1表示有BGREWRITEAOF命令被延遲了(服務器執行BGSAVE期間收到的BGREWRITEAOF會被延遲到BGSAVE執行完成之后執行)
23 struct saveparam *saveparams;//記錄了自動保存條件的數組(執行BGSAVE的條件)
24 long long dirty;//修改計數器(上一次執行BGSAVE之后已經產生了多少修改)
25 time_t lastsave;//上一次執行自動保存操作(BGSAVE)的時間
26 sds aof_buf;//AOF緩沖區
27
28 int cronloops;//serverCron函數的運行次數計數器
29
30 lua;//用于執行Lua腳本的Lua環境
31 redisClient *lua_client;//Lua腳本的偽客戶端,在服務器運行的整個生命周期一直存在,直至服務器關閉才會關閉
32 dict *lua_scripts;//字典,記錄所有載入的Lua腳本,鍵為某個Lua腳本的SHA1校驗和,值為對應的Lua腳本
33 dict *repl_scriptcache_dict;//字典,記錄已經傳播給所有從服務器的所有Lua腳本,鍵為腳本的SHA1校驗和,值為NULL,用于EVALSHA1命令的復制
34
35 long long slowlog_entry_id;//下一條慢查詢日志的ID
36 list *slowlog;//保存了所有慢查詢日志的鏈表
37 long long slowlog_log_slower_than;//服務器配置“slowlog-log-slower-than”選項的值,表示查詢慢于多少微秒便記錄慢查詢日志
38 unsigned long slowlog_max_len;//服務器配置“slowlog-max-len”選項的值,表示服務器最多保存多少條慢查詢日志記錄,若超出,最久的記錄會被覆蓋
39
40 monitors;//鏈表,監視器客戶端列表
41
42 dict *pubsub_channels;//字典,保存所有頻道的訂閱關系,鍵為某個被訂閱的頻道,值為鏈表,記錄了所有訂閱這個頻道的客戶端
43 list *pubsub_patterns;//鏈表,保存所有模式的訂閱關系,每個鏈表節點都包含了訂閱的客戶端和被訂閱的模式
44 };
struct redisDb {
dict*dict;//數據庫鍵空間字典,保存數據庫中所有的鍵值對
dict *expires;//過期字典,保存數據庫中所有鍵的過期時間
dict *watched_keys;//字典,正在被WATCH命令監視的鍵
};
redisDb中三個字典中的key共享對象,value值不一樣。對于過期的鍵,redis采用惰性刪除和定時刪除相結合的方式,惰性刪除,指執行之前會查看這個key是否過期,定時刪除值一段時間之后分多次遍歷數據庫,每次只刪除部分過期的數據。
redis客戶端
redis-server通過tcp端口或socket來創建和redis-cli的連接,可以修改redis.conf中的maxclients來指定最大連接數,在建立連接之后,socket會被設置為非阻塞模式,同時創造一個struct redisClient來保存客戶端的連接信息。
1 struct redisClient {2 redisDb *db;//記錄客戶端當前正在使用的數據庫,上文提到之前有16個們默認的數據庫,可以通過select進行切換數據庫
3 int fd;//客戶端正在使用的套接字描述符,-1表示偽客戶端(AOF文件或者Lua腳本),大于-1表示普通客戶端
4 robj *name;//客戶端名字
5 int flags;//客戶端標志,記錄了客戶端的角色,以及客戶端目前所處的狀態
6 sds querybuf;//輸入緩沖區,根據輸入內容動態地縮小或擴大,但不能超過1GB,否則服務器將關閉這個客戶端
7 robj **argv;//命令與命令參數,數組,每個元素都是一個字符串對象,argv[0]為命令,其余元素為參數
8 int argc;//argv數組的長度
9 struct redisCommand *cmd;//當前執行的命令的實現函數,指向命令表中的命令結構
10 char buf[REDIS_REPLY_CHUNK_BYTES];//固定大小輸出緩沖區,數組,默認大小為16KB
11 int bufpos;//buf數組目前已使用的字節數量
12 list *reply;//可變大小輸出緩沖區,鏈表
13 obuf_soft_limit_reached_time:記錄了“reply”輸出緩沖區第一次到達軟性限制的時間,用于計算持續超出軟性限制的時長,以此決定是否關閉客戶端14 int authenticated;//0表示未通過身份驗證,1表示已通過身份驗證
15 time_t ctime:創建客戶端的時間,可用于計算客戶端與服務器連接的時間長度16 time_t lastinteraction:客戶端與服務器最后一次進行互動的時間,可用于客戶端的空轉時長17 multiState mstate;//事務狀態,包含一個事務隊列,以及一個已入列命令計數器
18 };
db:是一個指針,指向Redis服務器狀態結構中的“db”數組其中一個元素,表示當前客戶端正在使用的數據庫。默認情況下,Redis客戶端的目標數據庫為0號數據庫,可以通過select命令切換,所以select命令的實現原理為:修改redisClient.db指針,讓它指向服務器中指定的數據庫。
fd:連接當前客戶端與Redis服務器的套接字描述符。值為-1表示偽客戶端(AOF文件或者Lua腳本),值大于-1則表示普通客戶端。Redis客戶端分為普通客戶端與偽客戶端兩種類型,其中通過網絡連接與Redis服務器進行連接的就是普通客戶端,反之則是偽客戶端了。偽客戶端也有兩種類型,分別是Lua腳本的偽客戶端和AOF文件的偽客戶端。Redis服務器狀態結構的“lua_client”屬性就保存了Lua腳本的偽客戶端,它會在Redis服務器初始化時就被創建,負責執行Lua腳本中包含的Redis命令,在服務器運行的整個生命周期一直存在,直至服務器關閉才會關閉。而AOF偽客戶端則是在載入AOF文件時被創建,用于執行AOF文件中的Redis命令,在AOF文件載入完成之后被關閉。client list:列出目前所有連接到服務器的普通客戶端。
redis的持久化
AOF、RDB指的是redis持久化策略,可以通過redis.conf中的參數來配置。
appendfsync (always/everysec/no)
save [time(s)] [times]
AOF指的是保存操作命令,他會將每一次redis的數據操作命令追加到文件中,當鍵過期的時候會加入del命令,并且每過一段時間,會對已經生成的文件優化一次,主要指的是操作命令的合并。
RDB指的是執行save或bgsave命令創建一個新的RDB文件,新建一個子進程,把所有的數據寫入文件。
redis中的文件事件和時間時間
redis中的事件分為文件事件和時間事件
文件事件:指的是通過epoll實現io多路復用程序來監聽多個套接字,對讀、寫、關閉、連接都支持事務,支持原子操作。
時間事件:指的是redis中在默寫特定時間執行操作,主要有定時事件和周期性事件。所有的時間事件會被放在一個無須列表中,新加入的事件會在事件的頭部插入。每次執行事件的時候都會去遍歷列表。正常情況下只有一個serverCron時間時間,在benchmark模式下,也只有兩個時間事件。
redis的啟動過程
(1)初始化服務器狀態結構
新創建一個struct redisServer類型的實例變量作為服務器的狀態,記錄著整個服務器的狀態,并為結構中的各個屬性設置默認值,例如:服務器的運行ID、默認配置文件路徑、默認端口等等,同時創建Redis命令表。
(2)載入配置選項
載入用戶指定的配置參數和配置文件,并根據用戶設定的配置,對服務器狀態變量的相關屬性進行修改。
(3)初始化服務器數據結構
這一步主要是為服務器狀態中的一些數據結構分配內存,例如:
“clients“:鏈表,保存所有與服務器連接的客戶端的狀態結構。
”db“:字典保存服務器的所有數據庫。
”lua“:用于執行Lua腳本的Lua環境。
”slowlog“:用于保存慢查詢日志。
除此之外,還會進行一些非常重要的設置操作,例如:
為服務器設置進程信號處理器。
創建共享對象,例如經常經常用到的“OK”回復字符串對象,1到10000的字符串對象等等。
為serverCron函數創建時間事件。
如果AOF持久化功能已經打開,則打開現有的AOF文件,若AOF文件不存在,則創建并打開一個新的AOF文件,為AOF寫入做好準備。
初始化服務器的后臺I/O模塊,為將來的I/O操作做好準備。
(4)還原數據庫狀態
若服務器啟用了AOF持久化功能,則載入AOF文件,否則載入RDB文件,根據AOF文件或RDB文件記錄的內容還原數據庫狀態,同時在日志文件中打印出載入文件并還原數據庫狀態所耗費的時長。
(5)執行事件循環
一切準備就緒,開始執行服務器的事件循環,開始接受客戶端的連接請求,處理客戶端發送的命令請求。
來源:oschina
鏈接:https://my.oschina.net/u/4332949/blog/3449911
總結
以上是生活随笔為你收集整理的已通过os信号请求关闭服务器,redis(一)内部机制的介绍和启动过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图像风格迁移cvpr2020_CVPR
- 下一篇: java matcher replace