馬 克 王加陽
(中南大學計算機學院 湖南 長沙 410083)
隨著電網運營模式的智能化,逐步實現“智能電網”工程目標[1]及“互聯網+智慧能源”新型思路在電力供給側的重點推進[2],未來可能將有更多的電力設備投入到電網系統中。據統計,截至2017年底,城鄉居民中智能電表的覆蓋率已達99.03%,累計采集用戶約4.47億,新裝智能電表3 748.7萬只。
新形勢下,必將導致電力數據的爆發性增長,電力系統中的電力數據覆蓋設備檢測、電力營銷、電網運行等多個領域,隨著數據增長及業務的擴展,各領域下電力數據的存儲效率及響應能力,將成為整個電力系統運行中至關重要的一環。傳統電力系統主要存在以下三種數據存儲模型。
(1) 關系型數據庫存儲模型。多采用小微型主機作為存儲設備,電力數據全部存放于關系型數據庫中,如Oracle、SQLServer等。該模型部署簡易,運維便捷,在初期,受到諸多電力企業青睞。但是,隨著數據量的增長,格式單一、擴容性差、響應緩慢等問題逐漸暴露。
(2) 單一式非關系型數據庫與關系型數據庫混合存儲模型。引入非關系型數據庫,如Redis、MongoDB等,集中管理部分熱點數據并對其進行緩存處理,另一部分非熱點數據仍然存放于關系型數據庫中。該模型消除了關系型數據中的數據格式單一、響應緩慢等問題。然而,單節點服務器提供的緩存服務在內存容量、可用性、穩固性等方面存在巨大局限。
(3) 分布式非關系型數據與關系型數據庫混合存儲模型。分布式非關系型數據庫能夠將請求數據分布至不同節點,易于實現負載均衡和服務器水平擴展,進而提高響應速度與并發性能。其中典型的代表即Redis集群作為分布式緩存架構,像新浪、GitHub、Pinterest[3]等互聯網公司已投入應用。目前,電力行業也正深入研究并逐步向此模型邁進。
Redis官方在3.0版本后終于提供了集群化方案,但是官方并沒有對此集群方案在實際生產環境中進行充分驗證[4]。在實際生產環境中,Redis集群常會遇到以下問題:動態擴展能力較弱、可視化性能監測缺失、節點狀態切換耗時長等。而且,一旦出現異常情況,運維人員不僅要熟知Redis集群相關架構,還要在組網架構和路由轉發等方面有一定的知識沉淀,對運維人員技能要求高。
針對這種情況,本文基于Codis分布式緩存架構進行研究及應用,描述了整個架構完整的部署方案及核心配置文件,并從電力系統中業務存儲能力、數據檢索效率、性能優良檢測等多角度,對此方案進行深度測試。
基于鍵值對(Key-Value)儲存的非關系型數據庫憑借著靈活的數據模型及高性能的體驗[5],被廣泛應用于互聯網及分布式計算等各個領域。在諸多Key-Value非關系型數據庫中,Redis是應用最廣泛且最具有代表性的方案[6]。
Redis是開源的、高性能的、鍵值對存儲數據的NoSQL數據庫,常常被用于緩存和中間件[7]。相比于其他非關系型數據庫,Redis具有以下特點:
(1) 數據類型豐富。支持字符串(String)、鏈表(List)、普通集合(Set)、有序集合(Sorted Set)、散列(Hash)五大數據類型,輕松應對實際產生環境中的各種數據結構。
(2) 操作命令多樣。每種數據類型都對應著多樣的操作命令,以字符串類型為例,除了常用的set、get命令完成字符數據的存取外,還支持替換字符串setrange、批量設置鍵值對mset、自增存儲數據的長度incrby、指定字符追加數據值append等命令,極大地方便了開發者對數據屬性的管理操作。
(3) 性能體驗極佳。Redis數據存取都是基于內存中完成的,因此不會受到磁盤I/O讀寫速度的限制,讀寫速度高達10萬/s[8],遠遠優于常規的關系型數據庫讀寫速度。
(4) 數據存儲安全。Redis提高了AOF和RDB兩種數據化持久方式[9],允許開發者自定義時間周期,定期地將內存中的數據保存至磁盤中,以確保異常情況時迅速恢復數據集。
(5) 應用范圍廣泛。目前Redis應用于網站訪問量統計、網站在線人數統計、積分排行榜、消息緩存等多個方面。
單節點Redis服務無法提供高并發、大數據服務的特性,因此必須采用Redis集群架構進行彌補。
以官方提供方案中的Redis Cluster架構為例,如圖1所示。Redis Cluster是一個去中心化的結構模型,通過動態擴展多臺主機節點,實現Redis分布式架構。多節點服務器間相互連接,并通過Gossip協議進行廣播消息通信,確保數據之間的同步。對于客戶端,只需任意連接其中一臺節點服務器進行相關讀寫操作,集群便會通過定義配置進行負載均衡,通過路由轉發去請求真正的服務器節點。

圖1 Redis Cluster架構
通過架構圖可知,Redis Cluster部署方案比較單一,集群內部節點耦合度嚴重。一旦業務擴展,需要動態擴展成百上千節點時,部署龐大Redis集群將給運維人員帶來極大困難。同時,數據遷移、繁瑣配置文件、成千上萬行的運維命令,同樣會給運維人員帶來巨大的挑戰。
Codis是由豌豆莢基于Go語言開發的一個分布式Redis集群解決方案,并于2014年11月對外開源。
Codis分布式緩存架構底層將Redis集群按照一定規則進行分組,且每個組內可以自定義主從配置,如圖2所示[10]。Codis架構將Redis節點群進行分組細化,形成多個組群,分解了Redis集群中的整個去中心化網絡結構,簡化了Redis大集群部署的復雜度且降低了大集群管理難度。

圖2 Codis分布式緩存架構
所有的Redis服務組通過codis-proxy代理進行管理,由于codis-proxy代理是無狀態的且無縫銜接Redis協議,因此上層客戶端可以直接通過codis-proxy代理與整個Redis服務組進行對接。當發生讀寫請求的時候,客戶端的操作流程與原生的Redis Server并沒有太大差異。底層的轉發流程關鍵點在于codis-proxy代理,codis-proxy代理會根據請求按照一定的算法進行路由轉發及數據的遷移工作。正是由于codis-proxy代理的出現,使得底層讀寫工作對客戶端相對透明,因此能夠充分利用動態擴展的Redis實例計算能力,從而完成大數據量和高并發的讀寫操作。除此之外,Codis架構還提供了可供選擇的運維便捷、高性能化管理的交互組件,組件如下。
(1) Codis Server。在Codis集群架構中,會采用插槽(slot)的方式來分配數據,默認將slot分為1 024份,開發者可以自行對這1 024份slot進行group分組操作,當客戶端進行存儲的時候,會調用CRC32取模算法,將指定的key映射至對應的節點。redis-server啟動、每部分數據插槽管理及數據遷移的工作都可以交給Codis Server進行處理。
(2) Codis Dashboard。Codis Dashboard負責Codis集群的配置工作,該組件支持開發者通過指定的RESTful接口完成codis-proxy、codis-server的添加及刪除任務。同時,該組件可以通過Redis的哨兵機制確保codis-proxy狀態信息一致性。
(3) Codis FE。利用Codis FE,開發者可以通過可視化Web界面,一鍵式部署Redis服務節點、創建codis-proxy代理節點,甚至可以實時監控整個集群運行的性能狀況。
(4) Codis Admin。利用Codis Admin組件,開發者可以使用命令行工具完成codis-proxy創建、codis-dashboard狀態變更等控制任務。此組件的存在,使得Codis整個架構更加完整,開發者不僅可以通過圖形化界面管理集群,而且還可以使用傳統的命令行工具進行管理操作。
整個Codis架構的部署共涉及5臺服務器進行模擬實際生產環境,各臺服務器的硬件信息如表1所示。

表1 服務器硬件信息
此集群架構每臺服務器節點上所涉及軟件環境為:Go 1.7.1、JDK1.7.0、Codis 3.1、Redis3.2.4、ZooKeeper3.4.9。具體節點部署信息如表2所示。

表2 服務器軟件信息
由于整個Codis分布式緩存架構組件較多,接下來主要描述架構搭建關鍵步驟及部分核心配置,其他非關鍵性配置信息省略。
(1) Go語言及依賴庫的安裝。由于Codis是基于Go語言開發的,因此首先必須確保基礎環境的存在,具體命令如下:
yum install autoconf automake libtool -y
yum install -y gcc glibc gcc-c++ make git
cd $GOPATH/src/github.com/CodisLabs/codis
make
(2) Java環境及ZooKeeper安裝。ZooKeeper核心配置文件zoo.cfg部分配置信息如下:
tickTime=2000
#自定義心跳檢測發送時間
dataDir=/usr/data/zookeeper
#自定義產生數據路徑
server.1=192.168.2.105:2888:3888 #添加主機服務地址
(3) Codis Server安裝與配置。codis-server部署成功后將替代redis-server進行啟動,關鍵配置如下:
#bind 127.0.0.1
#為了安全考慮建議綁定內網IP,防止外網訪問
port 6379
#redis節點監聽端口,生成環境中建議更換為非常用端口
daemonize yes
#開啟守護進程模式
pidfile/usr/local/redis/redis-6380/run/redis_6380.pid
#自定義pid進程文件生成的位置
logfile/usr/local/redis/redis6380/logs/logs_6380.log
#自定義log日志文件生成的位置
dir/usr/local/redis/redis-6380/db
#自定義數據文件生成的位置
requirepass mark-codis
#開啟登錄主機密碼
(4) Codis Dashboard安裝與配置。Dashboard安裝編譯成功后會生成一個dashboard.ini配置文件,需要對此文件進行如下修改:
coordinator_name="zookeeper"
#使用的協調器的名稱,只
#能設置兩個zookeeper、etcd關系的鍵值對
coordinator_addr="192.168.2.105:2181"
#使用的協調器的節點地址
product_name="codis-demo"
#該產品名稱
product_auth="mark-codis"
#該產品的授權秘鑰
admin_addr="0.0.0.0:18080"
#自定義后臺管理路徑的地址和端口
(5) Codis Proxy安裝與配置。codis-proxy安裝編譯成功后會生成一個proxy.ini配置文件,需要對此文件進行如下修改:
product_name="codis-demo"
#該產品名稱
product_auth="mark-codis"
#該產品的授權秘鑰
jodis_name="zookeeper"
#使用的協調器
admin_addr="0.0.0.0:11080"
#連接地址
jodis_addr="192.168.2.105:2181"
#設置zookeeper地址
(6) Codis FE安裝與配置。使用codis-admin提供的相關命令即可快速完成codis-fe的安裝:
/usr/local/codis/bin/codis-admin—dashboard-list—zookeeper=192.168.2.105|tee/usr/local/codis/conf/codis.json
所有組件部署并啟動成功后,在瀏覽器中輸入codis-fe進程運行所在節點的主機地址,即192.168.2.105:18090/#codis-demo,可以發現Codis架構已經正常啟動。Codis架構部署成功后啟動界面如圖3所示。

圖3 Codis架構部署成功部分界面
漏電、過載、短路等電氣異常是火災引發的重要因素[11-12],因此電力系統中通常存在監控子模塊,不間斷采集用電線路中的電壓、電流、諧波、功率等數據,并通過時分秒等時間刻度趨勢圖進行分析預測。這就意味著短時間內電力系統中將要存儲大量電力數據,并且需要在不同時間刻度之間進行快速的數據運算,而這些短時間內電力數據并不需要長期保存,因此可以采用Hash結構存儲電力屬性數據,并根據線路、時間刻度等關鍵信息為基礎設置Key值(electric_線路_秒),具體存儲模型如圖4所示。

圖4 電力線路數據存儲結構
當準備向Codis架構中存儲采集到的電力數據時,首先需要先連接至codis-proxy代理,命令如下:
/home/mark/Cluster/gowork/src/github.com/CodisLabs/codis/extern/redis-3.2.4/src/redis-cli-h 192.168.2.105-a foobared-p 19000
然后通過hset命令向Codis架構中存儲電力數據,當存儲部分電力數據后,試圖分別登錄codis-server01、codis-server02、codis-server03,尋找electric_trunk1_road01對應的Hash值,發現并不是每臺redis服務組上的每個redis節點都儲存著指定的key值數據,實際上這條指定的key對應的鍵值,會經過CRC32的取模算法映射至一臺指定redis節點。這意味著該集群底層可以被無限地擴展,形成一個原則上內存無限大的Redis服務。動態擴展的多節點可以通過自定義規則按照組別劃分,對Redis集群中復雜交錯的網絡拓撲結構進行了解耦,有力地加強對Redis集群的管理。而且Codis架構底層運作原理對于開發者來講又是透明的,開發者只需要像操作原生單節點Redis服務一樣操作Codis架構即可完成數據存儲,這將大大提高電力業務數據的存儲能力與效率。
在電力系統中監控模塊往往存在一些公共的數據信息,如線路坐標信息。這些信息通常不會變更,需要持久保存,但在系統中卻經常去檢索相關線路坐標信息。為了能夠快速地按照建筑、樓層等要素值進行檢索,可以仿照3.1節中涉及的業務存儲模型建立相關的Hash結構儲存。
為了測試Codis架構檢索的速度,設置電力數據請求參數集:不同數量的客戶端并發數,每個客戶端請求均為1 000次,請求數據量大小均為10 000 B,分別在Codis架構和部署了3臺相同硬件配置服務器(共計9個Redis服務節點)的Redis集群上進行測試,測試結果如圖5所示。

圖5 并發響應時間對比
從實驗結果來看,Codis架構雖經過Proxy代理真正Redis服務節點并且配置了多種組件的情況下,性能并不輸于Redis集群,當客戶端并發量超過700個左右時,Codis架構的性能甚至略優于Redis集群;當客戶端并發量達到1 000個時,Codis架構可以在40 ms內檢索到數據,由此可推斷Codis架構可以高速地完成電力數據的檢索工作。
電力系統業務復雜,性能指標不僅僅體現在數據存儲容量、檢索效率方面,數據吞吐能力也是關鍵一環,數據吞吐能力高低直接決定了Codis分布式緩存架構是否能夠應用于電力系統中。
為此,分別設置不同的請求量對Codis分布式緩存架構中操作頻繁的命令進行QPS測試,測試結果如圖6所示。

圖6 Codis架構中頻繁操作命令QPS
測試結果表明,對于產生環境中操作頻繁的命令在多客戶端情況下進行請求,每秒鐘能夠響應的請求次數依舊有著不俗表現,而且在測試期間,后端codis-server平均CPU占用率約為60%~85%,意味著此時Codis架構并非滿負載運行,每臺codis-server服務器仍存在空余空間完成其他操作。與同硬件環境的9臺Redis集群相比,同指令相同請求量下QPS沒有太大差距,Codis架構的數據吞吐能力依舊可以勝任電力系統中緩存數據讀寫的工作。
Redis集群作為緩存架構在電力系統中長期運行,一方面,隨著電網規模的擴張和電力業務的變動,快速地部署更多Redis服務節點是必經之路;另一方面,不可避免地會因為內部代碼Bug、硬件問題或者外部因素出現故障,從而導致整個電力系統運行不穩定。及時地鎖定故障節點并排查故障原因,能夠極大地減少故障處理時間,減少運維人員工作量,進而提高電力系統運行的穩定性。然而,Redis集群關于以上兩點都沒有給出相應的解決方案,但是Codis架構卻提供了圖形化界面,完成新的Redis節點部署與故障節點的定位排查,如圖7所示。

圖7 Codis架構中Redis節點管理可視化界面
本文從電力系統中緩存架構存在的實際問題出發,對Codis分布式緩存架構進行研究,并給出該架構的核心配置步驟及方案,然后對其在電力系統中的業務存儲能力、索引檢索效率、性能優良分析等方面進行實際應用與測試。實驗證明,該架構在數據儲存與索引查詢上具備優異性能,在可視化分析、運維管理角度突出于Redis集群,具有一定的研究與推廣價值。
下一步將繼續結合電力系統中實際應用場景,對Codis分布式緩存架構的高可用、故障轉移方面做進一步的研究。