楊 旭
(中央宣傳部電影數(shù)字節(jié)目管理中心,北京 100866)
隨著互聯(lián)網(wǎng)化的發(fā)展,人們許多行為都從線下走到了線上,以前的現(xiàn)金支付已經(jīng)被線上虛擬支付漸漸取代,人們通過互聯(lián)網(wǎng)就能買到任何東西,小到一瓶飲料大到一輛汽車?;ヂ?lián)網(wǎng)的迅猛發(fā)展,刺激的不只是購物,也促進(jìn)了電影信息的進(jìn)一步發(fā)展,同時也對傳統(tǒng)的互聯(lián)網(wǎng)平臺架構(gòu)設(shè)計提出了挑戰(zhàn)。首先就是訪問和并發(fā)量的考驗,在面對日益增長的訪問量的情況下,傳統(tǒng)的單機(jī)關(guān)系數(shù)據(jù)庫在大批量存儲和數(shù)據(jù)處理能力上存在局限性,容易出現(xiàn)容量和性能瓶頸,分布式存儲架構(gòu)設(shè)計可解決單機(jī)數(shù)據(jù)庫存儲對容量和性能的依賴。
在“互聯(lián)網(wǎng)+”“電影+”理念和思路的大環(huán)境下,對海量影片數(shù)據(jù)信息的分析成為更迫切的需求,這些都會對服務(wù)器的存儲性能提出更高的要求,采用傳統(tǒng)的存儲模式會降低用戶的體驗感和滿意度。分布式存儲是將數(shù)據(jù)分布緩存在多臺獨立的服務(wù)器上,這不同于以往的把所有數(shù)據(jù)放在單獨的存儲服務(wù)器上的方式,分布式存儲解決了傳統(tǒng)單機(jī)存儲服務(wù)器的海量讀寫性能的瓶頸,同時也為數(shù)據(jù)安全性提供了更加可靠的解決方案。
目前分布式存儲應(yīng)用較多的是基于Redis的分布式存儲架構(gòu)。
Redis是一個開源,遵守BSD 協(xié)議,使用ANSI C語言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存,可被用于數(shù)據(jù)緩存、數(shù)據(jù)庫或消息隊列等,并提供多種語言的API支持,是現(xiàn)在最受歡迎的NoSQL 數(shù)據(jù)庫之一 。
Redis的一個重要應(yīng)用是其作為數(shù)據(jù)緩存以加快系統(tǒng)響應(yīng)時間,提高系統(tǒng)吞吐量。例如,當(dāng)有大量用戶訪問時,用戶每次訪問頁面都需要向數(shù)據(jù)庫發(fā)送請求,在很多情況下,從數(shù)據(jù)庫請求的數(shù)據(jù)相對固定,針對這種情況可使用Redis作為緩存,即每次從數(shù)據(jù)庫請求數(shù)據(jù)前,先判斷緩存中是否存在所請求的數(shù)據(jù),如果存在就從緩存中讀取數(shù)據(jù),如果不存在則去請求數(shù)據(jù)庫,并將數(shù)據(jù)加入緩存,這樣大大提高系統(tǒng)訪問效率。
Redis也可以作為一種高級的Key-Value數(shù)據(jù)庫,其中 Value 支持五種數(shù)據(jù)類型:字符串(Strings)類型、字符串列表 (Lists)類型、字符串集合 (Sets)類型、有序字符串集合 (Sorted Sets)類型和哈希(Hashes)類型。
Redis也可用作消息隊列,其隊列List類型可支持阻塞式讀寫,可以很容易地實現(xiàn)一個高性能的優(yōu)先隊列。
基于Redis的分布式存儲架構(gòu),數(shù)據(jù)庫完全在內(nèi)存中,在讀寫速度上相比傳統(tǒng)的單機(jī)架構(gòu)的數(shù)據(jù)訪問具有如下優(yōu)勢:
(1)Redis性能極高,是高性能的Key-Value數(shù)據(jù)庫,Redis存儲讀寫能力可達(dá)10w QPS 每秒。Redis最高可存儲512MB 的鍵值對。而512MB×2=1024MB,即我們將最大獲得1GB的數(shù)據(jù)支撐。
(2)Redis支持多種數(shù)據(jù)類型,常用的數(shù)據(jù)類型有:字符串 (Strings) 類型、字符串列表(Lists)類型、字符串集合(Sets)類型、有序字符串集合(Sorted Sets)類型、哈希(Hashes)類型,pub/sub發(fā)布與訂閱和Transactions事務(wù)幾種。其中哈希機(jī)制在復(fù)雜規(guī)?;臄?shù)據(jù)中廣泛使用,本文利用Redis哈希存儲信息,哈希是一個String類型的Field 和Value 類型的映射表,形如Value=[{Field1,Value},{Field2,Value},… {Fieldn,Value}],其在Redis的哈希類型中以String Field和String Value的map容器存儲,本文利用Redis哈希存儲結(jié)構(gòu)存儲影片信息,文中哈希表的Field值分別對應(yīng)影片編號、影片名、推薦值、影片信息等屬性標(biāo)簽,每一個哈希表最多可以存儲40億個鍵值對,所以該類型符合本文存儲信息的需求。
(3)Redis操作都是原子性的,單個操作原子性,簡化復(fù)雜的用戶業(yè)務(wù)。Redis還具有持久化的特性,使得數(shù)據(jù)能持久地存儲在磁盤上,具備主備模式可以在主庫損壞的時候進(jìn)行及時的切換。
(4)Redis支持多種編程語言的接入方式,具有C、Java、JavaScript、python、ruby 等客戶端API,可方便用戶利用客戶端二次開發(fā),如支持Java的Jedis客戶端的jar包。
(5)Redis支持批量處理數(shù)據(jù),可在短時間內(nèi)插入百萬條數(shù)據(jù),并加載到緩存中。
Redis在頻繁讀取數(shù)據(jù)中能節(jié)省資源,提高速度,主要在以下幾個場景中應(yīng)用:
(1)Counting計數(shù)應(yīng)用
Redis計數(shù)功能是最簡單直觀的模式,利用Redis原子性自增操作記錄用戶的點贊數(shù)、分享數(shù)、收藏數(shù)等,可快速并可節(jié)省開銷。每當(dāng)用戶點擊增加一個計數(shù),利用Key:Value鍵值,key中存儲字符串?dāng)?shù),用incr操作實現(xiàn)對Redis存儲數(shù)據(jù)的原子操作,Redis Incr命令可將key中存儲的數(shù)字值增一。
(2)Cache緩存應(yīng)用
緩存熱點數(shù)據(jù),這也是Redis最典型的應(yīng)用之一,根據(jù)實際情況,緩存用戶信息,緩存Session等;熱點排行榜:即利用Redis排行榜實現(xiàn)最近、最熱、點擊率最高、活躍度最高等條件的top list,完美地解決了數(shù)據(jù)庫全表掃描的效率問題等。
Redis對Cache的應(yīng)用和Memched技術(shù)一樣,對內(nèi)存讀取利用率高,Redis 支持持久化,但是Memched 技術(shù)不支持持久化,Redis可以將內(nèi)存中的數(shù)據(jù)保存到硬盤中,然后重啟之后再讀取數(shù)據(jù)。Redis使用Key-hash結(jié)構(gòu)在緩存應(yīng)用,可以有效壓縮內(nèi)存使用空間,提供內(nèi)存利用率。
(3)熱點和排行的應(yīng)用
傳統(tǒng)的排行使用方式是利用數(shù)據(jù)庫的查詢語句實現(xiàn),例如SQL語句如下所示:
Select*from infotable order by time desc;
在Web開發(fā)過程中,上述利用SQL 語言實現(xiàn)排序查詢的這種用法比較常見,這種方式會帶來每次訪問都需要數(shù)據(jù)庫進(jìn)行排序查詢,其訪問效率低,但這個問題如果在Redis實現(xiàn)起來就迎刃而解。Redis充分使用模板類,用Zrange進(jìn)行數(shù)目限制,每次只保留最新的條數(shù),只有數(shù)據(jù)修改或超出的范圍才會訪問數(shù)據(jù)庫。Redis技術(shù)的使用降低了數(shù)據(jù)和Web交互的頻次,而且在一定程度上解決了讀寫分離的問題,保證了信息的一致性。
隨著互聯(lián)網(wǎng)、媒體融合、大數(shù)據(jù)應(yīng)用的發(fā)展,現(xiàn)在的互聯(lián)網(wǎng)平臺對高性能需求逐漸增加,各大知名互聯(lián)網(wǎng)企業(yè)都在大量使用基于非關(guān)系型數(shù)據(jù)庫(NoSQL)的分布式存儲應(yīng)用。目前包括新浪微博、阿里云、傳媒巨頭Viacom 及Pinterest都在Redis技術(shù)上有重要的應(yīng)用。新浪微博自己擁有史上最大的Redis集群,阿里云提供云數(shù)據(jù)庫Redis數(shù)據(jù)緩存業(yè)務(wù),提供包括集群版、讀寫分離版、容災(zāi)版、混合存儲版等多種定制模式,也是當(dāng)前用戶使用Redis的選擇之一,該技術(shù)的應(yīng)用是在架構(gòu)上對互聯(lián)網(wǎng)類應(yīng)用上很好的補充。
本文把Redis部署在服務(wù)器上,為了保證項目在生產(chǎn)應(yīng)用中的穩(wěn)定使用,配置Redis主備機(jī)。圖1為基于Redis的分布式架構(gòu)部署圖。
圖1 基于Redis的分布式架構(gòu)部署圖
在圖1架構(gòu)部署圖中配置了2臺Redis數(shù)據(jù)庫緩存服務(wù)器,Redis技術(shù)的應(yīng)用可加速數(shù)據(jù)讀取速度,減少數(shù)據(jù)庫的讀寫操作和使用頻次,比如用戶在讀一些基本信息可用Redis數(shù)據(jù)緩存服務(wù)代替數(shù)據(jù)庫查詢功能。當(dāng)用戶新寫入數(shù)據(jù)時,直接訪問數(shù)據(jù)庫并寫入數(shù)據(jù)庫,等數(shù)據(jù)庫數(shù)據(jù)更新完成后再更新Redis服務(wù)器中的緩存數(shù)據(jù),從而保證數(shù)據(jù)的一致性。
以一臺linux服務(wù)器為例配置Redis服務(wù),表1為Redis服務(wù)的安裝環(huán)境:
表1 Redis配置表
(1)安裝編譯環(huán)境
Redis需要依賴一些編譯環(huán)境庫,需安裝編譯環(huán)境以及依賴:gcc gcc-c++make tcl、centos-release-scl、devtoolset-9-gcc devtoolset-9-gcc-c++devtoolset-9-binutils。
(2)編譯安裝Redis
復(fù)制redis-6.0.9.tar.gz 到指定目錄 (如:/root目錄),再解壓縮redis-6.0.9.tar.gz到指定目錄(如:/root目錄),再切換進(jìn)入指定目錄。
編譯并安裝redis-6.0.9,具體指令如下:
make PREFIX=/usr/local/redis install
(3)配置Redis
配置Redis安裝目錄中conf文件及其中bind、logfile、daemonize、protected-mode、dir等參數(shù),在centos下運行redis-server,如圖2所示。
圖2 redis運行結(jié)果圖
Redis主要有四種工作模式:Redis單點、Redis集群、Redis哨兵模式和分片Redis四種模式。
Redis單點模式:在實際生產(chǎn)過程中,單點模式在出現(xiàn)故障風(fēng)險時,如Redis服務(wù)恢復(fù)不及時會對整個系統(tǒng)運行產(chǎn)生重大影響。
Redis集群模式:集群模式是由多個單點Redis組成,任意節(jié)點都是互通的。
Redis哨兵模式:哨兵模式是由一個或多個哨兵實例組成,并對主Master狀態(tài)進(jìn)行監(jiān)控,如遇到Master異常,則會進(jìn)行主從切換,將從機(jī)切換為主機(jī),之前的主機(jī)作為從機(jī)。
分片Redis模式:分片即分區(qū)是分割數(shù)據(jù)到多個Redis,系統(tǒng)共同維護(hù)整個內(nèi)存。
結(jié)合本文應(yīng)用需求及四種模式的應(yīng)用場景和優(yōu)缺點選擇Redis哨兵模式。本文在Redis服務(wù)器上配置了Sentinel模式,需要先配置主機(jī)master的redis.conf配置文件,再配置從機(jī)slave的sentinel.conf配置文件,利用如下命令啟動Sentinel系統(tǒng):
redis-server/path/to/sentinel.conf --sentinel
哨兵模式可以有效的監(jiān)控異常,并具有主備配置,在主機(jī)宕機(jī)時,備機(jī)能即時補充,符合本文應(yīng)用需求。
Redis是開源的,支持C++、Java、Python等多種開發(fā)語言,它的最大優(yōu)勢是讀寫速度快,比較多的應(yīng)用是基于Java 語言開發(fā)的Jedis客戶端API的應(yīng)用。本文使用基于Java語言開發(fā)的Redis接口API,開始在Java中使用Redis 前,需要確保已經(jīng)安裝了redis服務(wù)及Java 的Redis驅(qū)動,具體驅(qū)動包括redis.clients.jedis、redis.clients.jedis.exceptions、redis.clients.util三個Packages,在開發(fā)過程中根據(jù)用戶需要引入不同的Packages。
在本文工程pom.xml文件中配置dependency,加入Jedis客戶端的相關(guān)依賴jedis.2.1.0.jar,其中:group Id配置為redis.clients,artifactId配置為jedis,version配置為2.1.0。
Redis客戶端和服務(wù)端之間的通信協(xié)議是RESP(Redis Senalization Protocol),為實現(xiàn)基于Redis的RESP協(xié)議的客戶端與服務(wù)器端的數(shù)據(jù)交互,本文使用Jedis客戶端API實現(xiàn)與本地的Redis服務(wù)端進(jìn)行數(shù)據(jù)交互,文中配置啟動端口為默認(rèn)端口6379,連接Ip 為192.168.70.102,代碼利用Jedis的incr、decr函數(shù)實現(xiàn)增減操作,set、get函數(shù)實現(xiàn)設(shè)置和獲取操作。
文中為實現(xiàn)Redis分布式存儲,在工程中引入Spring Session,即是把Session 統(tǒng)一存儲在Redis中。在工程pom.xml文件中加入引用Redis依賴,配置dependency屬性,引入啟動器spring-sessiondata-redis.1.3.1.RELEASE,spring-session-dataredis可以實現(xiàn)把session信息存儲到Redis分布式集群中,并可自動裝載Redis Template對象,具體配置為:groupid配置為org.springframework.session,artifactId 配置為spring-session-data-redis,version配置為1.3.1.RELEASE。
(1)數(shù)據(jù)類型的選擇
Jedis支持使用String、List、set、sorted sets等幾種類型,下面是Redis要用到的數(shù)據(jù)結(jié)構(gòu)的不同特點及應(yīng)用場景,如表2所示。
表2 Redis數(shù)據(jù)類型比較
經(jīng)過表2的對比,本文結(jié)合Redis分布式存儲技術(shù),采用sorted sets數(shù)據(jù)類型來存儲用戶喜愛影片的數(shù)據(jù)信息。
(2)影響因素的確定
本文中影響影片推薦功能有幾個重要的影響因素,分別是用戶的喜愛程度和用戶的所在區(qū)域等,通過用戶長時間登錄的所在區(qū)域和喜愛程度兩個變量共同協(xié)作,得出符合用戶需求的推薦影片。
因此設(shè)計Key∶Vaule關(guān)系時,Key值設(shè)為用戶屬性 (即所在區(qū)域值)、Value哈希表為屬性標(biāo)簽,包括影片屬性及喜愛度值等,如圖3所示。
圖3 Key∶Value的哈希關(guān)系結(jié)構(gòu)圖
圖3中,通過Key (用戶屬性)+Filed (屬性標(biāo)簽)就可以組成Key∶Value的哈希關(guān)系結(jié)構(gòu),這樣設(shè)計既不需要存儲大量的重復(fù)數(shù)據(jù),也不會帶來序列化和并發(fā)修改控制的問題,提高了訪問效率,也節(jié)省了開銷。
本文利用Redis分布式存儲技術(shù)實現(xiàn)影片推薦功能,使不同區(qū)域用戶可獲得定制化的推薦影片排行榜,更有針對性地服務(wù)目標(biāo)群體,如圖4所示。
圖4 推薦影片實現(xiàn)結(jié)果圖
測試Redis分布式存儲架構(gòu)和傳統(tǒng)的單機(jī)存儲架構(gòu)在用戶并發(fā)在100、300、500、1000的吞吐率,當(dāng)用戶并發(fā)數(shù)達(dá)到1000時,傳統(tǒng)單機(jī)模式下響應(yīng)時間變長,處理請求能力下降到79req/s,而Redis模式性能保持不變。Redis分布式存儲架構(gòu)在日常高峰期可以瞬間響應(yīng),節(jié)省了訪問數(shù)據(jù)庫的頻次,提升用戶體驗度的同時保證了系統(tǒng)穩(wěn)定性。
在互聯(lián)網(wǎng)、大數(shù)據(jù)、媒體融合快速發(fā)展的今天,提高用戶的滿意度和體驗度是互聯(lián)網(wǎng)平臺的首要和重要的任務(wù),現(xiàn)在判斷一個平臺的好壞不只是能否使用,更要有舒適的體驗度。本文綜合分析了Redis分布式存儲數(shù)據(jù)的應(yīng)用現(xiàn)狀,并通過實踐應(yīng)用驗證了Redis分布式存儲在提高讀寫性能、解決內(nèi)存消耗上的優(yōu)勢。本文根據(jù)Redis的適用場景,搭建主備Redis的分布式存儲架構(gòu),提出一種支持影片推薦的分布式存儲方法,該架構(gòu)實現(xiàn)了利用Redis的分布式存儲的技術(shù),節(jié)省內(nèi)存消耗,提升讀寫速度,大大減少了在影片推薦排行過程中讀寫數(shù)據(jù)庫的壓力,同時也保證了數(shù)據(jù)安全性和一致性。?