查看網(wǎng)站開發(fā)語言aso優(yōu)化什么意思
目錄
List 編碼方式
早期版本
現(xiàn)今版本
List 實(shí)際應(yīng)用
多表之間的關(guān)聯(lián)關(guān)系
消息隊(duì)列
頻道(多列表)消息隊(duì)列
微博 Timeline
棧 & 隊(duì)列
List 編碼方式
早期版本
- 早期版本 List 類型的內(nèi)部編碼方式有兩種
- ziplist(壓縮列表)
- linkedlist(鏈表)
- 兩個(gè)配置項(xiàng)
- list-max-ziplist-entries 配置
- list-max-ziplist-value 配置
注意:
- 現(xiàn)版本?Redis 已不再使用這兩個(gè)配置項(xiàng)
- 且上述的 兩種編碼方式 為早期版本 Reids 中的 List 類型內(nèi)部編碼方式
現(xiàn)今版本
- 現(xiàn)今版本 Redis 使用 quicklist 作為 List 類型的內(nèi)部編碼方式
- quicklist 相當(dāng)于?ziplist 和 linkedlist 的結(jié)合
- quicklist 整體上還是一個(gè) linkedlist ,但 linkedlist 的每個(gè)節(jié)點(diǎn)均為一個(gè) ziplist
特點(diǎn):
- 每個(gè)節(jié)點(diǎn)上的 ziplist 不會(huì)太大,且這多個(gè) ziplist 通過鏈?zhǔn)浇Y(jié)構(gòu)鏈接起來
配置項(xiàng):
- 該配置項(xiàng)描述了每個(gè)節(jié)點(diǎn) ziplist 的閾值
- 當(dāng) ziplist 滿足閾值,便將其分裂成多個(gè)列表節(jié)點(diǎn),即多個(gè) ziplist?
- 再將這多個(gè) ziplist 通過鏈?zhǔn)浇Y(jié)構(gòu)鏈接起來
注意:
- 觀察上圖注釋信息,ziplist 的閾值為可選項(xiàng)
- 所以我們還需針對(duì)當(dāng)前業(yè)務(wù)場景,來選擇合適的閾值!
實(shí)例理解
- 我們通過?object encoding key?來查看編碼方式
List 實(shí)際應(yīng)用
多表之間的關(guān)聯(lián)關(guān)系
- 可將?list 作為 數(shù)組 這樣的結(jié)構(gòu)來存儲(chǔ)多個(gè)元素
實(shí)例理解
- 使用 MySQL 表示學(xué)生和班級(jí)信息
- 上圖?MySQL 表結(jié)構(gòu) 可以很方便的實(shí)現(xiàn) 查詢指定班級(jí)中有哪些同學(xué)
- Redis 所提供的查詢功能 是不如 MySQL 的
- 所以我們可以通過往 Redis 中插入 List 類型鍵值對(duì)直接將 學(xué)生 和 班級(jí)信息 進(jìn)行關(guān)聯(lián)
- 結(jié)合上圖實(shí)例,Redis 通過 List 類型 便可以將 學(xué)生 和 班級(jí)信息 關(guān)聯(lián)起來
- 從而能很輕易的實(shí)現(xiàn)?查詢指定班級(jí)中有哪些同學(xué)
注意:
- 此處除了使用 Hash 類型表示學(xué)生信息,也可使用 String + JSON 的方式來表示學(xué)生信息
- 即 具體 Redis 中的數(shù)據(jù)是如何組織的,都需根據(jù)實(shí)際的業(yè)務(wù)情況來決定
消息隊(duì)列
- 生產(chǎn)者消費(fèi)者模型
- 上圖的 brpop 為阻塞操作
- 當(dāng)列表為空時(shí),brpop 命令便會(huì)阻塞等待,一直等到其他客戶端向列表中 lpush 元素為止
重點(diǎn)理解:
- 此處?只有一個(gè)消費(fèi)者能搶到元素
通俗理解:
- 誰先執(zhí)行的?brpop 命令,誰就能拿到這個(gè)新 lpush 的元素
- 該設(shè)定便能很好的構(gòu)成?"輪詢"?效果
實(shí)例理解
- 假設(shè)此時(shí)列表為空,三個(gè)消費(fèi)者(A、B、C)按順序執(zhí)行 brpop 命令進(jìn)行阻塞等待
- 即執(zhí)行順序?yàn)?消費(fèi)者A ——>?消費(fèi)者B ——> 消費(fèi)者C
- 當(dāng)有新元素到達(dá)列表時(shí),該新元素將被 消費(fèi)者A 獲取,且 brpop 命令立即返回,標(biāo)志著 消費(fèi)者A?完成了一次消費(fèi)操作
- 若消費(fèi)者A 想要繼續(xù)消費(fèi),必須再次執(zhí)行 brpop 命令
- 此時(shí)執(zhí)行順序變?yōu)?/strong>?消費(fèi)者B?——> 消費(fèi)者C?——> 消費(fèi)者A
- 如果再有新元素到達(dá),消費(fèi)者B 將獲取該元素,且 brpop 命令立即返回,標(biāo)志著 消費(fèi)者 B 完成了一次消費(fèi)操作
總結(jié):
- 上述實(shí)例所描述的這種輪詢方式,即消費(fèi)者們按照固定的順序交替執(zhí)行 brpop 命令
- 很好的實(shí)現(xiàn)了對(duì)阻塞隊(duì)列的有序消費(fèi)
頻道(多列表)消息隊(duì)列
- 多列表/頻道 這種場景是比較常見的
實(shí)例理解
- 日常使用的程序,比如抖音
- 一個(gè)頻道 用來傳輸短視頻數(shù)據(jù)
- 一個(gè)頻道 用來傳輸彈幕
- 還可以有多個(gè)頻道,用來傳輸點(diǎn)贊、轉(zhuǎn)發(fā)、收藏、評(píng)論數(shù)據(jù)
優(yōu)點(diǎn):
- 多頻道模式 一定程度上保證了在某種數(shù)據(jù)發(fā)生問題的時(shí)候,不會(huì)對(duì)其他數(shù)據(jù)造成影響
- 具有一定的 解耦合 作用
微博 Timeline
- 每個(gè)用戶都擁有屬于自己的 Timeline(微博列表),現(xiàn)需要分頁展示文章列表
- 此時(shí)便可以考慮使用列表,因?yàn)榱斜聿坏怯行虻?#xff0c;且支持按照索引范圍獲取元素
實(shí)例理解
- 每篇微博使用 哈希結(jié)構(gòu)存儲(chǔ)
- 此處包含三個(gè)屬性(title、timestamp、content)
hmset mblog:1 title xx timestamp 1476536196 content xxxxx ... hmset mblog:n title xx timestamp 1476536196 content xxxxx
- 向用戶 Timeline 添加微博,使用 List 類型
- 此處使用 user:<uid>:mblogs 作為微博的鍵
lpush user:1:mblogs mblog:2 mblog:4 ... lpush user:k:mblogs mblog:n
- 分頁獲取用戶的 Timeline
- 此處假設(shè)獲取用戶1 的前 5 篇微博
keylist = lrange user:1:mblogs 0 4 for key in keylist {hgetall key }
問題一:
- 當(dāng)前一頁中有多少數(shù)據(jù)是不確定,所以有可能會(huì)導(dǎo)致 for 循環(huán)比較大
- 從而會(huì)觸發(fā)多次 hgetall 命令,即多次?網(wǎng)絡(luò)請(qǐng)求
解決方法:
- 使用 pipeline(流水線、管道)
- 雖然此處是多個(gè) Redis 命令,但是通過 pipeline 我們可以將這些命令合并成一個(gè) 網(wǎng)絡(luò)請(qǐng)求 進(jìn)行通信
- 由此可以大大降低 客戶端 和 服務(wù)器 之間的交互次數(shù)
問題二:
- lrange 在列表兩端表現(xiàn)較好,獲取列表中間的元素表現(xiàn)較差
解決方案:
- 將文章對(duì)應(yīng)的 list 進(jìn)行切分
- 假設(shè)某用戶發(fā)布了?1w 篇微博,則 list 的長度為?1w
- 如果將這 1w 篇微博拆分成 10 份,即 每份1k 篇微博
- 此時(shí)如果想獲取第 5k 篇左右的微博
- 即直接找到第五個(gè)列表,進(jìn)行遍歷即可
- 通過這樣的拆分方式便能降低單個(gè) list 的長度,并加快中間位置元素的查詢速度
棧 & 隊(duì)列
- 同側(cè)存取(lpush+lpop 或 rpush+rpop)為棧
- 異側(cè)存取(lpush+rpop 或 rpush+lpop)為隊(duì)列