詹利群,程海林,任曉煒
1(廣西壯族自治區氣象信息中心,南寧 530022)
2(成都信息工程大學,成都 610225)
2016年12月,全國綜合氣象信息共享平臺(簡稱CIMISS)在25個省份正式開始業務化運行,全國氣象部門初步建立了基于CIMISS的國省一致的氣象數據數據環境,各省統一了數據的來源、標準、流程和服務[1,2],形成了良好的業務應用生態.廣西壯族自治區氣象局圍繞CIMISS 統一數據環境開展核心業務系統的集約整合和流程再造,截至2017年底已有26個核心業務系統成功對接CIMISS.隨著越來越多核心業務系統的對接,CIMISS 成為一個數據訪問效率的瓶頸,所有對接的核心業務系統的數據源調用都是通過氣象數據統一服務接口(簡稱MUSIC)[3,4]調用CIMISS 數據.MUSIC 面向氣象業務和科研,提供全國統一、標準、豐富的數據訪問服務和應用編程接口(API),為國、省、地、縣各級應用系統提供唯一權威的數據接入服務.據2017年接口應用統計分析,用戶平均每天訪問接口的次數達到35 萬次以上,實時并發數平均達到每秒50 次以上,接口耗時<1 秒的統計達到97.8%以上,>1 秒以上占據2.2%以上.在這些資料中,逐小時自動氣象站資料具有空間分辨率高、時間間隔短的特點,一直是氣象業務應用中用到最多的幾種資料之一[5],對于開展預報預測、決策服務、災害預警等氣象業務意義重大[6],用戶對該類數據的檢索效率提出了越來越高的要求.傳統的直接從數據庫查詢數據已經滿足不了需求,我們迫切需要找出一種高效查詢逐小時自動氣象站數據的方法,以提高用戶服務效率.
Redis 是一種基于內存運行并支持持久化的NoSQL數據庫,主要解決關系型數據庫高并發情況下數據處理時效問題.因為是純內存操作,Redis 讀寫性能非常出色,每秒可以處理超過10 萬次的讀寫操作[7].
Redis 是開源的高性能Key-Value 存儲引擎,提供多種數據結構.Redis 可以用作緩存,也可以用作存儲[8].支持字符串、鏈表、集合、哈希等多種數據結構以及豐富的編程語言,還可將緩存數據持久化,對數據的更新將異步保存到磁盤上,除此之外,也實現了masterslave(主從)同步,提供集群操作.
1)性能極高
Redis 直接在內存中進行讀取及寫入,他的速度非常的快.讀取速度是110 000 次/s,寫入速度是81 000 次/s .
2)豐富的數據類型
Redis 支持二進制案例的 Strings,Lists,Hashes,Sets 及 Ordered Sets 數據類型操作.
3)原子性操作
Redis的所有操作都是原子性的,同時Redis 還支持對幾個操作全并后的原子性執行.
4)具有豐富的特性
Redis 還支持 publish/subscribe,通知,key 過期等等特性.
Redis 最主要的應用場景之一便是業務緩存,將一些不經常改變但又經常訪問的熱點數據常駐在內存中,并在內存中完成對數據的操作[9],有效地減少數據庫讀取次數,減少數據庫壓力,提高響應時間,增強吞吐量.
對Redis的主要操作便是對其鍵值的存取操作,根據數據結構的不同,提供有非常豐富的操作命令.例如,對字符串和哈希結構的簡單存取命令如下[9,10]:
1)字符串操作
存儲命令:SET key value
查詢命令:GET key
2)哈希(hash)操作
存儲命令:HSET key field value
查詢命令:HGET key field
Redis 還有設置時間過期的功能,通過EXPIRE key seconds 命令完成對鍵key的過期時間設置.
逐小時自動氣象站資料作為氣象業務部門日常觀測的重要資料之一,也是業務應用中用到最多的幾種資料之一.通過分析CIMISS—MUSIC 氣象數據統一服務接口中的資料訪問情況,如圖1所示.
通過分析得出,中國地面逐小時資料是所有資料訪問中訪問次數最多的,平均每天達到10 萬次左右,占據所有資料訪問的三分之一左右.因此,對逐小時自動站資料的檢索查詢效率進行優化提升具有非常大的必要性.
根據CIMISS 數據入庫時間分析地面自動氣象站觀測逐小時資料的到報情況,如圖2所示.

圖1 廣西CIMISS 資料訪問情況分析

圖2 2017年11月20日10時數據到報情況
可以發現,98%以上地面自動站的數據在正點后5 分鐘內已到報,正點十分后數據相對穩定,不經常改變,因此可在正點十分后將相對穩定的數據緩存到Redis 以提升檢索效率.
為了確保Redis 緩存數據與CIMISS 數據的一致性,需要定期的將Redis 數據與CIMISS 進行同步,但如果同步頻率設置太高,如每秒或每分鐘同步一次,則從Redis 獲取數據與從CIMISS 獲取數據無差別,對檢索效率提升不大.如果同步頻率設置太低,如每10 分鐘或每半小時同步一次,緩存中的數據與CIMISS 數據的一致性差異較大.為此,需要分析CIMISS 地面自動氣象站觀測逐小時資料的數據更新規律,選取了廣西2017年的中國地面逐小時資料數據,統計平均每k(k=1,2,3,…,10)分鐘更新次數,結果如圖3所示.

圖3 CIMISS 平均每k 分鐘更新次數
需要選擇一個較高的同步頻率并且在這個頻率期間數據更新盡量少.根據逐小時資料數據的更新規律,可選擇每隔5 分鐘定期同步CIMISS的數據,以此確保緩存數據的準確性.
傳統的關系型數據庫把邏輯模型映射為一系列表來實現,而Redis 作為典型的Key-Value 數據庫沒有表的概念,需要將邏輯關系映射在Key 值中或者一系列的鍵值中[11].在CIMISS 系統中,逐小時自動氣象站資料是基于Oracle 關系數據庫進行存儲的,其檢索接口方式主要包括有按時間、地區等.根據這些業務需求,需要對數據在Redis中的存儲結構進行策略優化設計,Redis 數據庫設計的關鍵在于Key的設計,合理的設計能夠有效提升查詢效率和節省內存的開銷.因此,針對實時查詢的需求,在Redis中的地面自動氣象站逐小時資料,只存儲最近1 小時的數據,并通過設計業務數據庫、索引數據庫和過期時間庫以提升查詢效率和保證有效性.
業務數據是存儲地面自動氣象站逐小時資料數據的庫,包括站名、區站號、市、縣、經度、維度、行政區代碼等基礎信息,并可動態擴展溫度、降水量等觀測要素值.為實現此功能,使用站號作為Key(固定前綴_surf1h_表示逐小時資料),使用哈希結構作為存儲數據的結構.其存儲結構模型如圖4所示.

圖4 逐小時資料業務數據存儲結構
站名、站號等基礎信息作為通用的公共數據,可在Redis 搭建完成后便初始化并長期保存,而在業務調用中,通過哈希結構的HSET 命令來更新要素數據或動態擴展要素,使得業務數據庫能夠支撐存儲地面逐小時資料的所有要素信息.如廣西氣象自動站有2700個站,在Redis 初始化時就可將全部自動站采用站號Key 進行初始化完成,每個Key中的氣象自動站逐小時210個要素字段也可以動態初始化完成,在數據到報后通過jedis.hset("_surf1h_"+站號,"要素",value)的方式進行添加覆蓋數據,從而達到數據的快速存儲操作.
……
Redis>jedis.hset("_surf1h_59431","City","南寧")
Redis>jedis.hset("_surf1h_59431","Cnty","江南區")
Redis>jedis.hset("_surf1h_59431","Lat","22.7833")
Redis>jedis.hset("_surf1h_59431","Lon","108.55")
……
為了實現能夠快速的按照地區、站號等要素值檢索,需要建立地區、要素值與業務數據庫中Key(即站號)的索引關系.檢索數據時,先通過索引庫檢索到符合條件的站號,以站號為Key 到業務數據庫中業務數據.不同的索引方式根據不同的關系操作,采用不同的數據存儲結構.在本文中,主要建立了地區-站號索引庫,用于支持按地區檢索要素.
地區-站號索引庫采用哈希結構,頂級Key 命名為_surf1h_index_area,哈希結構的Key 使用市(縣)名,值為區站號,多個使用逗號分隔,這部分數據經常被訪問但幾乎不會更新,因此在搭建Redis 后即可進行初始化并長期保存.通過在初期建立_surf1h_index_area的Key,將廣西14個地市和每個地市的相對應的區站號建立起來,其存儲結構如圖5所示.

圖5 逐小時資料地區-站號索引庫存儲結構
為保證緩存在業務數據庫中數據與CIMISS中的數據是準確一致的,可以通過設計過期時間庫來確保有效性.過期時間的設定與檢索查詢效率和數據一致性緊密相關,過期時間太短,則會頻繁的查詢CIMISS,效率提升不明顯,過期時間太長,緩存中的數據又與CIMISS 差異較大,不適合業務應用.Redis 本身擁有設置時間過期的功能,即對存儲在Redis 數據庫中的值可以設置一個過期時間.根據對2.2 自動氣象站資料的時間特性進行分析,在正點10 分時開始將較穩定的數據在Redis 進行緩存,并每隔5 分與CIMISS 數據進行一次同步,即Redis中的數據只有在5 分鐘內是有效的,當超出該時間后,過期時間庫中的該要素信息便會被移除,此時即表示業務數據庫該要素的數據已過期.
數據寫入Redis 業務數據庫初期,程序員建立散列類型,通過HSET 命令逐要素寫入.設計過程中又通過HMSET 命令同時設置多個要素字段寫入,程序代碼比之前簡潔.另外,通過要使用Redis 集群存儲資料首先要初始化線程類:
new RedisTestThread("redis"+i,element,admin-Code).start()
將不同的要素、地區數據進行初始化.在線程類中實現將不同的站號進行初始化,根據資料要素的不同站號,通過jedis.hmset(key,dataMap)進行數據設置,其中Key 為"_surf1h_"+站號,dataMap 為站號下對應的業務數據.
最后設置數據過期時間jedis.expire(key,Time).
省、市、縣三級用戶對自動氣象站逐小時數據的查詢主要通過地區行政編碼進行分類查詢,索引庫的建立,可以通過采用地區行政編碼作為地區分類.首先建立所有地區分類的集合,如“450000”代表全廣西,則該索引下的站號為全廣西的自動站站號,“450100”代表南寧市,則“450100”索引下存放整個南寧市的自動站站號.通過循環設置全廣西各區市縣的站號索引.在程序設計上先定義一個HashMap 用來存放行政編碼對應的站號信息,然后通過jedis.hmset(_surf1h_index_area,map)存放業務數據,jedis.expire(_surf1h_index_area,Time)設置過期時間,達到按地區行政編碼優化索引庫提升索引查詢性能.
完成業務數據庫、索引庫及過期時間庫存儲設計后,開始通過程序將逐小時自動氣象站資料及相關的輔助信息存入庫中,資料查詢流程如圖6所示.

圖6 基于Redis的逐小時資料檢索查詢流程
主要包括以下三種情況:
1)請求時間在正點后十分鐘內
根據自動氣象站觀測規范,自動氣象站觀測數據在正點觀測后,數據立即從分布在全區各個觀測站發回觀測數據文件.通常正點后的2-4 分鐘是地面逐小時觀測數據入庫的高峰期,在這個時間內數據解碼入庫的更新頻度非常高,將數據緩存到Redis中沒有意義,因此這個時間內的數據請求均是通過接口直接訪問CIMISS 獲取數據并返回.
2)請求時間在正點十分后,Redis 緩存數據已過期
此時CIMISS中數據相對穩定,但Redis中緩存數據已過期,因此需要重新訪問CIMISS 以獲取最新有效數據,獲取數據后更新業務數據庫中相應要素的值,同時重新設置該要素的過期時間,如設置為5 分鐘,最后返回數據.
3)請求時間在正點十分后,Redis 緩存數據未過期
此時緩存在Redis中的數據為有效數據,首先通過查詢條件,在索引庫中進行相應的關系查詢篩選出符合條件的站點數據,然后通過站號從業務數據庫中檢索數據并返回.
在程序設計上使用jedis.hget(areaIndexKey,admin-Code),根據地區行政編碼進行數據分類獲取站號索引,得到該地區的所有站點,再通過循環站點獲取業務數據:

通過上述代碼可查詢得到相應的業務數據
1)搭建Redis 集群
使用Redis 集群不僅可以擴大緩存數據量,也能通過主從復制機制避免單節點故障導致無法繼續工作.在本文中,搭建3 臺服務器6個節點的Redis 集群,部署環境如表1所示.

表1 Redis 集群配置
2)建立模擬訪問
使用Jedis(Redis的Java 版本的客戶端實現)實現對Redis 集群的操作[12],編寫Java 程序執行訪問請求,使用多線程等技術,模擬實現對CIMISS 以及對Redis的檢索查詢操作.
選取地面中中國地面逐小時資料進行試驗分析,并選取了2018年11月26~30日每天上午7-10時和下午17-22時(業務高峰期)對實時數據(1 小時內)進行緩存.資料包括站號、站名、溫度、降水等210個要素,如表2所示.

表2 中國地面逐小時資料數據結構
為實現對基于Redis的逐小時自動氣象站資料存儲的查詢效率進行分析,設計兩組實驗模擬訪問最近一小時的逐小時自動氣象站資料,實驗周期為2018年11月26~30日每天上午7-10時和下午17-22時,訪問頻率為每隔一分鐘進行一次請求,實驗詳細設計如表3所示.

表3 實驗組設計
實驗選擇檢索南寧市最近一小時降雨量為例,通過記錄每次開始執行訪問至獲取到數據時的時間差(即執行一次檢索數據的耗時,時間單位為ms)作為實驗結果.
1)查詢效率分析
因正點后前十分CIMISS 組合Redis 組均是直接訪問CIMISS 接口,效率一致,不必分析.選擇在正點十分后模擬基于Redis 和CIMISS的數據查詢,每分鐘調用一次查詢,分別記錄每次查詢耗時,結果如圖7所示.
可以看出,在正點十分后,直接從CIMISS 查詢的耗時總體在500 ms 左右,而Redis的查詢耗時大多數時候在100 ms 左右,每隔5 分鐘因需從CIMISS 進行數據同步而耗時在500 ms 左右.從Redis 查詢平均耗時0.2 秒左右,CIMISS 組平均耗時0.5 秒左右,前者具有更高的查詢效率,是后者的兩倍以上.

圖7 基于Redis 與CIMISS 查詢耗時對比
2)數據一致性分析
緩存中的數據包括中國地面逐小時資料共210個要素,為確保數據的準備,通過對比2018年11月26~30日每天上午7-10時和下午17-22時每分鐘從Redis 取出的要素值與CIMISS中的要素值,記錄值相同的要素個數,實驗期間平均結果如圖8所示.

圖8 Redis 與CIMISS 數據值相同的要素個數統計圖
通過分析,中國地面逐小時資料共210個要素在1 小時內緩存數據與CIMISS 數據的一致性達到了99%以上,能確保數據的完整性,滿足業務應用要求.
本文利用Redis 是開源的高性能Key-Value 存儲引擎,提供多種數據結構利用Redis 開源高效內存數據庫的特點,結合地面自動氣象站逐小時資料在實際業務中的應用,通過Redis 數據庫結構模型設計和優化、并通過實驗對Redis 提高了逐小時自動氣象站資料的檢索效率和數據一致性進行驗證,為用戶在不同氣象資料查詢檢索方面提供了一套可操作的技術參考樣例.由于自動氣象站觀測資料更正報等實際情況,可能導致緩存在Redis中的數據的及時性和一致性降低,這方面可以考慮采用基于消息的機制更新緩存數據或縮短緩存時間等來這個解決問題.在氣象業務中,還存在很多對查詢要求較高的觀測資料,本文提出的逐小時地面自動站資料數據結構模型并通過Redis 進行緩存能有效的提升檢索效率,并可以應用到其它資料的檢索調用業務場景中,具有較好的推廣應用價值.