Redis設計與實現之事件

目錄

一、事件

1、文件事件

讀事件

寫事件

2、 時間事件

3、時間事件應用實例:服務器常規操作

4、事件的執行與調度

5、事件是否有重要性級別或優先級?需要立即處理還是可以延遲處理?

6、事件的類型是什么?是針對鍵的操作,還是集群的狀態變化?

二、小結


一、事件

事件是 Redis 服務器的核心,它處理兩項重要的任務:

  1. 處理文件事件:在多個客戶端中實現多路復用,接受它們發來的命令請求,并將命令的執行結果返回給客戶端。

  2. 時間事件:實現服務器常規操作(server cron job)。

本文以下內容就來介紹這兩種事件,以及它們背后的運作模式。

1、文件事件

Redis 服務器通過在多個客戶端之間進行多路復用,從而實現高效的命令請求處理:多個客戶 端通過套接字連接到 Redis 服務器中,但只有在套接字可以無阻塞地進行讀或者寫時,服務器 才會和這些客戶端進行交互。

Redis 將這類因為對套接字進行多路復用而產生的事件稱為文件事件(file event),文件事件可 以分為讀事件和寫事件兩類。

讀事件

讀事件標志著客戶端命令請求的發送狀態。

當一個新的客戶端連接到服務器時,服務器會給為該客戶端綁定讀事件,直到客戶端斷開連接 之后,這個讀事件才會被移除。讀事件在整個網絡連接的生命期內,都會在等待和就緒兩種狀態之間切換:

? 當客戶端只是連接到服務器,但并沒有向服務器發送命令時,該客戶端的讀事件就處于 等待狀態。

? 當客戶端給服務器發送命令請求,并且請求已到達時(相應的套接字可以無阻塞地執行讀 操作),該客戶端的讀事件處于就緒狀態。作為例子,下圖展示了三個已連接到服務器、但并沒有發送命令的客戶端:

?這三個客戶端的狀態如下表:

之后,當客戶端 X 向服務器發送命令請求,并且命令請求已到達時,客戶端 X 的讀事件狀態 變為就緒:

?這時,三個客戶端的狀態如下表(只有客戶端 X 的狀態被更新了):

當事件處理器被執行時,就緒的文件事件會被識別到,相應的命令請求會被發送到命令執行 器,并對命令進行求值。

寫事件

寫事件標志著客戶端對命令結果的接收狀態。

和客戶端自始至終都關聯著讀事件不同,服務器只會在有命令結果要傳回給客戶端時,才會為 客戶端關聯寫事件,并且在命令結果傳送完畢之后,客戶端和寫事件的關聯就會被移除。

一個寫事件會在兩種狀態之間切換:

? 當服務器有命令結果需要返回給客戶端,但客戶端還未能執行無阻塞寫,那么寫事件處 于等待狀態。

? 當服務器有命令結果需要返回給客戶端,并且客戶端可以進行無阻塞寫,那么寫事件處 于就緒狀態。

當客戶端向服務器發送命令請求,并且請求被接受并執行之后,服務器就需要將保存在緩存內 的命令執行結果返回給客戶端,這時服務器就會為客戶端關聯寫事件。

作為例子,下圖展示了三個連接到服務器的客戶端,其中服務器正等待客戶端 X 變得可寫,從 而將命令的執行結果返回給它:

?此時三個客戶端的事件狀態分別如下表:

當客戶端 X 的套接字可以進行無阻塞寫操作時,寫事件就緒,服務器將保存在緩存內的命令執 行結果返回給客戶端:?此時三個客戶端的事件狀態分別如下表(只有客戶端 X 的狀態被更新了):

當命令執行結果被傳送回客戶端之后,客戶端和寫事件之間的關聯會被解除(只剩下讀事件), 至此,返回命令執行結果的動作執行完畢:?

Note: 同時關聯寫事件和讀事件

前面提到過,讀事件只有在客戶端斷開和服務器的連接時,才會被移除。

這也就是說,當客戶端關聯寫事件的時候,實際上它在同時關聯讀/寫兩種事件。

因為在同一次文件事件處理器的調用中,單個客戶端只能執行其中一種事件(要么讀,要么寫, 但不能又讀又寫),當出現讀事件和寫事件同時就緒的情況時,事件處理器優先處理讀事件。

這也就是說,當服務器有命令結果要返回客戶端,而客戶端又有新命令請求進入時,服務器先 處理新命令請求。

2、 時間事件

時間事件記錄著那些要在指定時間點運行的事件,多個時間事件以無序鏈表的形式保存在服務器狀態中。 每個時間事件主要由三個屬性組成:

? when :以毫秒格式的 UNIX 時間戳為單位,記錄了應該在什么時間點執行事件處理函數。

? timeProc :事件處理函數。
? next 指向下一個時間事件,形成鏈表。

根據 timeProc 函數的返回值,可以將時間事件劃分為兩類:

  • 如果事件處理函數返回ae.h/AE_NOMORE,那么這個事件為單次執行事件:該事件會在指 定的時間被處理一次,之后該事件就會被刪除,不再執行。

  • 如果事件處理函數返回一個非AE_NOMORE的整數值,那么這個事件為循環執行事件:該 事件會在指定的時間被處理,之后它會按照事件處理函數的返回值,更新事件的 when 屬 性,讓這個事件在之后的某個時間點再次運行,并以這種方式一直更新并運行下去。可以用偽代碼來表示這兩種事件的處理方式:

    def handle_time_event(server, time_event):# 執行事件處理器,并獲取返回值# 返回值可以是 AE_NOMORE ,或者一個表示毫秒數的非符整數值 retval = time_event.timeProc()if retval == AE_NOMORE:# 如果返回 AE_NOMORE ,那么將事件從鏈表中刪除,不再執行server.time_event_linked_list.delete(time_event) else:# 否則,更新事件的 when 屬性# 讓它在當前時間之后的 retval 毫秒之后再次運行 time_event.when = unix_ts_in_ms() + retval

    當時間事件處理器被執行時,它遍歷所有鏈表中的時間事件,檢查它們的到達事件(when 屬 性),并執行其中的已到達事件:

    def process_time_event(server): # 遍歷時間事件鏈表for time_event in server.time_event_linked_list: # 檢查事件是否已經到達if time_event.when >= unix_ts_in_ms():# 處理已到達事件 handle_time_event(server, time_event)

    Note: 無序鏈表并不影響時間事件處理器的性能
    在目前的版本中,正常模式下的 Redis 只帶有 serverCron 一個時間事件,而在 benchmark 模式下,Redis 也只使用兩個時間事件。 在這種情況下,程序幾乎是將無序鏈表退化成一個指針來使用,所以使用無序鏈表來保存時間事件,并不影響事件處理器的性能。

3、時間事件應用實例:服務器常規操作

對于持續運行的服務器來說,服務器需要定期對自身的資源和狀態進行必要的檢查和整理,從而讓服務器維持在一個健康穩定的狀態,這類操作被統稱為常規操作(cron job)。 在 Redis 中,常規操作由 redis.c/serverCron 實現,它主要執行以下操作:

? 更新服務器的各類統計信息,比如時間、內存占用、數據庫占用情況等。

? 清理數據庫中的過期鍵值對。
? 對不合理的數據庫進行大小調整。
? 關閉和清理連接失效的客戶端。
? 嘗試進行 AOF 或 RDB 持久化操作。
? 如果服務器是主節點的話,對附屬節點進行定期同步。
? 如果處于集群模式的話,對集群進行定期同步和連接測試。

Redis 將 serverCron 作為時間事件來運行,從而確保它每隔一段時間就會自動運行一次,又 因為 serverCron 需要在 Redis 服務器運行期間一直定期運行,所以它是一個循環時間事件: serverCron 會一直定期執行,直到服務器關閉為止。

在 Redis 2.6 版本中,程序規定 serverCron 每隔 10 毫秒就會被運行一次。從 Redis 2.8 開始, 10 毫秒是 serverCron 運行的默認間隔,而具體的間隔可以由用戶自己調整。

4、事件的執行與調度

既然 Redis 里面既有文件事件,又有時間事件,那么如何調度這兩種事件就成了一個關鍵問題。 簡單地說,Redis 里面的兩種事件呈合作關系,它們之間包含以下三種屬性:

  1. 一種事件會等待另一種事件執行完畢之后,才開始執行,事件之間不會出現搶占。

  2. 事件處理器先處理文件事件(處理命令請求),再執行時間事件(調用serverCron)

  3. 文件事件的等待時間(類poll函數的最大阻塞時間),由距離到達時間最短的時間事件 決定。

這些屬性表明,實際處理時間事件的時間,通常會比時間事件所預定的時間要晚,至于延遲的 時間有多長,取決于時間事件執行之前,執行文件事件所消耗的時間。

比如說,以下圖表就展示了,雖然時間事件 TE 1 預定在 t1 時間執行,但因為文件事件 FE 1 正在運行,所以 TE 1 的執行被延遲了:

另外,對于像 serverCron 這類循環執行的時間事件來說,如果事件處理器的返回值是 t ,那 么 Redis 只保證:

  • 如果兩次執行時間事件處理器之間的時間間隔大于等于t,那么這個時間事件至少會被 處理一次。

  • 而并不是說,每隔 t 時間,就一定要執行一次事件——這對于不使用搶占調度的 Redis 事件處理器來說,也是不可能做到的

    舉個例子,雖然 serverCron (sC)設定的間隔為 10 毫秒,但它并不是像如下那樣每隔 10 毫

    秒就運行一次:

在實際中,serverCron 的運行方式更可能是這樣子的:?

根據情況,如果處理文件事件耗費了非常多的時間,serverCron 被推遲到一兩秒之后才能執 行,也是有可能的。整個事件處理器程序可以用以下偽代碼描述:

def process_event():# 獲取執行時間最接近現在的一個時間事件te = get_nearest_time_event(server.time_event_linked_list)# 檢查該事件的執行時間和現在時間之差# 如果值 <= 0 ,那么說明至少有一個時間事件已到達 # 如果值 > 0 ,那么說明目前沒有任何時間事件到達 nearest_te_remaind_ms = te.when - now_in_ms()if nearest_te_remaind_ms <= 0:# 如果有時間事件已經到達# 那么調用不阻塞的文件事件等待函數 poll(timeout=None)else:# 如果時間事件還沒到達# 那么阻塞的最大時間不超過 te 的到達時間 poll(timeout=nearest_te_remaind_ms)# 處理已就緒文件事件 process_file_events()# 處理已到達時間事件 process_time_event()

通過這段代碼,可以清晰地看出:
? 到達時間最近的時間事件,決定了poll的最大阻塞時長。 ? 文件事件先于時間事件處理。

將這個事件處理函數置于一個循環中,加上初始化和清理函數,這就構成了 Redis 服務器的主 函數調用:

def redis_main(): # 初始化服務器init_server()# 一直處理事件,直到服務器關閉為止 while server_is_not_shutdown():process_event()# 清理服務器 clean_server()

5、事件是否有重要性級別或優先級?需要立即處理還是可以延遲處理?

Redis事件沒有定義重要性級別或優先級。所有的事件都會按照發生的順序進行處理,沒有特定的順序要求。因此,Redis事件可以根據需要進行立即處理,也可以延遲處理。

6、事件的類型是什么?是針對鍵的操作,還是集群的狀態變化?

Redis事件的類型有兩種,分別是針對鍵的操作事件和集群的狀態變化事件。

  1. 針對鍵的操作事件(Key Event):這些事件與鍵的操作相關,包括以下幾種類型:

    • SET:當一個鍵被設置或修改時觸發。
    • GET:當一個鍵被獲取時觸發。
    • DEL:當一個鍵被刪除時觸發。
    • EXPIRE:當一個鍵的過期時間被設置時觸發。
    • EXPIRED:當一個鍵的過期時間到達時觸發。
    • RENAME:當一個鍵被重命名時觸發。
    • PERSIST:當一個鍵的過期時間被移除時觸發。
    • ...
  2. 集群的狀態變化事件(Cluster Event):這些事件與Redis集群的狀態變化相關,包括以下幾種類型:

    • NODE ADDED:當一個新的節點加入集群時觸發。
    • NODE REMOVED:當一個節點被移除集群時觸發。
    • NODE UPDATED:當一個節點的狀態或信息發生變化時觸發。
    • SLOT ASSIGNED:當一個槽位被指派給一個節點時觸發。
    • SLOT UNASSIGNED:當一個槽位從一個節點上移除時觸發。
    • ...?

二、小結

  • Redis 的事件分為時間事件和文件事件兩類。

  • 文件事件分為讀事件和寫事件兩類:讀事件實現了命令請求的接收,寫事件實現了命令 結果的返回。

  • 時間事件分為單次執行事件和循環執行事件,服務器常規操作serverCron就是循環事 件。

  • 文件事件和時間事件之間是合作關系:一種事件會等待另一種事件完成之后再執行,不 會出現搶占情況。

  • 時間事件的實際執行時間通常會比預定時間晚一些。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/537312.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/537312.shtml
英文地址,請注明出處:http://en.pswp.cn/news/537312.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何用python32位開發詞典軟件_Python如何實現字典?

I was wondering how python dictionaries work under the hood, particularly the dynamic aspect?When we create a dictionary, what is its initial size?If we update it with a lot of elements, I suppose we need to enlarge the hash table. I suppose we need to r…

信息系統項目管理師:軟件測試、調試及其管理

1&#xff0e;4&#xff0e;5軟件測試及其管理 1、軟件測試方法可分為靜態測試和動態測試。 靜態測試是指被測試程序不在機器上運行&#xff0c;而采用人工檢測和計算機輔助靜態分析的手段對程序進行檢測。靜態測試包括對文檔的靜態測試和對代碼的靜態測試。對文檔的靜態測試…

項目驗收材料整合流程

目標&#xff1a;多份word整合成一份項目驗收材料 第一步&#xff1a;編寫好word&#xff1b;準備好一份驗收材料的封面與目錄word 第二步&#xff1a;用WPS的word轉PDF&#xff0c;批量轉成PDF&#xff1b; 第三步&#xff1a;用Adobe Acrobat DC 合并轉成的多個PDF成為一個…

python調用接口獲取文件_python接口文件使用說明

首先&#xff0c;python接口文件在安裝好的darknet目錄下的python文件夾&#xff0c;打開就可以看到這里的darknet.py文件就是python接口用編輯器打開查看最后部分代碼&#xff1a;使用十分簡單&#xff0c;先將網絡配置加載進去&#xff0c;然后進行檢測就行了。但其實現在還不…

[譯]Kube Router Documentation

體系結構 Kube路由器是圍繞觀察者和控制器的概念而建立的。 觀察者使用Kubernetes監視API來獲取與創建&#xff0c;更新和刪除Kubernetes對象有關的事件的通知。 每個觀察者獲取與特定API對象相關的通知。 在從API服務器接收事件時&#xff0c;觀察者廣播事件。 控制器注冊以獲…

windows11 22H2資源管理器開啟多標簽頁

效果 步驟 windows11 22H2后續可能會推送該功能&#xff0c;現在是隱藏的&#xff0c;需要借助工具把這個隱藏功能開啟 工具&#xff1a;vivetool 下載&#xff1a;Releases thebookisclosed/ViVe GitHub 步驟1&#xff1a;右鍵開始菜單&#xff0c;選擇“終端&#xff08;…

python像素處理_Python 處理圖片像素點的實例

###在做爬蟲的時候有時需要識別驗證碼,但是驗證碼一般都有干擾物,這時需要對驗證碼進行預處理,效果如下:from PIL import Imageimport itertoolsimg Image.open(C:/img.jpg).convert(L) #打開圖片,convert圖像類型有L,RGBA# 轉化為黑白圖def blackWrite(img):blackXY []# 遍歷…

Mysql更改表名大小寫不敏感

編輯配置文件 vi /etc/my.cnf 在[mysqld]后添加添加 lower_case_table_names1 重啟服務 service mysqld stop service mysqld start 部署會遇到的問題&#xff1a; MySQL在Linux下數據庫名、表名、列名、別名大小寫規則是這樣的&#xff1a;   1、數據庫名與表名是嚴格區分大…

遇到“我覺得行才算行”的業主怎么辦?

目錄 案例 分析 案例 項目初期UI設計需求不確定,我們設計了幾稿,業主還是不滿意,沒有確定最終稿。后來呢,業主安排了一位內部的美工A過來。美工A給出了很多修改意見,我們根據美工A的意見進行了修改,又反反復復改了好幾版,最后業主不算滿意地確定了。 后來項目要收尾…

python讀取多個文件夾下所有txt_Python實現合并同一個文件夾下所有txt文件的方法示例...

本文實例講述了Python實現合并同一個文件夾下所有txt文件的方法。分享給大家供大家參考&#xff0c;具體如下&#xff1a;一、需求分析合并一個文件夾下所有txt文件二、合并效果三、python實現代碼# -*- coding:utf-8*-import sysreload(sys)sys.setdefaultencoding(utf-8)impo…

項目是臨時的,那項目組成員也是臨時的嗎?

在PMBOK定義項目屬性&#xff0c;“臨時性”是項目的三大屬性之一。 在“結束項目或階段”過程里的活動&#xff0c;重新分配人員&#xff1a;釋放團隊資源&#xff0c;在一些合同里面&#xff0c;項目結束后&#xff0c;需要給客戶提供培訓和一段時間的維護保修&#xff0c;那…

ceph安裝配置

簡介 ceph是一個開源分布式存儲系統&#xff0c;支持PB級別的存儲&#xff0c;支持對 象存儲&#xff0c;塊存儲和文件存儲&#xff0c;高性能&#xff0c;高可用&#xff0c;可擴展。 部署網絡建議架構圖 部署 部署架構圖&#xff0c;本次實驗部署jewel版本 實驗環境的Vagrant…

推薦好用的JavaScript模塊

2019獨角獸企業重金招聘Python工程師標準>>> 譯者按&#xff1a; 作者將自己常用的JavaScript模塊分享給大家。 原文&#xff1a;? JavaScript Modules Worth Using ?譯者: Fundebug為了保證可讀性&#xff0c;本文采用意譯而非直譯。另外&#xff0c;本文版權歸原…

python直接連接oracle_python連接oracle

一&#xff1a;弄清版本&#xff0c;最重要&#xff01;&#xff01;&#xff01;首先安裝配置時&#xff0c;必須把握一個點&#xff0c;就是版本一致&#xff01;包括&#xff1a;系統版本&#xff0c;python版本&#xff0c;oracle客戶端的版本&#xff0c;cx_Oracle的版本&…

項目計劃不要拖,要趕緊排

目錄 案例 復盤 應對 總結 案例 業主:這個項目很急,趕緊干活吧,明天就安排人來干活。 于是,項目經理問公司要來資源,第二天就投入到項目里。 公司只有一個項目,這樣搞,項目能順利實施,業主滿意,公司老板感覺這種方法不錯哦。 當公司項目越來越多了,員工也越來…

select函數_SQL高級功能:窗口函數

一、窗口函數有什么用&#xff1f;在日常生活中&#xff0c;經常會遇到需要在每組內排名&#xff0c;比如下面的業務需求&#xff1a;排名問題&#xff1a;每個部門按業績來排名topN問題&#xff1a;找出每個部門排名前N的員工進行獎勵面對這類需求&#xff0c;就需要使用sql的…

客戶端C++與前端js交互

客戶端與前端交互 qwebchannel.js文件引入建立通信// c發送消息給js new QWebChannel(qt.webChannelTransport, function(channel){var content channel.objects.jsContext;// 建立通信后&#xff0c;客戶端通過調用 sMsg 方法來執行后面的回調函數&#xff0c;從而實現c與j…

python動態映射_sqlalchemy動態映射

似乎您可以直接使用屬性&#xff0c;而不是使用columnsdict。考慮以下設置&#xff1a;from sqlalchemy import Table, Column, Integer, Unicode, MetaData, create_enginefrom sqlalchemy.orm import mapper, create_sessionclass Word(object):passwordColumns [english, k…

linux外接顯示屏,關掉本身的筆記本電腦

https://blog.csdn.net/a2020883119/article/details/79561035 先用xrandr命令查看&#xff1a; eDP-1 connected eDP-1是連接著的 關掉&#xff1a;sudo xrandr --output eDP-1 --off 打開&#xff1a;sudo xrandr --output eDP-1 --auto

發揮項目“臨時性”威力,讓項目順利實施

所謂臨時性,就是要有明確的“開始”和“結束”。雖然大家都知道項目一定會有開始和結束的,但要更多地關注“明確“。 問題1:問商務(售前)或業主,這個項目什么時候結束? 答:商務或業主他們有時候也不知道,因為國內的項目大多數是提前開始交付,是一邊交付,一邊把里程…