<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Redis 的各項(xiàng)功能解決了哪些問(wèn)題?(1024程序員節(jié)快樂(lè))

          共 5717字,需瀏覽 12分鐘

           ·

          2021-10-26 12:42

          ??

          先看一下 Redis 是一個(gè)什么東西。官方簡(jiǎn)介解釋到:
          Redis 是一個(gè)基于 BSD 開(kāi)源的項(xiàng)目,是一個(gè)把結(jié)構(gòu)化的數(shù)據(jù)放在內(nèi)存中的一個(gè)存儲(chǔ)系統(tǒng),你可以把它作為數(shù)據(jù)庫(kù),緩存和消息中間件來(lái)使用。同時(shí)支持 strings,lists,hashes,sets,sorted sets,bitmaps,hyperloglogs 和 geospatial indexes 等數(shù)據(jù)類(lèi)型。它還內(nèi)建了復(fù)制,lua 腳本,LRU,事務(wù)等功能,通過(guò)redis sentinel 實(shí)現(xiàn)高可用,通過(guò) redis cluster 實(shí)現(xiàn)了自動(dòng)分片。以及事務(wù),發(fā)布/訂閱,自動(dòng)故障轉(zhuǎn)移等等。

          綜上所述,Redis 提供了豐富的功能,初次見(jiàn)到可能會(huì)感覺(jué)眼花繚亂,這些功能都是干嘛用的?都解決了什么問(wèn)題?什么情況下才會(huì)用到相應(yīng)的功能?那么下面從零開(kāi)始,一步一步的演進(jìn)來(lái)粗略的解釋下。

          1. 從零開(kāi)始

          最初的需求非常簡(jiǎn)單,我們有一個(gè)提供熱點(diǎn)新聞列表的 api:http://api.xxx.com/hot-news,api 的消費(fèi)者抱怨說(shuō)每次請(qǐng)求都要2秒左右才能返回結(jié)果。

          隨后我們就著手于如何提升一下 api 消費(fèi)者感知的性能,很快最簡(jiǎn)單粗暴的第一個(gè)方案就出來(lái)了:為 API 的響應(yīng)加上基于 HTTP 的緩存控制 cache-control:max-age=600?,即讓消費(fèi)者可以緩存這個(gè)響應(yīng)十分鐘。

          如果 api 消費(fèi)者如果有效的利用了響應(yīng)中的緩存控制信息,則可以有效的改善其感知的性能(10分鐘以內(nèi))。

          但是還有2個(gè)弊端:第一個(gè)是在緩存生效的10分鐘內(nèi),api 消費(fèi)者可能會(huì)得到舊的數(shù)據(jù);第二個(gè)是如果 api 的客戶端無(wú)視緩存直接訪問(wèn) API 依然是需要2秒,治標(biāo)不治本吶。

          2. 基于本機(jī)內(nèi)存的緩存

          為了解決調(diào)用 API 依然需要2秒的問(wèn)題,經(jīng)過(guò)排查,其主要原因在于使用 SQL 獲取熱點(diǎn)新聞的過(guò)程中消耗了將近2秒的時(shí)間,于是乎,我們又想到了一個(gè)簡(jiǎn)單粗暴的解決方案,即把 SQL 查詢的結(jié)果直接緩存在當(dāng)前 api 服務(wù)器的內(nèi)存中(設(shè)置緩存有效時(shí)間為1分鐘)。

          后續(xù)1分鐘內(nèi)的請(qǐng)求直接讀緩存,不再花費(fèi)2秒去執(zhí)行 SQL 了。假如這個(gè) api 每秒接收到的請(qǐng)求是100個(gè),那么一分鐘就是6000個(gè),也就是只有前2秒擁擠過(guò)來(lái)的請(qǐng)求會(huì)耗時(shí)2秒,后續(xù)的58秒中的所有請(qǐng)求都可以做到即使響應(yīng),而無(wú)需再等2秒的時(shí)間。

          其他 API 的小伙伴發(fā)現(xiàn)這是個(gè)好辦法,于是很快我們就發(fā)現(xiàn) API 服務(wù)器的內(nèi)存要爆滿了。。。

          3.?服務(wù)端的 Redis

          在 API 服務(wù)器的內(nèi)存都被緩存塞滿的時(shí)候,我們發(fā)現(xiàn)不得不另想解決方案了。最直接的想法就是我們把這些緩存都丟到一個(gè)專(zhuān)門(mén)的服務(wù)器上吧,把它的內(nèi)存配置的大大的。然后我們就盯上了redis。。。至于如何配置部署 redis 這里不解釋了,redis 官方有詳細(xì)的介紹。

          隨后我們就用上了一臺(tái)單獨(dú)的服務(wù)器作為 Redis 的服務(wù)器,API 服務(wù)器的內(nèi)存壓力得以解決。

          3.1 持久化(Persistence)

          單臺(tái)的 Redis 服務(wù)器一個(gè)月總有那么幾天心情不好,心情不好就罷工了,導(dǎo)致所有的緩存都丟失了(redis 的數(shù)據(jù)是存儲(chǔ)在內(nèi)存的嘛)。

          雖然可以把 Redis 服務(wù)器重新上線,但是由于內(nèi)存的數(shù)據(jù)丟失,造成了緩存雪崩,API 服務(wù)器和數(shù)據(jù)庫(kù)的壓力還是一下子就上來(lái)了。
          所以這個(gè)時(shí)候 Redis 的持久化功能就派上用場(chǎng)了,可以緩解一下緩存雪崩帶來(lái)的影響。

          redis 的持久化指的是 redis 會(huì)把內(nèi)存中的數(shù)據(jù)寫(xiě)入到硬盤(pán)中,在 redis 重新啟動(dòng)的時(shí)候加載這些數(shù)據(jù),從而最大限度的降低緩存丟失帶來(lái)的影響。

          3.2 哨兵(Sentinel)和復(fù)制(Replication)

          Redis 服務(wù)器毫無(wú)征兆的罷工是個(gè)麻煩事。那么怎辦辦?答曰:備份一臺(tái),你掛了它上。

          那么如何得知某一臺(tái) redis 服務(wù)器掛了,如何切換,如何保證備份的機(jī)器是原始服務(wù)器的完整備份呢?這時(shí)候就需要 Sentinel 和 Replication 出場(chǎng)了。

          Sentinel 可以管理多個(gè) Redis 服務(wù)器,它提供了監(jiān)控,提醒以及自動(dòng)的故障轉(zhuǎn)移的功能;Replication 則是負(fù)責(zé)讓一個(gè) Redis 服務(wù)器可以配備多個(gè)備份的服務(wù)器。

          Redis 也是利用這兩個(gè)功能來(lái)保證 Redis 的高可用的。此外,Sentinel 功能則是對(duì) Redis 的發(fā)布和訂閱功能的一個(gè)利用。

          3.3 集群(Cluster)

          單臺(tái)服務(wù)器資源的總是有上限的,CPU 資源和 IO 資源我們可以通過(guò)主從復(fù)制,進(jìn)行讀寫(xiě)分離,把一部分 CPU 和 IO 的壓力轉(zhuǎn)移到從服務(wù)器上。

          但是內(nèi)存資源怎么辦,主從模式做到的只是相同數(shù)據(jù)的備份,并不能橫向擴(kuò)充內(nèi)存;單臺(tái)機(jī)器的內(nèi)存也只能進(jìn)行加大處理,但是總有上限的。

          所以我們就需要一種解決方案,可以讓我們橫向擴(kuò)展。最終的目的既是把每臺(tái)服務(wù)器只負(fù)責(zé)其中的一部分,讓這些所有的服務(wù)器構(gòu)成一個(gè)整體,對(duì)外界的消費(fèi)者而言,這一組分布式的服務(wù)器就像是一個(gè)集中式的服務(wù)器一樣(之前在解讀 REST 的博客中解釋過(guò)分布式于基于網(wǎng)絡(luò)的差異:基于網(wǎng)絡(luò)應(yīng)用的架構(gòu))。

          在 Redis 官方的分布式方案出來(lái)之前,有 twemproxy 和 codis 兩種方案,這兩個(gè)方案總體上來(lái)說(shuō)都是依賴 proxy 來(lái)進(jìn)行分布式的,也就是說(shuō) redis 本身并不關(guān)心分布式的事情,而是交由 twemproxy 和 codis 來(lái)負(fù)責(zé)。

          而 redis 官方給出的 cluster 方案則是把分布式的這部分事情做到了每一個(gè) redis 服務(wù)器中,使其不再需要其他的組件就可以獨(dú)立的完成分布式的要求。

          我們這里不關(guān)心這些方案的優(yōu)略,我們關(guān)注一下這里的分布式到底是要處理哪些事情。也就是 twemproxy 和 codis 獨(dú)立處理的處理分布式的這部分邏輯和 cluster 集成到 redis 服務(wù)的這部分邏輯到底在解決什么問(wèn)題?

          如我們前面所說(shuō)的,一個(gè)分布式的服務(wù)在外界看來(lái)就像是一個(gè)集中式的服務(wù)一樣。

          那么要做到這一點(diǎn)就面臨著有一個(gè)問(wèn)題需要解決:既是增加或減少分布式服務(wù)中的服務(wù)器的數(shù)量,對(duì)消費(fèi)這個(gè)服務(wù)的客戶端而言應(yīng)該是無(wú)感的;那么也就意味著客戶端不能穿透分布式服務(wù),把自己綁死到某一個(gè)臺(tái)的服務(wù)器上去,因?yàn)橐坏┤绱耍憔驮僖矡o(wú)法新增服務(wù)器,也無(wú)法進(jìn)行故障替換。

          解決這個(gè)問(wèn)題有兩個(gè)路子:
          第一個(gè)路子最直接,那就是我加一個(gè)中間層來(lái)隔離這種具體的依賴,即 twemproxy 采用的方式,讓所有的客戶端只能通過(guò)它來(lái)消費(fèi) redis 服務(wù),通過(guò)它來(lái)隔離這種依賴(但是你會(huì)發(fā)現(xiàn) twermproxy 會(huì)成為一個(gè)單點(diǎn)),這種情況下每臺(tái) redis 服務(wù)器都是獨(dú)立的,它們之間彼此不知對(duì)方的存在;

          第二個(gè)路子是讓 redis 服務(wù)器知道彼此的存在,通過(guò)重定向的機(jī)制來(lái)引導(dǎo)客戶端來(lái)完成自己所需要的操作,比如客戶端鏈接到了某一個(gè) redis 服務(wù)器,說(shuō)我要執(zhí)行這個(gè)操作,redis 服務(wù)器發(fā)現(xiàn)自己無(wú)法完成這個(gè)操作,那么就把能完成這個(gè)操作的服務(wù)器的信息給到客戶端,讓客戶端去請(qǐng)求另外的一個(gè)服務(wù)器,這時(shí)候你就會(huì)發(fā)現(xiàn)每一個(gè) redis 服務(wù)器都需要保持一份完整的分布式服務(wù)器信息的一份資料,不然它怎么知道讓客戶端去找其他的哪個(gè)服務(wù)器來(lái)執(zhí)行客戶端想要的操作呢。

          上面這一大段解釋了這么多,不知有沒(méi)有發(fā)現(xiàn)不管是第一個(gè)路子還是第二個(gè)路子,都有一個(gè)共同的東西存在,那就是分布式服務(wù)中所有服務(wù)器以及其能提供的服務(wù)的信息。

          這些信息無(wú)論如何也是要存在的,區(qū)別在于第一個(gè)路子是把這部分信息單獨(dú)來(lái)管理,用這些信息來(lái)協(xié)調(diào)后端的多個(gè)獨(dú)立的 redis 服務(wù)器;第二個(gè)路子則是讓每一個(gè) redis 服務(wù)器都持有這份信息,彼此知道對(duì)方的存在,來(lái)達(dá)成和第一個(gè)路子一樣的目的,優(yōu)點(diǎn)是不再需要一個(gè)額外的組件來(lái)處理這部分事情

          Redis Cluster 的具體實(shí)現(xiàn)細(xì)節(jié)則是采用了 Hash 槽的概念,即預(yù)先分配出來(lái)16384個(gè)槽:在客戶端通過(guò)對(duì) Key 進(jìn)行 CRC16(key)% 16384運(yùn)算得到對(duì)應(yīng)的槽是哪一個(gè);

          在 redis 服務(wù)端則是每個(gè)服務(wù)器負(fù)責(zé)一部分槽,當(dāng)有新的服務(wù)器加入或者移除的時(shí)候,再來(lái)遷移這些槽以及其對(duì)應(yīng)的數(shù)據(jù),同時(shí)每個(gè)服務(wù)器都持有完整的槽和其對(duì)應(yīng)的服務(wù)器的信息,這就使得服務(wù)器端可以進(jìn)行對(duì)客戶端的請(qǐng)求進(jìn)行重定向處理。

          4.?客戶端的 Redis

          上面的第三小節(jié)主要介紹的是 Redis 服務(wù)端的演進(jìn)步驟,解釋了 Redis 如何從一個(gè)單機(jī)的服務(wù),進(jìn)化為一個(gè)高可用的、去中心化的、分布式的存儲(chǔ)系統(tǒng)。這一小節(jié)則是關(guān)注下客戶端可以消費(fèi)的 redis 服務(wù)。

          4.1 數(shù)據(jù)類(lèi)型

          redis 支持豐富的數(shù)據(jù)類(lèi)型,從最基礎(chǔ)的 string 到復(fù)雜的常用到的數(shù)據(jù)結(jié)構(gòu)都有支持:
          1. string:最基本的數(shù)據(jù)類(lèi)型,二進(jìn)制安全的字符串,最大512M。

          2. list:按照添加順序保持順序的字符串列表。

          3. set:無(wú)序的字符串集合,不存在重復(fù)的元素。

          4. sorted set:已排序的字符串集合。

          5. hash:key-value 對(duì)的一種集合。

          6. bitmap:更細(xì)化的一種操作,以 bit 為單位。

          7. hyperloglog:基于概率的數(shù)據(jù)結(jié)構(gòu)。


          這些眾多的數(shù)據(jù)類(lèi)型,主要是為了支持各種場(chǎng)景的需要,當(dāng)然每種類(lèi)型都有不同的時(shí)間復(fù)雜度。

          其實(shí)這些復(fù)雜的數(shù)據(jù)結(jié)構(gòu)相當(dāng)于之前我在《解讀REST》這個(gè)系列博客基于網(wǎng)絡(luò)應(yīng)用的架構(gòu)風(fēng)格中介紹到的遠(yuǎn)程數(shù)據(jù)訪問(wèn)(Remote Data Access = RDA)的具體實(shí)現(xiàn),即通過(guò)在服務(wù)器上執(zhí)行一組標(biāo)準(zhǔn)的操作命令,在服務(wù)端之間得到想要的縮小后的結(jié)果集,從而簡(jiǎn)化客戶端的使用,也可以提高網(wǎng)絡(luò)性能。

          比如如果沒(méi)有 list 這種數(shù)據(jù)結(jié)構(gòu),你就只能把 list 存成一個(gè) string,客戶端拿到完整的 list,操作后再完整的提交給 redis,會(huì)產(chǎn)生很大的浪費(fèi)。

          4.2 事務(wù)

          上述數(shù)據(jù)類(lèi)型中,每一個(gè)數(shù)據(jù)類(lèi)型都有獨(dú)立的命令來(lái)進(jìn)行操作,很多情況下我們需要一次執(zhí)行不止一個(gè)命令,而且需要其同時(shí)成功或者失敗。

          redis 對(duì)事務(wù)的支持也是源自于這部分需求,即支持一次性按順序執(zhí)行多個(gè)命令的能力,并保證其原子性。

          4.3 Lua 腳本

          在事務(wù)的基礎(chǔ)上,如果我們需要在服務(wù)端一次性的執(zhí)行更復(fù)雜的操作(包含一些邏輯判斷),則 lua 就可以派上用場(chǎng)了(比如在獲取某一個(gè)緩存的時(shí)候,同時(shí)延長(zhǎng)其過(guò)期時(shí)間)。

          redis 保證 lua 腳本的原子性,一定的場(chǎng)景下,是可以代替 redis 提供的事務(wù)相關(guān)的命令的。相當(dāng)于基于網(wǎng)絡(luò)應(yīng)用的架構(gòu)風(fēng)格中介紹到的遠(yuǎn)程求值(Remote Evluation = REV)的具體實(shí)現(xiàn)。

          4.4 管道

          因?yàn)?redis 的客戶端和服務(wù)器的連接時(shí)基于 TCP 的, 默認(rèn)每次連接都時(shí)只能執(zhí)行一個(gè)命令。管道則是允許利用一次連接來(lái)處理多條命令,從而可以節(jié)省一些 tcp 連接的開(kāi)銷(xiāo)。管道和事務(wù)的差異在于管道是為了節(jié)省通信的開(kāi)銷(xiāo),但是并不會(huì)保證原子性。

          4.5 分布式鎖

          官方推薦采用 Redlock 算法,即使用 string 類(lèi)型,加鎖的時(shí)候給的一個(gè)具體的 key,然后設(shè)置一個(gè)隨機(jī)的值;取消鎖的時(shí)候用使用 lua 腳本來(lái)先執(zhí)行獲取比較,然后再刪除 key。

          具體的命令如下:
          SET resource_name my_random_value NX PX 30000
          if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1])else return 0end

          總結(jié)

          本篇著重從抽象層面來(lái)解釋下 redis 的各項(xiàng)功能以及其存在的目的,而沒(méi)有關(guān)心其具體的細(xì)節(jié)是什么。從而可以聚焦于其解決的問(wèn)題,依據(jù)抽象層面的概念可以使得我們?cè)谔囟ǖ膱?chǎng)景下選擇更合適的方案,而非局限于其技術(shù)細(xì)節(jié)。

          以上均是筆者個(gè)人的一些理解,如果不當(dāng)之處,歡迎指正。


          參考

          Redis 文檔:https://github.com/antirez/redis-doc
          Redis 簡(jiǎn)介:https://redis.io/topics/introduction
          Redis 持久化(Persistence):https://redis.io/topics/persistence
          Redis 發(fā)布/訂閱(Pub/Sub):https://redis.io/topics/pubsub
          Redis 哨兵(Sentinel):https://redis.io/topics/sentinel
          Redis 復(fù)制(Replication):https://redis.io/topics/replication
          Redis 集群(cluster):https://redis.io/topics/cluster-tutorial
          RedIs 事務(wù)(Transaction):https://redis.io/topics/transactions
          Redis 數(shù)據(jù)類(lèi)型(data types):https://redis.io/topics/data-types-intro
          Redis 分布式鎖:https://redis.io/topics/distlock
          Redis 管道(pipelining ):https://redis.io/topics/pipelining
          Redis Lua Script:https://redis.io/commands/eval
          作者:blackheart
          地址:cnblogs.com/linianhui/p/7792512.html
          猜你喜歡
          深入理解HBase Memstore
          Hadoop 數(shù)據(jù)遷移用法詳解
          Hbase修復(fù)工具Hbck
          數(shù)倉(cāng)建模分層理論
          一文搞懂Hive的數(shù)據(jù)存儲(chǔ)與壓縮
          大數(shù)據(jù)組件重點(diǎn)學(xué)習(xí)這幾個(gè)
          ?

          ?

          瀏覽 39
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  女人荫蒂被添高潮视频 | 亚洲午夜精品视频 | 欧美性xxx88 | 伊人网站| 日日奸日日射日日舔日日干APP |