久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Redis都解決了什么問題

130次閱讀
沒有評論

共計 4304 個字符,預計需要花費 11 分鐘才能閱讀完成。

本篇內容主要講解“Redis 都解決了什么問題”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓丸趣 TV 小編來帶大家學習“Redis 都解決了什么問題”吧!

1、從 0 開始

最初的需求非常簡單,我們有一個提供熱點新聞列表的 api:http://api.xxx.com/hot-news,api 的消費者抱怨說每次請求都要 2 秒左右才能返回結果。

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

如果 api 消費者如果有效的利用了響應中的緩存控制信息,則可以有效的改善其感知的性能(10 分鐘以內)。但是還有 2 個弊端:第一個是在緩存生效的 10 分鐘內,api 消費者可能會得到舊的數據; 第二個是如果 api 的客戶端無視緩存直接訪問 API 依然是需要 2 秒,治標不治本吶。

2、基于本機內存的緩存

為了解決調用 API 依然需要 2 秒的問題,經過排查,其主要原因在于使用 SQL 獲取熱點新聞的過程中消耗了將近 2 秒的時間,于是乎,我們又想到了一個簡單粗暴的解決方案,即把 SQL 查詢的結果直接緩存在當前 api 服務器的內存中(設置緩存有效時間為 1 分鐘)。后續 1 分鐘內的請求直接讀緩存,不再花費 2 秒去執行 SQL 了。

假如這個 api 每秒接收到的請求時 100 個,那么一分鐘就是 6000 個,也就是只有前 2 秒擁擠過來的請求會耗時 2 秒,后續的 58 秒中的所有請求都可以做到即使響應,而無需再等 2 秒的時間。

其他 API 的小伙伴發現這是個好辦法,于是很快我們就發現 API 服務器的內存要爆滿了。。。

3、服務端的 Redis

在 API 服務器的內存都被緩存塞滿的時候,我們發現不得不另想解決方案了。最直接的想法就是我們把這些緩存都丟到一個專門的服務器上吧,把它的內存配置的大大的。然后我們就盯上了 redis。。。至于如何配置部署 redis 這里不解釋了,redis 官方有詳細的介紹。隨后我們就用上了一臺單獨的服務器作為 Redis 的服務器,API 服務器的內存壓力得以解決。

3.1 持久化(Persistence)

單臺的 Redis 服務器一個月總有那么幾天心情不好,心情不好就罷工了,導致所有的緩存都丟失了(redis 的數據是存儲在內存的嘛)。雖然可以把 Redis 服務器重新上線,但是由于內存的數據丟失,造成了緩存雪崩,API 服務器和數據庫的壓力還是一下子就上來了。

所以這個時候 Redis 的持久化功能就派上用場了,可以緩解一下緩存雪崩帶來的影響。redis 的持久化指的是 redis 會把內存的中的數據寫入到硬盤中,在 redis 重新啟動的時候加載這些數據,從而最大限度的降低緩存丟失帶來的影響。

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

Redis 服務器毫無征兆的罷工是個麻煩事。那么怎辦辦? 答曰:備份一臺,你掛了它上。那么如何得知某一臺 redis 服務器掛了,如何切換,如何保證備份的機器是原始服務器的完整備份呢?

這時候就需要 Sentinel 和 Replication 出場了。Sentinel 可以管理多個 Redis 服務器,它提供了監控,提醒以及自動的故障轉移的功能;Replication 則是負責讓一個 Redis 服務器可以配備多個備份的服務器。Redis 也是利用這兩個功能來保證 Redis 的高可用的。此外,Sentinel 功能則是對 Redis 的發布和訂閱功能的一個利用。

3.3 集群(Cluster)

單臺服務器資源的總是有上限的,CPU 資源和 IO 資源我們可以通過主從復制,進行讀寫分離,把一部分 CPU 和 IO 的壓力轉移到從服務器上。但是內存資源怎么辦,主從模式做到的只是相同數據的備份,并不能橫向擴充內存; 單臺機器的內存也只能進行加大處理,但是總有上限的。

所以我們就需要一種解決方案,可以讓我們橫向擴展。最終的目的既是把每臺服務器只負責其中的一部分,讓這些所有的服務器構成一個整體,對外界的消費者而言,這一組分布式的服務器就像是一個集中式的服務器一樣(之前在解讀 REST 的博客中解釋過分布式于基于網絡的差異:基于網絡應用的架構)。

在 Redis 官方的分布式方案出來之前,有 twemproxy 和 codis 兩種方案,這兩個方案總體上來說都是依賴 proxy 來進行分布式的,也就是說 redis 本身并不關心分布式的事情,而是交由 twemproxy 和 codis 來負責。而 redis 官方給出的 cluster 方案則是把分布式的這部分事情做到了每一個 redis 服務器中,使其不再需要其他的組件就可以獨立的完成分布式的要求。

我們這里不關心這些方案的優略,我們關注一下這里的分布式到底是要處理那些事情? 也就是 twemproxy 和 codis 獨立處理的處理分布式的這部分邏輯和 cluster 集成到 redis 服務的這部分邏輯到底在解決什么問題?

如我們前面所說的,一個分布式的服務在外界看來就像是一個集中式的服務一樣。那么要做到這一點就面臨著有一個問題需要解決:既是增加或減少分布式服務中的服務器的數量,對消費這個服務的客戶端而言應該是無感的; 那么也就意味著客戶端不能穿透分布式服務,把自己綁死到某一個臺的服務器上去,因為一旦如此,你就再也無法新增服務器,也無法進行故障替換。

解決這個問題有兩個路子:

第一個路子最直接,那就是我加一個中間層來隔離這種具體的依賴,即 twemproxy 采用的方式,讓所有的客戶端只能通過它來消費 redsi 服務,通過它來隔離這種依賴(但是你會發現 twermproxy 會成為一個單點),這種情況下每臺 redis 服務器都是獨立的,它們之間彼此不知對方的存在;

第二個路子是讓 redis 服務器知道彼此的存在,通過重定向的機制來引導客戶端來完成自己所需要的操作,比如客戶端鏈接到了某一個 redis 服務器,說我要執行這個操作,redis 服務器發現自己無法完成這個操作,那么就把能完成這個操作的服務器的信息給到客戶端,讓客戶端去請求另外的一個服務器,這時候你就會發現每一個 redis 服務器都需要保持一份完整的分布式服務器信息的一份資料,不然它怎么知道讓客戶端去找其他的哪個服務器來執行客戶端想要的操作呢。

上面這一大段解釋了這么多,不知有沒有發現不管是第一個路子還是第二個路子,都有一個共同的東西存在,那就是分布式服務中所有服務器以及其能提供的服務的信息。這些信息無論如何也是要存在的,區別在于第一個路子是把這部分信息單獨來管理,用這些信息來協調后端的多個獨立的 redis 服務器; 第二個路子則是讓每一個 redis 服務器都持有這份信息,彼此知道對方的存在,來達成和第一個路子一樣的目的,優點是不再需要一個額外的組件來處理這部分事情。

Redis Cluster 的具體實現細節則是采用了 Hash 槽的概念,即預先分配出來 16384 個槽:在客戶端通過對 Key 進行 CRC16(key)%  16384 運算得到對應的槽是哪一個; 在 redis 服務端則是每個服務器負責一部分槽,當有新的服務器加入或者移除的時候,再來遷移這些槽以及其對應的數據,同時每個服務器都持有完整的槽和其對應的服務器的信息,這就使得服務器端可以進行對客戶端的請求進行重定向處理。

4、客戶端的 Redis

上面的第三小節主要介紹的是 Redis 服務端的演進步驟,解釋了 Redis 如何從一個單機的服務,進化為一個高可用的、去中心化的、分布式的存儲系統。這一小節則是關注下客戶端可以消費的 redis 服務。

4.1 數據類型

redis 支持豐富的數據類型,從最基礎的 string 到復雜的常用到的數據結構都有支持:

鴻蒙官方戰略合作共建——HarmonyOS 技術社區

string:最基本的數據類型,二進制安全的字符串,最大 512M。

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

set:無序的字符串集合,不存在重復的元素。

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

hash:key-value 對的一種集合。

bitmap:更細化的一種操作,以 bit 為單位。

hyperloglog:基于概率的數據結構。

這些眾多的數據類型,主要是為了支持各種場景的需要,當然每種類型都有不同的時間復雜度。其實這些復雜的數據結構相當于之前我在《解讀 REST》這個系列博客基于網絡應用的架構風格中介紹到的遠程數據訪問 (Remote  Data Access =  RDA) 的具體實現,即通過在服務器上執行一組標準的操作命令,在服務端之間得到想要的縮小后的結果集,從而簡化客戶端的使用,也可以提高網絡性能。比如   如果沒有 list 這種數據結構,你就只能把 list 存成一個 string,客戶端拿到完整的 list,操作后再完整的提交給 redis,會產生很大的浪費。

4.2 事務

上述數據類型中,每一個數據類型都有獨立的命令來進行操作,很多情況下我們需要一次執行不止一個命令,而且需要其同時成功或者失敗。redis 對事務的支持也是源自于這部分需求,即支持一次性按順序執行多個命令的能力,并保證其原子性。

4.3 Lua 腳本

在事務的基礎上,如果我們需要在服務端一次性的執行更復雜的操作 (包含一些邏輯判斷),則 lua 就可以排上用場了(比如在獲取某一個緩存的時候,同時延長其過期時間)。redis 保證 lua 腳本的原子性,一定的場景下,是可以代替 redis 提供的事務相關的命令的。相當于基于網絡應用的架構風格中介紹到的遠程求值(Remote  Evluation = REV) 的具體實現。

4.4 管道

因為 redis 的客戶端和服務器的連接時基于 TCP 的,  默認每次連接都時只能執行一個命令。管道則是允許利用一次連接來處理多條命令,從而可以節省一些 tcp 連接的開銷。管道和事務的差異在于管道是為了節省通信的開銷,但是并不會保證原子性。

4.5 分布式鎖

官方推薦采用 Redlock 算法,即使用 string 類型,加鎖的時候給的一個具體的 key,然后設置一個隨機的值; 取消鎖的時候用使用 lua 腳本來先執行獲取比較,然后再刪除 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 0 end

到此,相信大家對“Redis 都解決了什么問題”有了更深的了解,不妨來實際操作一番吧!這里是丸趣 TV 網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-07-27發表,共計4304字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 苍溪县| 保定市| 屏南县| 紫阳县| 镇安县| 高尔夫| 隆昌县| 建宁县| 磐石市| 黄山市| 崇礼县| 新郑市| 靖宇县| 屏东市| 将乐县| 元阳县| 辽宁省| 南召县| 西昌市| 梅河口市| 安多县| 集安市| 闸北区| 英山县| 渝北区| 山丹县| 哈巴河县| 桑植县| 雷州市| 儋州市| 灌阳县| 襄樊市| 霍邱县| 兰溪市| 东至县| 莫力| 钦州市| 盘锦市| 潮安县| 盱眙县| 屏山县|