楊 旭
(中央宣傳部電影數字節目管理中心,北京 100866)
隨著互聯網化的發展,人們許多行為都從線下走到了線上,以前的現金支付已經被線上虛擬支付漸漸取代,人們通過互聯網就能買到任何東西,小到一瓶飲料大到一輛汽車。互聯網的迅猛發展,刺激的不只是購物,也促進了電影信息的進一步發展,同時也對傳統的互聯網平臺架構設計提出了挑戰。首先就是訪問和并發量的考驗,在面對日益增長的訪問量的情況下,傳統的單機關系數據庫在大批量存儲和數據處理能力上存在局限性,容易出現容量和性能瓶頸,分布式存儲架構設計可解決單機數據庫存儲對容量和性能的依賴。
在“互聯網+”“電影+”理念和思路的大環境下,對海量影片數據信息的分析成為更迫切的需求,這些都會對服務器的存儲性能提出更高的要求,采用傳統的存儲模式會降低用戶的體驗感和滿意度。分布式存儲是將數據分布緩存在多臺獨立的服務器上,這不同于以往的把所有數據放在單獨的存儲服務器上的方式,分布式存儲解決了傳統單機存儲服務器的海量讀寫性能的瓶頸,同時也為數據安全性提供了更加可靠的解決方案。
目前分布式存儲應用較多的是基于Redis的分布式存儲架構。
Redis是一個開源,遵守BSD 協議,使用ANSI C語言編寫、支持網絡、可基于內存,可被用于數據緩存、數據庫或消息隊列等,并提供多種語言的API支持,是現在最受歡迎的NoSQL 數據庫之一 。
Redis的一個重要應用是其作為數據緩存以加快系統響應時間,提高系統吞吐量。例如,當有大量用戶訪問時,用戶每次訪問頁面都需要向數據庫發送請求,在很多情況下,從數據庫請求的數據相對固定,針對這種情況可使用Redis作為緩存,即每次從數據庫請求數據前,先判斷緩存中是否存在所請求的數據,如果存在就從緩存中讀取數據,如果不存在則去請求數據庫,并將數據加入緩存,這樣大大提高系統訪問效率。
Redis也可以作為一種高級的Key-Value數據庫,其中 Value 支持五種數據類型:字符串(Strings)類型、字符串列表 (Lists)類型、字符串集合 (Sets)類型、有序字符串集合 (Sorted Sets)類型和哈希(Hashes)類型。
Redis也可用作消息隊列,其隊列List類型可支持阻塞式讀寫,可以很容易地實現一個高性能的優先隊列。
基于Redis的分布式存儲架構,數據庫完全在內存中,在讀寫速度上相比傳統的單機架構的數據訪問具有如下優勢:
(1)Redis性能極高,是高性能的Key-Value數據庫,Redis存儲讀寫能力可達10w QPS 每秒。Redis最高可存儲512MB 的鍵值對。而512MB×2=1024MB,即我們將最大獲得1GB的數據支撐。
(2)Redis支持多種數據類型,常用的數據類型有:字符串 (Strings) 類型、字符串列表(Lists)類型、字符串集合(Sets)類型、有序字符串集合(Sorted Sets)類型、哈希(Hashes)類型,pub/sub發布與訂閱和Transactions事務幾種。其中哈希機制在復雜規模化的數據中廣泛使用,本文利用Redis哈希存儲信息,哈希是一個String類型的Field 和Value 類型的映射表,形如Value=[{Field1,Value},{Field2,Value},… {Fieldn,Value}],其在Redis的哈希類型中以String Field和String Value的map容器存儲,本文利用Redis哈希存儲結構存儲影片信息,文中哈希表的Field值分別對應影片編號、影片名、推薦值、影片信息等屬性標簽,每一個哈希表最多可以存儲40億個鍵值對,所以該類型符合本文存儲信息的需求。
(3)Redis操作都是原子性的,單個操作原子性,簡化復雜的用戶業務。Redis還具有持久化的特性,使得數據能持久地存儲在磁盤上,具備主備模式可以在主庫損壞的時候進行及時的切換。
(4)Redis支持多種編程語言的接入方式,具有C、Java、JavaScript、python、ruby 等客戶端API,可方便用戶利用客戶端二次開發,如支持Java的Jedis客戶端的jar包。
(5)Redis支持批量處理數據,可在短時間內插入百萬條數據,并加載到緩存中。
Redis在頻繁讀取數據中能節省資源,提高速度,主要在以下幾個場景中應用:
(1)Counting計數應用
Redis計數功能是最簡單直觀的模式,利用Redis原子性自增操作記錄用戶的點贊數、分享數、收藏數等,可快速并可節省開銷。每當用戶點擊增加一個計數,利用Key:Value鍵值,key中存儲字符串數,用incr操作實現對Redis存儲數據的原子操作,Redis Incr命令可將key中存儲的數字值增一。
(2)Cache緩存應用
緩存熱點數據,這也是Redis最典型的應用之一,根據實際情況,緩存用戶信息,緩存Session等;熱點排行榜:即利用Redis排行榜實現最近、最熱、點擊率最高、活躍度最高等條件的top list,完美地解決了數據庫全表掃描的效率問題等。
Redis對Cache的應用和Memched技術一樣,對內存讀取利用率高,Redis 支持持久化,但是Memched 技術不支持持久化,Redis可以將內存中的數據保存到硬盤中,然后重啟之后再讀取數據。Redis使用Key-hash結構在緩存應用,可以有效壓縮內存使用空間,提供內存利用率。
(3)熱點和排行的應用
傳統的排行使用方式是利用數據庫的查詢語句實現,例如SQL語句如下所示:
Select*from infotable order by time desc;
在Web開發過程中,上述利用SQL 語言實現排序查詢的這種用法比較常見,這種方式會帶來每次訪問都需要數據庫進行排序查詢,其訪問效率低,但這個問題如果在Redis實現起來就迎刃而解。Redis充分使用模板類,用Zrange進行數目限制,每次只保留最新的條數,只有數據修改或超出的范圍才會訪問數據庫。Redis技術的使用降低了數據和Web交互的頻次,而且在一定程度上解決了讀寫分離的問題,保證了信息的一致性。
隨著互聯網、媒體融合、大數據應用的發展,現在的互聯網平臺對高性能需求逐漸增加,各大知名互聯網企業都在大量使用基于非關系型數據庫(NoSQL)的分布式存儲應用。目前包括新浪微博、阿里云、傳媒巨頭Viacom 及Pinterest都在Redis技術上有重要的應用。新浪微博自己擁有史上最大的Redis集群,阿里云提供云數據庫Redis數據緩存業務,提供包括集群版、讀寫分離版、容災版、混合存儲版等多種定制模式,也是當前用戶使用Redis的選擇之一,該技術的應用是在架構上對互聯網類應用上很好的補充。
本文把Redis部署在服務器上,為了保證項目在生產應用中的穩定使用,配置Redis主備機。圖1為基于Redis的分布式架構部署圖。

圖1 基于Redis的分布式架構部署圖
在圖1架構部署圖中配置了2臺Redis數據庫緩存服務器,Redis技術的應用可加速數據讀取速度,減少數據庫的讀寫操作和使用頻次,比如用戶在讀一些基本信息可用Redis數據緩存服務代替數據庫查詢功能。當用戶新寫入數據時,直接訪問數據庫并寫入數據庫,等數據庫數據更新完成后再更新Redis服務器中的緩存數據,從而保證數據的一致性。
以一臺linux服務器為例配置Redis服務,表1為Redis服務的安裝環境:

表1 Redis配置表
(1)安裝編譯環境
Redis需要依賴一些編譯環境庫,需安裝編譯環境以及依賴:gcc gcc-c++make tcl、centos-release-scl、devtoolset-9-gcc devtoolset-9-gcc-c++devtoolset-9-binutils。
(2)編譯安裝Redis
復制redis-6.0.9.tar.gz 到指定目錄 (如:/root目錄),再解壓縮redis-6.0.9.tar.gz到指定目錄(如:/root目錄),再切換進入指定目錄。
編譯并安裝redis-6.0.9,具體指令如下:
make PREFIX=/usr/local/redis install
(3)配置Redis
配置Redis安裝目錄中conf文件及其中bind、logfile、daemonize、protected-mode、dir等參數,在centos下運行redis-server,如圖2所示。

圖2 redis運行結果圖
Redis主要有四種工作模式:Redis單點、Redis集群、Redis哨兵模式和分片Redis四種模式。
Redis單點模式:在實際生產過程中,單點模式在出現故障風險時,如Redis服務恢復不及時會對整個系統運行產生重大影響。
Redis集群模式:集群模式是由多個單點Redis組成,任意節點都是互通的。
Redis哨兵模式:哨兵模式是由一個或多個哨兵實例組成,并對主Master狀態進行監控,如遇到Master異常,則會進行主從切換,將從機切換為主機,之前的主機作為從機。
分片Redis模式:分片即分區是分割數據到多個Redis,系統共同維護整個內存。
結合本文應用需求及四種模式的應用場景和優缺點選擇Redis哨兵模式。本文在Redis服務器上配置了Sentinel模式,需要先配置主機master的redis.conf配置文件,再配置從機slave的sentinel.conf配置文件,利用如下命令啟動Sentinel系統:
redis-server/path/to/sentinel.conf --sentinel
哨兵模式可以有效的監控異常,并具有主備配置,在主機宕機時,備機能即時補充,符合本文應用需求。
Redis是開源的,支持C++、Java、Python等多種開發語言,它的最大優勢是讀寫速度快,比較多的應用是基于Java 語言開發的Jedis客戶端API的應用。本文使用基于Java語言開發的Redis接口API,開始在Java中使用Redis 前,需要確保已經安裝了redis服務及Java 的Redis驅動,具體驅動包括redis.clients.jedis、redis.clients.jedis.exceptions、redis.clients.util三個Packages,在開發過程中根據用戶需要引入不同的Packages。
在本文工程pom.xml文件中配置dependency,加入Jedis客戶端的相關依賴jedis.2.1.0.jar,其中:group Id配置為redis.clients,artifactId配置為jedis,version配置為2.1.0。
Redis客戶端和服務端之間的通信協議是RESP(Redis Senalization Protocol),為實現基于Redis的RESP協議的客戶端與服務器端的數據交互,本文使用Jedis客戶端API實現與本地的Redis服務端進行數據交互,文中配置啟動端口為默認端口6379,連接Ip 為192.168.70.102,代碼利用Jedis的incr、decr函數實現增減操作,set、get函數實現設置和獲取操作。
文中為實現Redis分布式存儲,在工程中引入Spring Session,即是把Session 統一存儲在Redis中。在工程pom.xml文件中加入引用Redis依賴,配置dependency屬性,引入啟動器spring-sessiondata-redis.1.3.1.RELEASE,spring-session-dataredis可以實現把session信息存儲到Redis分布式集群中,并可自動裝載Redis Template對象,具體配置為:groupid配置為org.springframework.session,artifactId 配置為spring-session-data-redis,version配置為1.3.1.RELEASE。
(1)數據類型的選擇
Jedis支持使用String、List、set、sorted sets等幾種類型,下面是Redis要用到的數據結構的不同特點及應用場景,如表2所示。

表2 Redis數據類型比較
經過表2的對比,本文結合Redis分布式存儲技術,采用sorted sets數據類型來存儲用戶喜愛影片的數據信息。
(2)影響因素的確定
本文中影響影片推薦功能有幾個重要的影響因素,分別是用戶的喜愛程度和用戶的所在區域等,通過用戶長時間登錄的所在區域和喜愛程度兩個變量共同協作,得出符合用戶需求的推薦影片。
因此設計Key∶Vaule關系時,Key值設為用戶屬性 (即所在區域值)、Value哈希表為屬性標簽,包括影片屬性及喜愛度值等,如圖3所示。

圖3 Key∶Value的哈希關系結構圖
圖3中,通過Key (用戶屬性)+Filed (屬性標簽)就可以組成Key∶Value的哈希關系結構,這樣設計既不需要存儲大量的重復數據,也不會帶來序列化和并發修改控制的問題,提高了訪問效率,也節省了開銷。
本文利用Redis分布式存儲技術實現影片推薦功能,使不同區域用戶可獲得定制化的推薦影片排行榜,更有針對性地服務目標群體,如圖4所示。

圖4 推薦影片實現結果圖
測試Redis分布式存儲架構和傳統的單機存儲架構在用戶并發在100、300、500、1000的吞吐率,當用戶并發數達到1000時,傳統單機模式下響應時間變長,處理請求能力下降到79req/s,而Redis模式性能保持不變。Redis分布式存儲架構在日常高峰期可以瞬間響應,節省了訪問數據庫的頻次,提升用戶體驗度的同時保證了系統穩定性。
在互聯網、大數據、媒體融合快速發展的今天,提高用戶的滿意度和體驗度是互聯網平臺的首要和重要的任務,現在判斷一個平臺的好壞不只是能否使用,更要有舒適的體驗度。本文綜合分析了Redis分布式存儲數據的應用現狀,并通過實踐應用驗證了Redis分布式存儲在提高讀寫性能、解決內存消耗上的優勢。本文根據Redis的適用場景,搭建主備Redis的分布式存儲架構,提出一種支持影片推薦的分布式存儲方法,該架構實現了利用Redis的分布式存儲的技術,節省內存消耗,提升讀寫速度,大大減少了在影片推薦排行過程中讀寫數據庫的壓力,同時也保證了數據安全性和一致性。?