1. 程式人生 > >redis 系列20 服務器下

redis 系列20 服務器下

track before com mic 中一 生成 _id local load

原文:redis 系列20 服務器下

二. serverCron函數

  2.3 更新服務器每秒執行命令次數

    serverCron函數中的trackOperationsPerSecond函數會以每100毫秒一次的頻率執行,這個函數以抽樣計算的方式,估算並記錄服務器在最近一秒鐘處理的命令請求數量,這個值可以通過info status命令的instantaneous_ops_sec域查看:

        127.0.0.1:6379> info stats
        # Stats
        total_connections_received:5
        total_commands_processed:
67 //服務器在最近一秒鐘處理的命令請求數量 instantaneous_ops_per_sec:0

  關於trackOperationsPerSecond函數的內部實現就不再介紹,大致是當客戶端執行INFO命令時,服務器就會調用getOperationsPerSecond函數,根據ops_sec_samples環形數組中的抽樣結果,計算出instantaneous_ops_per_sec屬性的值。

  

  2.4 更新服務器內存

    服務器狀態redisServer結構的stat_peak_memory屬性記錄了服務器的內存峰值大小,每次serverCron函數執行時,程序都會查看服務器當前使用的內存數量,並與stat_peak_memory保存的數值進行比較,如果當前的內存數量比stat_peak_memory屬性記錄的值要大,那麽程序就將當前使用的內存數量記錄到stat_peak_memory屬性記錄中。INFO memory命令的used_memory_peak和used_memory_peak_human兩個域分別以兩種格式記錄了服務器的內存峰值。

    127.0.0.1:6379> info memory
    # Memory
    used_memory_peak:858952
    used_memory_peak_human:838.82K

    這兩個是域是指過去Redis內存使用的峰值,是反映了內存過去最高峰值,而不是當前使用內存的值。

  2.5 處理sigterm信號

    在啟動服務器時,redis會為服務器進程的singterm信號關聯處理器singtermHandler函數,這個信息處理器負責在服務器接收到singterm信號時,打開服務器狀態的shutdown_asap標識。 每次serverCron函數運行時,程序都會對服務器狀態redisServer結構函數的shutdown_asap屬性進行檢查,並根據屬性的值決定是否關閉服務器。

        static void  sigtermHandler(int sig){
                //打印日誌
                redisLogFromHandler(reids_warning,"received sigterm, scheduling shutdown...");
            //打開關閉標識
                server.shutdown_asap=1;
            }
      //下面先打開日誌功能,在redis.conf文件中設置日誌文件路徑,保存配置文件,重啟服務。
         171 logfile /usr/local/redis/redis.log
         [root@xuegod64 redis]# redis-server redis.conf
            
     //當在客戶端執行shutdown關閉服務器時,服務器在接到sigterm信號之後,關閉服務器並打印相關日誌。
        127.0.0.1:6379> shutdown
        not connected>  

    日誌顯示可以看到,服務器在關閉自身之前會進行RDB持久化操作,這也是服務器攔截sigterm信號的原因,日誌信息如下:

          43:M 06 Dec 11:07:42.562 # User requested shutdown...

          42343:M 06 Dec 11:07:42.562 * Saving the final RDB snapshot before exiting.

          42343:M 06 Dec 11:07:42.565 * DB saved on disk

          42343:M 06 Dec 11:07:42.565 * Removing the pid file.

          42343:M 06 Dec 11:07:42.565 # Redis is now ready to exit, bye bye...

  

  2.6 管理客戶端資源

    serverCron函數每次執行都會調用clinetsCron函數,該函數會對一定數量的客戶端進行檢查,包括1.如果客戶端與服務器的連接已經超時(如很長時間沒有互動),那麽程序會釋放這個客戶端。2.如果客戶端在上一次執行命令請求之後,輸入緩沖區的大小超過了一定的長度,那麽程序會釋放客戶端當前的輸入緩沖區。

  2.7 執行被延遲的bgrewriteaof

    說到bgsave和bgrewriteaof二個客戶端命令,前者針對RDB持久化,後者針對AOF 持久化。在服務器執行bgsave命令的期間,如果客戶端向服務器發送了bgrewriteaof命令,那麽服務器會將bgrewriteaof命令的執行時間延遲到bgsave命令執行完畢之後。每次serverCron函數執行時,都會檢查bgsave命令或者bgrewriteaof命令是否正在執行,如果這兩個命令都沒在執行,並且aof_rewrite_scheduled屬性的值為1,那麽服務器就會執行之前被推延的bgrewriteaof命令。

        struct redisServer {
                    //如果值為1, 那麽表示有bgrewriteaof命令被延遲了
                int aof_rewrite_scheduled;
            }

  

  2.8 檢查持久化操作的運作狀態

    服務器狀態使用redisServer結構的rdb_child_pid屬性和aof_child_pid屬性記錄執行bgsave命令和bgrewriteaof命令的子進程的ID,這兩個屬性也可以用於檢查bgsave命令或者bgrewriteaof命令是否正在執行。

    struct redisServer {

            //記錄執行bgsave命令的子進程的ID
            //如果服務器沒有在執行bgsave,那麽這個屬性的值為-1.
            pid_t rdb_chlid_pid;

            //記錄執行bgrewriteaof命令的子進程的ID
            //如果服務器沒有在執行bgrewriteaof,那麽這個屬性的值為-1.
            pid_t aof_chlid_pid;
        }

    每次serverCron函數執行時,程序都會檢查rdb_chlid_pid和aof_child_pid兩個屬性值,只要其中一個屬性的值不為-1, 代表正在執行,程序就會執行一次wait3函數,檢查子進程是否有信號發給服務器主進程。如果有信號到達:那麽對於bgsave命令來說,新的rdb文件已經生成; 對於bbgrewriteaof命令來說,AOF文件已經重寫完成; 服務器需要進行相應命令的後續操作,比如用新的RDB文件替換現有RDB文件,或者用重寫後的AOF文件替換現有的AOF文件。如果沒有信號到達,那麽表示持久化操作未完成,程序不做動作。

三.初始化服務器

    一個Redis服務器啟動後,需要經過一系列的初始化和設置過程。比如(3.1)初始化服務器狀態;(3.2)接受用戶指定的服務器配置;(3.3)創建相應的數據結構和網絡連接等。

  3.1 初始化服務器狀態結構

    初始化服務器第一步就是創建一個struct redisServer類型的實例變量server作為服務器狀態,並為結構中的各個屬性設置默認值。初始化server變量的工作由redis.c/initServerConfig函數完成。主要包括:設置服務器運行ID(info 命令信息中的run_id);設置服務器的默認運行頻率(hz,在18 事件篇中有講);設置服務器的默認文件路徑(info 命令信息中的config_file) ;設置服務器運行架構(info 命令信息中的arch_bits) ;設置服務器的默認端口號(info 命令信息中的tcp_port) ;設置服務器的默認RDB持久化條件和AOF持久化條件;初始化服務器的LRU時鐘;創建命令表。 該initServerConfig函數沒有創建服務器狀態的其他數據結構;數據庫;慢查詢日誌;LUA環境;共享對象,這些數據結構在之後的步驟才會被創建出來

127.0.0.1:6379> info
# Server
redis_version:4.0.6
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:836bbbcc913c7a57
redis_mode:standalone
os:Linux 3.10.0-693.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:4.8.5
process_id:58994
run_id:b0694f86c7e794bf851f6193f1f96d85f993f325
tcp_port:6379
uptime_in_seconds:20
uptime_in_days:0
hz:10
lru_clock:659411
executable:/usr/local/redis/redis-server
config_file:/usr/local/redis/redis.conf

  

  3.2 載入配置選項

    在啟動服務器時,用戶可以通過給定配置參數或者指定配置文件來修改服務器的默認配置,當服務器在用initServerConfig函數初始化完server變量之後,就會開始載入用戶給定的配置參數和配置文件,並根據用戶設定的配置,對server變量相關屬性的值進行修改。

    例1:用戶在終端中指定redis服務器端口號,默認端口從6379變為了10086,啟動服務

         [root@xuegod64 redis]# redis-server --port 10086
         60098:C 07 Dec 16:04:05.183 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
        //下面通過另一個客戶端,指定端口,連接到服務器,通過info來查看,是沒有config_file的配置路徑。
        [root@xuegod64 ~]# redis-cli -h 127.0.0.1 -p 10086
         127.0.0.1:10086>info
        # Server
        redis_version:4.0.6
        ....

    例2: 用戶通過加載redis.conf配置文件,這是最常見的啟動服務。通過info來查看,這種是有config_file的配置路徑的

    [root@xuegod64 redis]# redis-server redis.conf

      通過上面案例知道,如果用戶為服務器狀態屬性指定了新的值,那麽服務器就會更新相應的屬性值,如果沒有為屬性設置新的值,那麽服務器就用之前initServerConfig函數為屬性設置的默認值。

  

  3.3 初始化服務器數據結構

    服務器在載入用戶指定的配置選項,並對server狀態進行更新之後,服務器就可以進入初始化第三個階段,此時服務器創建的數據結構還包括:server.clients鏈表;server.db數組;保存頻道訂閱信息的server.pubsub_channels字典以及server.pubsub_patterns鏈表; 用於執行Lua腳本的server.lua; 用於保存慢日誌的server.slowlog屬性。

    接著服務器將調用initServer函數,為以上的數據結構分配內存,該函數設置還包括:為服務器設置進程號處理器;創建共享對象;打開服務器監聽端口;為serverCron函數創建時間事件;做好AOF持久化寫入準備;初始化服務器後臺I/O模塊。當initServer函數執行完後,服務器將用ascll字符在日誌中打印出redis的圖標,以及redis的版本號信息。

技術分享圖片

    

3.4 還原數據庫狀態

    在完成了對服務器狀態server變量的初始化之後,服務器需要載入RDB文件或者AOF文件,並根據文件記錄的內容來還原服務器的數據庫狀態。如果服務器啟用了AOF持久化功能,那麽服務器使用AOF文件來還原數據庫狀態;相反 如果服務器沒有啟用AOF持久化功能,那麽服務器使用RDB文件來還原數據庫狀態。

    60183:M 07 Dec 16:06:15.343 * DB loaded from disk: 0.000 seconds    

redis 系列20 服務器下