1. 程式人生 > >全面解讀 NoSQL 資料庫 Redis 的核心技術與應用實踐

全面解讀 NoSQL 資料庫 Redis 的核心技術與應用實踐

640?wx_fmt=gif&wxfrom=5&wx_lazy=1

640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

網際網路和Web的蓬勃發展正在改變著我們的世界,隨著網際網路的不斷髮展和壯大,企業資料規模越來越大,併發量越來越高,關係資料庫無法應對新的負載壓力,隨著Hadoop,Cassandra,MongoDB,Redis等NoSQL資料庫的興起,因其良好的可擴充套件性,弱化資料庫的設計正規化,弱化一致性要求,在解決海量資料和高併發的問題上明顯優於關係型資料庫。因而很快廣泛應用於網際網路業務中。

Redis作為基於K-V的NoSQL資料庫,具有高效能、豐富的資料結構、持久化、高可用、分散式、支援複製等特性。從09年至今,經歷8年多的錘鍊,已經非常穩定,並且得到業界的廣泛認可和使用,同時社群非常活躍。

今天我們有幸邀請到了Redis中國使用者組主席張冬洪老師,請他分享Redis的核心技術,應用現狀及發展方向等。

遇見未來640?wx_fmt=pngDB舞臺孰是王者之Redis專訪

自我介紹,團隊介紹

1

640?wx_fmt=jpeg

我是來自新浪微博研發中心的高階DBA 張冬洪,目前在微博帶一個小組,主要負責微博平臺、手機微博、話題、紅包飛、開放平臺、私信、以及內容管控專案的資料庫產品運維和服務保障工作。工作中涉及的資料庫產品主要包括MySQL、Redis、Memcached、MCQ、Kafka、Pika、Postgresql等。

目前您的團隊工作重心是什麼呢?

2

微博研發中心資料庫部門主要負責全微博平臺的後端資源的託管和運維,涉及的資源種類比較多,資料量比較大,業務線和資源例項數目也是非常之多,併發量巨大。而這些正是微博這種體量的公司應該具有的,微博作為當今中文社交媒體的第一品牌,擁有超過3.76億的月活使用者,也是當前社會熱點事件傳播的最主要平臺,其中包括但不限制於大型活動(如:里約奧運會、朱日和沙場大點兵等),春晚,明星動態(如:王寶強離婚事件、女排奪冠、喬任樑去世、白百合出軌、TFBOYS生日、鹿晗關曉彤CP等)。

而熱點事件往往具有不可預見性和突發性,並且伴隨著極短時間內流量的數倍增長,甚至更多,有時持續時間較長。如何快速應對突發流量的衝擊,確保線上服務的穩定性,是一個非常巨大的挑戰和有意義的事情。為了達到這一目標,需要有一個完善的,穩定可靠的,健壯的資料庫運維體系來提供支撐和管理,所以我們團隊也是在領導的指導下,有目標、有計劃的開展一些資料庫自動化運維平臺的建設工作。

640?wx_fmt=png

在業餘的時間我和其他幾大網際網路公司的朋友一起發起了Redis中國使用者組(簡稱CRUG),也歡迎大家加入我們。

Redis在過去的版本演進中,比較重大的變化包括哪些呢?在最新4.0版本上,您認為最核心的變化是什麼呢?您關注的新特性有哪些,可以簡單介紹下嗎?
3

我最早接觸應該是在12年的時候,當時最新的版本應該是2.6.x。那個時候也沒有在線上用,只是學習Linux的時候瞭解過。所以知道Redis的版本號命名規則借鑑了Linux的方式,版本號第二位如果是奇數,則為非穩定版本,如果為偶數,則為穩定版本。

這裡我說下穩定版本的一些主要改進吧:

•Redis2.6

1)鍵的過期時間支援毫秒

2)從節點提供只讀功能

3)服務端支援Lua指令碼

4)放開客戶端連線數的硬編碼限制

5)去掉虛擬記憶體相關功能等

•  Redis2.8

1)完善主從複製功能,實現增量複製

2)Redis設定明顯的程序名,在系統中ps命令即可檢視

3)釋出/訂閱新增pub/sub命令

4)Redis Sentinel第二版釋出,較Redis 2.6更加完善,可以線上使用

5)可以通過config set命令設定maxclients等

•  Redis3.0

1)推出Redis的分散式叢集 Redis Cluster

2)全新的embedded string物件編碼結果,優化小物件的記憶體訪問,在特定的工作負載下能大幅度提升效能

3)LRU演算法提升

4)config set 設定maxmemory的時候可以設定不用的單位

5)新的Client pause命令,在指定時間內停止處理客戶端請求等

•  Redis3.2

1)新增GEO功能

2)新的List編碼型別quicklist 

3)SDS在速度和節省空間上都做了優化

4)Lua指令碼功能增強

5)新的RDB格式,仍相容舊版RDB,同時載入速度上也有提升

6)Cluster nodes命令加速等

在Redis4.0版本上,我認為最核心的功能應該是支援了module,這極大的豐富的Redis的功能,使得許多Redis本身不具有的,第三方開發者拓展的功能也能載入到Redis中當一個功能進行使用,比如RediSearch、ReJSON、Redis-ML等。除此之外,還看到有很多新特性:

1)psync2.0,優化了之前版本主從節點切換必然引起全量複製的問題

2)提供全新的快取剔除演算法LFU,並對已有演算法進行了優化

3)提供了非阻塞del和flushall和flushdb功能,有效解決了刪除bigkey可能造成的Redis阻塞

4)提供了RDB-AOF混合持久化格式

5)提供memory命令,實現對記憶體的更為全面的監控統計

6)Redis Cluster 相容NAT和Docker

7)引入Jemalloc庫,優化記憶體訪問等等

您能介紹一下Redis中的資料型別和它們的使用場景嗎?

4

Redis之所以能夠被廣泛的應用於企業的架構中,而且是不可或缺的重要組成部分,也可以說是標配吧,其中很重要的一點就是得益於它具有豐富的資料結構,這也是它逐漸替代Memcached,備受青睞的重要原因。那麼Redis都提供哪些資料型別呢?

相信對Redis有了解過的同學都知道,它的資料型別有:String、Hash、List、Set、Zset、Bitmaps、HyperLogLog、GEO等。

640?wx_fmt=png

隨著網際網路的興起和Redis技術的不斷完善和發展,它已經被廣泛應用於各行各業中,應用場景也是百花齊放。比如:會話快取(Session cache)、全頁快取(FPC)、手機驗證碼、訪問頻率限制/黑白名單、訊息佇列、釋出與訂閱、訊息通知、排名/排行榜/最新列表、計數器(比如微博的轉評贊計數、閱讀數(瀏覽數,視訊播放計數)、博文數(發帖數)、粉絲數、關注數(喜歡商品數)、未讀數(動態數))、共同好友/喜好/標籤、推送、下拉重新整理、私信、商品庫存管理(限時的優惠活動資訊)、證券指標實時計算,發號器/UUID、以及隨著LBS(基於位置服務)的發展,加入的GEO(地理資訊定位)的功能和基於Lua自定義命令或功能等等。大家在使用過程中,需要結合自己的業務場景,選擇正確的資料型別。

Redis資料庫有哪些主要的特點和優勢?使用時有什麼需要關注的點,可能會帶來哪些問題,可否通過實踐案例詳細描述一下?

5

Redis作為基於K-V的NoSQL資料庫,具有高效能、豐富的資料結構、持久化、高可用、分散式、支援複製等特性。從09年至今,經歷8年多的錘鍊,已經非常穩定,並且得到業界的廣泛認可和使用,同時社群非常活躍,開發者又很嚴謹,這使得Redis版本非常精簡,bug fix非常高效。根據similarweb.com的統計,中國Redis使用者佔全球Redis使用者的40.96%,所以我們在使用的過程中遇到的問題,大部分可能都有解決方案。

需要關注的點比較多,之前在CRUG深圳站活動的分享中也提到過一些,下面舉一些例子吧:

1)安全問題:Redis用非root使用者啟動,並且執行在內網,儘可能不要暴露在外網,配置認證requirepass xxx,減少被攻擊的風險;開啟危險命令認證(keys-need-auth yes   rename-command KEYS MY_KEYS)

2)容量問題:合理評估;合理使用記憶體分配策略(no-enviction、allkeys-random、allkeys-lru、volatile-random、volatile-ttl、volatile-lru);檢查是否有記憶體碎片;選擇合適的服務型別(Redis cluster或者pika);水平拆分;效能滿足的條件下選擇諸如ziplist類的內部編碼

3)big-key問題:可能會引起慢查或者頻寬瓶頸,按照業務邏輯拆成小key或者業務解耦剝離big-key或直接改用其他儲存方式

4)hot-key問題:Redis是單程序,節點例項很容易成為系統的短板,垂直擴容;增加local cache;如果只是簡單的k-v結構,可以考慮使用Memcached

5)使用姿勢問題:避免使用阻塞操作(如:flushall、flushdb、keys *等);儘量使用Pipeline,減少syscall帶來的網路IO,但要注意限制資料量大小;對多個元素操作時,像使用SORT、LREM、SUNION,計算複雜度為O(N), 避免線上亂用;儘可能使用最新的版本

6)Key過期問題:合理設定過期時間;如果存在許多該過期的key而沒被及時刪除,可以通過命令scan、hscan、sscan、zscan、keys *遍歷一遍key的方式實現

7)配置上:建議開啟tcp-keepalive,tcp-backlog,從庫設定readonly yes

8)系統設定:關閉NUMA;關閉transparent _hugepage; 關閉swap

等等,大家有問題的時候可以相互交流。

Redis如何做訊息佇列?

6

Redis做訊息佇列,有兩種實現方式:

第一種:通過資料結構List來實現

640?wx_fmt=png

優點:能夠實現持久化;支援叢集;介面使用簡單

缺點:

  • 如上圖所示,一條訊息只會被一個消費者消費,所以不存在有多個消費者消費一條訊息

  • 生產者和消費者的高可用或崩潰後的處理機制需要自己實現

  • 當生產者訊息寫入太快,消費者消費太慢,則有可能會導致記憶體溢位問題,導致程序crash

第二種:通過pub/sub來實現

640?wx_fmt=png

優點:

一個生產者可以對應多個消費者,但是必須保證訊息釋出者和訊息的訂閱者同時線上,否則,否則一旦訊息訂閱者由於各種異常情況而被迫斷開連線,在其重新連線後,其離線期間的訊息是無法被重新通知的(即發即棄)。當然,生產者不需要關心有多少的訂閱者,也不用關心訂閱者的具體資訊,而訂閱者可以根據需要自由選擇訂閱哪些頻道:支援叢集;介面使用簡單等。

缺點:

  • 沒有持久化機制,屬於即發即棄模式,因此也不需要制定訊息的備份和恢復機制

  • Redis沒有提供保證pub/sub訊息效能的方案

  • 當大量的訊息到達Redis服務時,如果訂閱者不能及時完成消費,則就會導致訊息堆積,引發上面一樣的記憶體問題      

您可以介紹下當前Redis的叢集功能和實現嗎?

7

要了解Redis的叢集功能,可以從資料分片、資料遷移、叢集通訊、故障檢測以及故障轉移等方面進行了解,Cluster相關的程式碼也不是很多,註釋也很詳細,可自行檢視,地址是:https://github.com/antirez/redis/blob/unstable/src/cluster.c。

這裡由於篇幅的原因,主要從資料分片和資料遷移兩方面進行詳細介紹:

  • 資料分片

Redis cluster在設計中沒有使用一致性雜湊(consistency hashing),而是使用資料分片(sharding),引入雜湊槽(hash slot)來實現;一個 redis cluster包含16384(0~16383)個雜湊槽,儲存在redis cluster中的所有的鍵都會被對映到這些slot中,叢集中的每個鍵都屬於這16384個雜湊槽的其中一個,叢集使用公式slot=CRC16(key)/16384來計算key屬於哪個槽,其中CRC16(key)語句用於計算key的CRC16 校驗和。

叢集中的每個主節點(Master)都負責處理16384個雜湊槽中的一部分,當叢集處於穩定狀態時,每個雜湊槽都只由一個主節點進行處理,每個主節點可以有一個到N個從節點(Slave),當主節點出現宕機或網路斷線等不可用時,從節點能自動提升為主節點進行處理。

640?wx_fmt=png

如上,clusterNode資料結構中的slots和numslots屬性記錄了節點負責處理哪些槽。其中,slot屬性是一個二進位制位陣列(bitarray),其長度為16384/8=2048 Byte,共包含16384個二進位制位。叢集中的master節點用bit(0和1)來標識對於某個槽是否擁有。比如,對於編號為1的槽,master只要判斷序列的第二位(索引從0開始)的值是不是1即可,時間複雜度為O(1)。

640?wx_fmt=png

叢集中所有槽的分配資訊都儲存在clusterState資料結構的slots陣列中,程式要檢查槽i是否已經被分配或者找出處理槽i的節點,只需要訪問clusterState.slots[i]的值即可,複雜度也為O(1)。clusterState資料結構如下所示:

640?wx_fmt=png

查詢關係如下圖:

640?wx_fmt=png

  • 資料遷移

資料遷移可以理解為slot和key的遷移,這個功能很重要,極大的方便了叢集做線性擴充套件,實現平滑的擴容或縮容。

那麼它是一個怎樣的實現過程呢?

下面舉個例子:現在要將Master A節點中的編號為1、2、3的slot遷移到Master B節點中,在slot遷移的中間狀態下,slot 1、2、3在Master A節點的狀態表現為MIGRATING,在Master B節點的狀態表現為IMPORTING。

640?wx_fmt=png

MIGRATING狀態

這個狀態如上圖所示是被遷移slot在當前所在Master A節點中出現的一種狀態,預備遷移slot從Mater A到Master B的時候,被遷移slot的狀態首先變為MIGRATING狀態,當客戶端請求的某個key所屬的slot的狀態處於MIGRATING狀態的時候,可能會出現以下幾種情況:

1)如果key存在則成功處理

2)如果key不存在,則返回客戶端ASK,客戶端根據ASK首先發送ASKING命令到目標節點,然後傳送請求的命令到目標節點

3)當key包含多個命令時:

  • 如果都存在則成功處理

  • 如果都不存在,則返回客戶端ASK

  • 如果一部分存在,則返回客戶端TRYAGAIN,通知客戶端稍後重試,這樣當所有的key都    遷移完畢的時候客戶端重試請求的時候回得到ASK,然後經過一次重定向就可以獲取這批鍵

此時並不重新整理客戶端中node的對映關係

IMPORTING狀態

這個狀態如上圖所示是被遷移slot在目標Master B節點中出現的一種狀態,預備遷移slot從Mater A到Master B的時候,被遷移slot的狀態首先變為IMPORTING狀態。在這種狀態下的slot對客戶端的請求可能會有下面幾種影響:

1)如果key不存在則新建

2)如果key不在該節點上,命令會被MOVED重定向,重新整理客戶端中node的對映關係

如果是ASKING命令則命令會被執行,從而key沒在被遷移的節點,已經被遷移到目標節點的情況命令可以被順利執行。

鍵空間遷移

這是完成資料遷移重要的一步,鍵空間遷移是指當滿足了slot遷移前提的情況下,通過相關命令將slot 1、2、3中的鍵空間從Master A節點轉移到Master B節點,這個過程由MIGRATE命令經過3步真正完成資料轉移。步驟示意如下:

640?wx_fmt=png

經過上面三步可以完成鍵空間資料遷移,然後再將處於MIGRATING和IMPORTING狀態的槽變為常態即可,從而完成整個重新分片的過程。

請您簡單介紹下Redis的高可用方案,如果可以,結合您的實踐經驗和案例進行分析

8

根據業務的規模以及Redis使用環境的不同,Redis的高可用方案也比較多。這裡舉一些例子說明一下業界比較常用的一些方案吧。需要說明一下的是下面的這些方案不涉及到同城多活或異地多活的場景,但是部分方案能夠做到跨資料中心的災備。

•Keepalive + Redis

640?wx_fmt=png

•Redis Sentinel

640?wx_fmt=png

•Twemproxy + Redis Sentinel + Redis

640?wx_fmt=png

•Redis Cluster

640?wx_fmt=png

•Redis Sentinel + Proxy + Zookeeper + Redis

640?wx_fmt=png

•Zookeeper + MySQL + Redis + DNS

640?wx_fmt=png

Redis資料庫在向著自動化運維的方向發展的過程中,面臨的最大的挑戰是什麼?如何克服?

9

如果不強調“最大的”話,我知道有不少的挑戰,哈哈。

我想最大的挑戰應該是“智慧化”吧。現在業界都在追捧DevOps、AIOps,那麼在Redis的自動化運維過程中,也需要學習行業的先進思想,結合部門自身的實際穩紮穩打,逐一突破。

首先在智慧化實現之前,我們要盡力實現下面的一些需求:

1)資料庫運維自動化平臺的建設,為RD和DBA提供較全面的自助服務和資料庫管理功能

2)工單事件關聯任務系統,一鍵完成自動安裝部署,新增產品線和報警

3)海量報警智慧分類(比如按產品線或按DBA分類),實現部分報警故障自愈 (比如:從庫readonly設定、記憶體使用率超過95%自動擴容)

4)基於佇列分散式批量部署,可橫向擴充套件,任務非同步排程,滿足大規模部署、擴容的需求

5)日誌實時展示,監控資料實時採集,圖形化多維度展示,滿足視覺化的需求

6)RedisHA支援秒級響應,實現故障無縫切換,滿足高可用的需求

7)快取彈性擴縮容(利用私有云和公有云,結合Docker容器化技術實現),滿足對熱點的快速應對

8)內部開發了各種通用的管理和運維指令碼,化繁為簡,提高工作效率

9)根據歷史/晚高峰資源的效能指標設定水位線,和報警閾值,提供決策支援

10)在Redis叢集、容災、異地多活(跨資料中心資料同步)、微服務等等方面還需要花很大的力氣去建設,目前依舊比較欠缺

智慧化的實現還需要持續的投入和迭代。

近幾年隨著大資料時代的到來,NoSQL資料庫在處理海量資料上表現出越來越多的優勢,請問您如何看待資料庫的未來,會朝著什麼樣的方向發展?

10

是的,這幾年從運維的角度看,明顯能感覺到資料體量上的膨脹,一個例項動不動就幾十G,一個叢集動不動幾百G、幾T,甚至更多。以Redis為代表的NoSQL資料庫在處理這方面的表現還是令人非常滿意的。它的高效能表現得淋漓盡致,從微博的業務來看,Redis例項每天承載著千億級的寫QPS、萬億級的讀QPS,資料量TB級,確實沒有Redis,且不說能不能用關係型資料庫儲存,單是硬體成本就幾何倍增長了吧。

未來,隨著硬體成本的降低,硬體效能優化的極致,比如PCIE、25GE網路的升級,一定是軟硬結合,會出現更多的Redis的相關產品和服務。包括收費的Redis Enterprise,Cloud Redis等,也包括開源的Pika、TiDB等NewSQL。正如阿里雲的同學所說,“資料庫終極是九九歸一 -- 量子資料庫”,一起期待吧。

對於初學Redis的同學,您有什麼好的學習方法和技巧給他們嗎?

11

首先當然還是需要多看官方文件,多看看業界大牛的技術部落格。其次可以買幾本書對比著學習下,目前市面上的相關書籍也就4,5本的樣子。然後主要的還是要多動手,實踐出真知,在使用的過程中,還是要結合具體的業務場景,靈活使用。有能力的時候,看看原始碼,瞭解底層的實現原理。最後,多思考多總結,好記性不如爛筆頭,每一次踩坑都是一次成長,遇到解決不了的問題的時候多向業界大牛們請教學習,平時多關注一些業界相關技術的最新動態。

您如何看待Redis的未來?從技術和非技術的多個維度,您如何看待Redis的發展方向

12

縱觀Redis的發展,無獨有偶的與網際網路的發展浪潮緊緊相隨,從web1.0到web2.0的轉變,從部落格、貼吧、論壇到社交媒體,從文字到圖文再到短視訊的興起,從網際網路到移動網際網路,從3G到4G到即將普及的5G,從異軍突起的新興產業,如:團購、電商、外賣、旅遊、遊戲、網際網路金融和證券、出行和直播等等,商業模式在不斷的改變,不斷的在重新整理人們的生活方式。

但是在這些變化的背後,不變的是Redis作為基礎服務為企業的高可用架構保駕護航,變化的是Redis的使用案例越來越豐富、服務體驗越來越好。在Redis的發展過程中,由於企業需求的多樣化,對Redis的要求越來越高,許多場景Redis的功能顯得相形見絀,因此出現了諸如Codis、Pika、CounterService、ApsaraCache、CacheCloud、smartClient(Redisson)等產品,它們是對Redis的有益補充。

隨著4.0版本module功能的推出,使得Redis擁有更多的想象和發展空間,在全文索引(RediSearch),AI(Redis-ML)、雲端計算、大資料、物聯網、人工智慧、BlockChain等領域,模組化的融合能力將極大的豐富Redis的功能,從而為企業構建更為多元化、立體化的資料庫使用方式。

您還有什麼想要分享的嗎?

13

在使用Redis的過程中,還需要保持關注官方的動態,多看看github上的changelog和issue,因為隨著Redis的使用者群體的增多,使用場景的複雜化,Redis自身隱藏的問題或瓶頸也會暴露出來,這樣有助於我們避免踩一些不必要的坑,及早規避一些風險。

不僅僅是Redis,學習其他的資料庫也是一樣的。另外,我們在關注Redis本身以外,還需要關注一些其他的Redis的替代產品(比如:SSDB、Pika、Codis、ApsaraCache、TiDB等),Redis的周邊工具(如:redis-migrate-tool、redis-faina、redis-audit、redis-rdb-tools、RedisMyAdmin等)、中介軟體(如:twemproxy、corvus、redis-cerberus)等。如果你想要從事Redis的開發,那麼你可能需要關注的更多,比如各種鎖的實現。

本文轉載自公眾號「資料和雲」

更多相關文章閱讀

精彩不止一瞬間

2天的時間,50多場精彩演講,你可以學到很多

來GOPS 深圳站。前瞻視訊新鮮出爐⬇️

點選閱讀原文,參與報名⬇️