高 昕,黃 真
(國電南瑞科技股份有限公司,江蘇南京 210061)
Redis 的全名為遠程字典服務(Remote Dictionary Server),它是一個基于內存的鍵-值(Key-Value)數據庫,在很大程度上彌補了內存緩沖存儲的匱乏[1]。Redis 為 Value 提供了非常靈活的數據形式,主要包括字符串(String)、鏈表(List)、集合(Set)、有序集合(Zset)及哈希表等[2]。對于不同的存儲需求,Redis 中總可以找到相應的鍵-值數據類型來匹配,例如將 String與 Json(JavaScript 對象表示法)進行結合,可以將完整的數據結構存入值中,而哈希表的方式又為成員變量的快速存取提供了極大的方便。Redis 在將數據實時寫入內存的同時,可以根據系統設計的需要,采用快照存儲(Snapshotting)或附加文件(AOF)的方式將數據進行持久化[3],一定程度上保證了數據安全,防止系統故障等意外事故對重要數據的影響。
Redis 支持多個實例的集群,采用一主(Master)多從(Slave)的方式,主/從之間采用數據復制的方式,可以將因單一 Redis 實例故障而導致的數據丟失及系統故障的概率降至最低,且結構上支持多級主/從[4]。集群內的主/從復制功能對雙方都不會產生阻塞(圖1),從節點可以只當作主節點的數據冗余備份,也可以提供只讀命令來減輕主節點服務器的壓力[5]。

圖1 主/從復制原理
Redis-Sentinel 是 Redis 官方推薦的高可用性解決方案,其本身也是一個獨立運行的進程,它能監控多個主/從集群,發現主節點宕機后能進行自動切換。主要有以下功能。
(1)監控:Sentinel 時刻監控 Redis 是否按照預期良好地運行。
(2)提醒:如果發現某個 Redis 節點運行出現狀況,能夠通知集群中其他 Sentinel 進程或應用服務。
(3)自動故障遷移:當 1 個主節點不可用時,能夠從該主節點的多個從節點中推選出 1 個可用的升為主節點,并通知其他從節點從新的主節點復制數據。
(4)Sentinel 本身支持集群的方式,對于主/從的切換采用多數表決的方法進行推選。另外,即使并非全部的 Sentinel 都在工作,Sentinel 也可以正常工作。Redis 與Redis-Sentinel 建立的集群結構如圖2 所示。

圖2 Redis 集群框架
Redis 的發布/訂閱(Pub/Sub)功能類似于以往的消息路由功能,發布/訂閱模式包含 2 種角色,分別是發布者和訂閱者。發布者發布消息,訂閱者接收消息,而訂閱的頻道則用來溝通發布者和訂閱者。發布/訂閱模式可以為進程之間提供消息傳遞,訂閱者可以訂閱 1 個或若干個頻道,發布者可以向任意頻道發送消息,只要訂閱了此頻道,都將收到此消息[6]。
在 Redis-Sentinel 的集群應用中,客戶端通過應用程序接口(API)向任一 Sentinel 服務訂閱主/從切換的通知消息,則當 Sentinel 監測到主節點或從節點的任何狀態變化時(上線、下線、表決結果及故障切換狀態等),都將通過消息通道發送到客戶端,通知客戶端重新連接最新的主/從節點以進行數據操作。
與地鐵不同,有軌電車因為自身的特點(與公共交通共享路權、行駛速度低等)決定了車載系統為非“故障-安全”系統[7]。在該系統中,控制及采集、顯示終端均采用雙機熱備的方式,分別放置于車廂兩端的駕駛艙中[8]。典型的有軌電車車載系統的組成如圖3 所示。
該系統的組成主要包括以下幾個特點:
(1)2 套冗余的車載控制主機(OBU)獨立接收各種外部接口數據;
(2)數據匯集在被接收的 OBU 中,2 套OBU 之間進行數據交互;
(3)1 套 OBU 故障時,由另外 1 套系統進行控制接管。
該系統構架對于非“故障-安全”的系統可以滿足系統功能要求,但可能帶來的問題主要有:
(1)2 套 OBU 之間需要在軟件級別同步數據,如當主用機 GPS 接收故障時,備用機接收到 GPS 位置數據時需要與主用機同步,既要考慮數據同步周期等問題,也要定義復雜的通信接口;
(2)針對每個 OBU 系統來說,接收到的外部數據及系統關鍵數據一般被存儲在進程自身的內存中,關鍵數據的持久化通過應用軟件進行本地文件的讀寫來完成,當系統故障重啟時可能會造成關鍵數據的丟失;
(3)客戶端對數據的訪問只能通過向主用 OBU 主動查詢或接收主用 OBU 的數據推送而獲得。
綜上列舉的應用層的問題,雖然不會對系統安全穩定帶來影響,但卻為功能的實現增加了操作復雜度,同時系統結構中各個模塊之間需要定義非常復雜的基于網絡的通信接口,也為系統間模塊增加了很大的耦合性。

圖3 車載系統結構簡圖
基于 Redis 集群的車載系統方案,在系統的結構上帶來的優勢主要有:
(1)Redis 是一個開放網絡訪問的數據庫,系統內的任意授權節點都可以通過相應的應用程序接口(API)從集群中獲取最新的數據,在數據訪問的隨機性上十分靈活;
(2)任意的接口程序都可以通過 API 及集群代理軟件將最新的數據寫入 Redis,數據庫中只保存 1 份最新的數據,為冗余系統的應用層開發帶來便利;
(3)Redis 系統集群中,主/從的復制由 Redis 負責執行,用戶不需要關心冗余系統中多個數據庫數據不一致或新上電機器的數據同步問題;
(4)集群系統的穩定性不會因為某個客戶端或服務端的故障而受到影響,且 Redis 的持久化技術可以將內存數據按照設定的方式固化到本地文件中,保證了數據的安全性,當 Redis 故障重啟時,可以從本地文件中重新加載數據到內存;
(5)Redis 的數據訪問十分高效,支持單步、事務、異步及管道技術等方法進行批量數據庫訪問[9]。
由此可見,采用 Redis 集群技術的車載系統可以為應用層的開發提供極大的便利性和系統數據的安全穩定性,基于此思路建立的車載系統結構圖如圖4 所示。
分析圖4 的系統結構圖,可知:
(1)字母 A、B 分別代表2 套車載設備對應的實例,每套設備均配備獨立的前置接口程序;
(2)2 個以上的 Redis 實例被平分在 2 套車載設備OBU中,組成 Redis 集群;多個 Redis-Sentinel 實例被平分在 2 套車載設備 OBU 中,組成 Redis-Sentinel 集群,如圖4 中虛線框部分;
(3)Redis 集群數據庫的內部主/從關系由 Sentinel集群表決決定,Redis 集群內部提供主/從數據復制及數據持久化功能;
(4)Redis 集群內的主/從狀態由 Sentinel 集群進行廣播通知,所有集群內部 Redis 實例對系統結構內元素開放,如智能顯示終端(TOD)可根據 OBU 的主備狀態及 Redis 集群的主/從關系,動態設定讀訪問實例及寫訪問實例,實行負載均擔;
(5)在 Redis 集群及應用軟件之間添加集群代理層軟件(Redis-Proxy),集群的任何狀態變化由代理軟件進行收集并實時切換讀寫鏈接,同時代理軟件的功能將實現集群的主/從切換對上層應用程序透明,通過接口實現對Redis數據的讀寫訪問;
(6)2 套系統中任何進程的單點故障都不會導致系統的不穩定,包括智能顯示終端(TOD)、通信接口、單一的 Redis 庫、單一的 Redis-Sentinel 實例等。

圖4 基于 Redis 集群的車載系統結構
自 Redis 問世以來就以其高效的內存訪問速度、靈活的數據形式、可靠的數據存儲及基于 Web 的訪問方式等優點被越來越多的大型互聯網企業所應用[8],如新浪微博建立了史上最大的 Redis 集群,用于數據發布及存儲,說明 Redis 的強大功能已經獲得了互聯網及數據緩存行業的認可。但在城市軌道交通信號領域中,Redis的應用則少之又少,一方面是通信信號領域的安全性要求使然,另一方面則是由長久以來信號領域的技術壟斷造成的。
本文主要結合江蘇省經信委資助項目——“有軌電車運行控制系統關鍵技術研究”的實施,對自主研發的有軌電車車載系統中 Redis 的應用情況進行了簡要描述,證明 Redis 集群在城市軌道交通信號領域的產品研發及應用中是可行的。其實,Redis 功能的強大遠遠超過了文中描述的內容,還需要在實際使用中對 Redis 集群功能進行更加深入的研究與挖掘。
[1]王 如. Redis消息推送機制應用技術研究[J]. 科技廣場,2016(8):41-44.
[2]曾超宇,李金香. Redis在高速緩存系統中的應用[J].微型機與應用,2013,32(12):11-13.
[3]王心 ,毛莉君. 基于Twemproxy的Redis集群解決方案的設計與實現[J]. 電子測試,2016(6):16-17.
[4]賴 . 基于Redis的分布式鎖的實現方案[J]. 信息通信,2016(10):83-84.
[5]明. 高可用可擴展集群化Redis設計與實現[D]. 陜西西安:西安電子科技大學,2014.
[6]余博,賈利民,秦勇,等. 城軌列車視頻數據傳輸系統的設計與實現[J]. 物流技術,2014,33(2):316-319,383.
[7]明瑞利. 有軌電車系統安全性分析[J]. 城市交通,2016(4):59-63,12.
[8]蔣衛中. 軌道交通車載綜合監控系統設計[J]. 都市快軌交通,2012,25(4):116-118,122.
[9]柳 亮,王麗,周陽辰. Redis集群性能測試分析[J].微型機與應用,2016,35(10):70-71,78.