線(xiàn)上真實(shí)排隊(duì)系統(tǒng)重構(gòu)案例分享
詳細(xì)技術(shù)方案介紹
一、背景
1、現(xiàn)狀:
* 目前線(xiàn)上乘客排隊(duì)性能瓶頸很明顯,主要采用Redis List存儲(chǔ)結(jié)構(gòu)。隨著隊(duì)列中訂單量增大,查詢(xún)、插入、判斷訂單是否在隊(duì)列中等操作RT指數(shù)級(jí)增長(zhǎng)。
* 目前乘客排隊(duì)架構(gòu),無(wú)法滿(mǎn)足業(yè)務(wù)擴(kuò)展需求,為支撐之后業(yè)務(wù)快速迭代,乘客排隊(duì)重構(gòu)迫在眉睫。
2、調(diào)研事項(xiàng)
* 使用Mysql存儲(chǔ)排隊(duì)信息可行性分析(線(xiàn)下環(huán)境壓測(cè))
* 對(duì)外接口和影響范圍梳理(目前對(duì)外提供的20個(gè)左右接口分析),
表格如下:
接口名稱(chēng) | 接口路徑 | 調(diào)用方 | QPS | RT(995) | 平均RT | 備注 |
入隊(duì) | /queue/enter | XXX | XXX | XXX | XXX |
二、目標(biāo)
1、對(duì)外接口不變,從底層存儲(chǔ)改造,兼容目前線(xiàn)上顯示場(chǎng)景,乘客排名顯示和出隊(duì)解耦。
排名顯示保留普通隊(duì)列、渠道隊(duì)列、優(yōu)先隊(duì)列(包含絕對(duì)優(yōu)先), 按入隊(duì)時(shí)間排序
出隊(duì)排序因子入隊(duì)時(shí)根據(jù)固定規(guī)則計(jì)算, 采用更加靈活的策略算法計(jì)算出隊(duì)優(yōu)先級(jí), 出隊(duì)時(shí)只需根據(jù)排序因子排序,從而間接決定出隊(duì)順序,
2、數(shù)據(jù)存儲(chǔ)排名采用Redis有序集合,隊(duì)列信息新增mysql存儲(chǔ),分128張表。
3、解決目前性能瓶頸問(wèn)題,支持后續(xù)業(yè)務(wù)快速迭代,以及后續(xù)需求擴(kuò)展。
三、整體方案
1、新老方案對(duì)比
重構(gòu)前存儲(chǔ)架構(gòu): redis: list數(shù)據(jù)結(jié)構(gòu) , key:蜂巢中心點(diǎn) + 車(chē)型 + 隊(duì)列類(lèi)型
重構(gòu)后存儲(chǔ)架構(gòu):
排名隊(duì)列: redis有序集合, key: 蜂巢中心點(diǎn) + 車(chē)型 + 隊(duì)列類(lèi)型(為了兼容老的)
隊(duì)列信息表: queue_info_xxx, mysql存儲(chǔ), 按蜂巢中心點(diǎn) hash分表,訂單號(hào) + 車(chē)型 建聯(lián)合唯一索引
部分接口新—老對(duì)比
接口 | 查看排名 | 是否在隊(duì)列中 | 入隊(duì) | 出隊(duì) | 插隊(duì) |
重構(gòu)前 | 1. 循環(huán)所有隊(duì)列中所有元素,循環(huán)判斷計(jì)算位置,2.查詢(xún)算法組計(jì)算預(yù)估時(shí)間 | 遍歷查詢(xún)出隊(duì)列所有元素,循環(huán)判斷是否contain | 先判斷是否在隊(duì)列中存在,這里也會(huì)判斷根據(jù)命中不同隊(duì)列類(lèi)型,寫(xiě)入redis 隊(duì)列(list) 中 | 根據(jù)車(chē)型循環(huán)&多隊(duì)列類(lèi)型循環(huán)出隊(duì),并記錄log | 權(quán)益卡插隊(duì) |
重構(gòu)后 | 通過(guò)訂單號(hào)從”隊(duì)列信息表“ 中查詢(xún)排隊(duì)信息,存在排隊(duì)記錄,判斷是否存在排名,若不存在排名顯示M+(排名隊(duì)列存在上線(xiàn)控制),否則查詢(xún)”排名隊(duì)列“直接返回順序 。查詢(xún)算法組計(jì)算預(yù)估時(shí)間 | 直接查詢(xún)"隊(duì)列信息表"判斷是否存在記錄 | 先寫(xiě)入"隊(duì)列信息表",若未超過(guò)排號(hào)閾值,則寫(xiě)入對(duì)應(yīng)"排名隊(duì)列" | 更新"隊(duì)列信息表"狀態(tài),若存在排名,則從排名隊(duì)列中移除,并異步通知候補(bǔ),并記錄log | 直接通過(guò)更新隊(duì)列信息表”order_by“字段 即可改變出隊(duì)順序 |
重構(gòu)前瓶頸分析: 每次請(qǐng)求都會(huì)將隊(duì)列中元素全部取出循環(huán)遍歷(當(dāng)排隊(duì)訂單量增大時(shí),RT呈指數(shù)級(jí)增長(zhǎng),賣(mài)個(gè)關(guān)子,原因大家可以想想為啥?)
重構(gòu)后存儲(chǔ)架構(gòu)優(yōu)勢(shì): 將原來(lái)的O(n)時(shí)間復(fù)雜度,變?yōu)镺(1)復(fù)雜度。
2、重構(gòu)后架構(gòu)圖
關(guān)于隊(duì)列大小統(tǒng)計(jì)問(wèn)題:
排名未限流隊(duì)列: 直接通過(guò)ZCARD獲取 (O(1) 時(shí)間復(fù)雜度)
排名限流隊(duì)列: 通過(guò)計(jì)數(shù)器獲取總長(zhǎng)度 (O(1)), 降級(jí)通過(guò)ZCARD獲取
2)關(guān)于新增運(yùn)力撮合——查詢(xún)列表【橙色部分】可能存在瓶頸問(wèn)題——后期優(yōu)化方向有2種 可以排名前N抽離出緩沖集合 隊(duì)列截?cái)?—— 大小超過(guò)N轉(zhuǎn)為其它表存儲(chǔ)
3、其它流程圖: 入隊(duì)、出隊(duì)流程圖 (此處省略)
4、表結(jié)構(gòu)設(shè)計(jì)
queue_info_[001 ~ 128] : 排隊(duì)信息表 按蜂巢中線(xiàn)點(diǎn) hash % 128 規(guī)則分表,數(shù)據(jù)按天歸檔
queue_manager : 排 名隊(duì)列管理表 主要控制是否限流狀態(tài),和蜂巢隊(duì)列信息
queue_log_[001~128] : 訂單入隊(duì)&出隊(duì)記錄表,按蜂巢中線(xiàn)點(diǎn) hash % 128 規(guī)則分表,后期再考慮歸檔。
詳細(xì)表結(jié)構(gòu) —— 省略
四、排序字段(order_by) 設(shè)計(jì)
針對(duì)排隊(duì)場(chǎng)景,時(shí)間越小,越在前??梢允褂脮r(shí)間差逆序計(jì)算,公式如下: ~(-1L << 39L) & (~(毫秒級(jí)時(shí)間差))
其它規(guī)則此處省略.
五、歷史隊(duì)列場(chǎng)景兼容問(wèn)題
排名顯示: 普通隊(duì)列、渠道隊(duì)列、優(yōu)先隊(duì)列
訂單出隊(duì): 通過(guò)權(quán)重系數(shù)不同配置,最后計(jì)算出不同排序
六、灰度方案
按城市灰度,先選小流量城市。
七、回滾方案
關(guān)閉城市灰度開(kāi)關(guān),已存在隊(duì)列中數(shù)據(jù)會(huì)影響,需要遷移工具刷新數(shù)據(jù)
八、數(shù)據(jù)歸檔方案 & 兜底方案
數(shù)據(jù)歸檔: 乘客排隊(duì)信息按天歸檔
兜底策略: 長(zhǎng)時(shí)間(可配置)排隊(duì)狀態(tài)未變更(可能出現(xiàn)異常),強(qiáng)制退出
九、數(shù)據(jù)監(jiān)控&報(bào)警
乘客排隊(duì)Grafana監(jiān)控: 監(jiān)控指標(biāo): 城市、蜂巢、車(chē)型、普通隊(duì)列數(shù)、渠道隊(duì)列數(shù)、優(yōu)先隊(duì)列數(shù) 報(bào)警: 隊(duì)列數(shù)超過(guò)閾值釘釘報(bào)警
十、時(shí)間規(guī)劃
方案調(diào)研的接口(20個(gè)接口)增加改造方案、責(zé)任人,進(jìn)度項(xiàng)
接口名稱(chēng) | 接口路徑 | 調(diào)用方 | QPS | RT(995) | 平均RT | 備注 | 改造方案 | 責(zé)任人 | 進(jìn)度 |
入隊(duì) | /queue/enter | XXX | XXX | XXX | XXX |
注意: 接口自測(cè) 和 CR是在開(kāi)發(fā)階段完成的,監(jiān)控報(bào)警不影響測(cè)試的開(kāi)發(fā),可以在測(cè)試階段開(kāi)發(fā)。
十一、關(guān)聯(lián)組
略
十二、所需資源
略
總結(jié)
重構(gòu)需要考慮到細(xì)節(jié)很多,需要考慮到每一個(gè)可能出現(xiàn)瓶頸的地方,以及后續(xù)優(yōu)化,擴(kuò)展問(wèn)題。
所有改動(dòng)項(xiàng),必須責(zé)任到個(gè)人(避免遺漏),另外提測(cè)之前必須全部自測(cè)通過(guò)(單元測(cè)試)。