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