技術選型理由
Etcd
- Zookeeper 和Etcd 都是業界優秀的分布式協調系統,解決了分布式系統協調和元數據存儲。etcd 參考了 ZooKeeper 的設計和實現經驗,並從 Zookeeper 中汲取的經驗教訓用於優化自身架構,從而幫助其支持 Kubernetes 等大型系統。
- 解決服務發現,保證元數據變更后對集群中的每個實例的本地緩存進行更新
- 技術創新,使用業界認可的中間件,保持技術先進性。使用成熟后可覆蓋其他業務場景。
Guava cache
業界和本部門很多應用都比較常用,基於jvm的內存緩存,適用於以下場景:
- 願意消耗一些內存空間來提升讀性能
- 鍵值會多次被查詢
- 內存適用總量不會超過jvm內容容量
對於分布式協調的應用場景沒有用redis、ducc、jmq因為這些中間件的應用場景的優勢不在於此。
改造一:業務數據本地緩存化,並通過分布式數據庫解決元數據一致性
目的
- 當前數據查詢先走redis緩存,為提高服務器利用率,遇突發流量時可以減少redis單分片的壓力
- 兩級緩存提高服務穩定性
- 解決數據在集群環境下的一致性,保證每個jvm內存中的數據一致
影響范圍
大促核心接口:
- xxx.checkSkuId,預估數據量10w條 (MaximumSize)10MB,最終按照壓測情況調優。
PopWareDetailService.PC/M 樣式接口,但由於數據內容較大,如果要做緩存,數據量要線上實際去觀測一下,建議只做熱點。
業務流程
第一步:業務場景下,數據的新增與更新會觸發入庫(mysql/mongodb)和redis,本方案會新增寫入etcd集群。寫入規則是根節點(系統名)/子節點(業務名)/葉子節點(業務key)
第二步:每個應用客戶端docker節點訂閱etcd集群業務目錄,業務目錄下的key值變更都會監聽到
第三步:監聽到有變化的key會將數據同步到基於guava cache實現的本地緩存中
第四步:當業務代碼被訪問時先從本地緩存中獲取數據,本地緩存是有數據的
第五步:如果本地緩存沒有數據(或者應用被重啟)通過第6步回源到redis獲取數據,並回寫到本地緩存中。數據有變更時會通過1,2,3步驟完成本地緩存的更新
第七步:監控服務負責Etcd集群監控,另外再用mdc系統監控
第八步:開源應用,查看Etcd節點和葉子節點數據
使用 對內存的管理:
- 緩存淘汰策略:LRU,最近最少使用策略,無論是否過期,根據元素最后一次被使用的時間戳,清除最遠使用時間戳的元素釋放空間。策略算法主要比較元素最近一次被get使用時間。在熱點數據場景下較適用,優先保證熱點數據的有效性
- 提供統計接口:緩存命中率、緩存條數
- 清理緩存接口:key、keys、all
業務規則
- etcd集群,一主兩從,預發環境2c4g,生產環境4c8g
- etcd集群監控,
- 現階段通過mdc進行服務器性能監控(cpu、內存、磁盤、連通性等)
- 搭建新應用來對集群健康進行監控,通過etcd提供http接口來獲取,結合ump進行監控,暫不進行監控數據的持久化
- 為XX.checkSkuId設置本地緩存優先讀取,如果沒查到回源到jimdb
- ducc參數與開關配置:
- 是否優先讀取本地緩存開關
- guava cache初始化配置,包括:緩存條數
- 本地緩存運維查詢接口:查詢key,刪除key/ALL,緩存命中率
- etcd SDK開發,包括功能put、get、del、watch
改造二:對緩存穿透、熱key、異常量、限流 4種數據上報,通過服務端計算進行結果的同步
目的
- 對null key進行計算,達到閾值則同步到集群的各客戶端jvm內存,解決緩存穿透
- 對熱key進行秒級的計算,達到閾值則同步到集群的各客戶端jvm內存,防止redis單片過熱
- 對調用的上游業務接口異常量進行計算,達到閾值則同步到集群的各客戶端jvm內存,進行業務熔斷
影響范圍
- PopWareDetailService.PC/M 樣式接口(nullkey、熱key)
- 工作台保存業務中的多個上游接口(熔斷)
業務流程
第一步,請求進入客戶端,從本地緩存讀取業務key數據進行業務流程判斷,是否空值,是否被限流、是否被降級
第二步,客戶端根據業務需求調用上報SDK模塊,進行null key的上報、調用上報、接口調用異常上報
第三步,計算集群上報心跳到etcd集群,SDK模塊從etcd獲取計算服務IP集合,實現服務發現
第四步,將業務key進行hash取模,再將上報請求固定在一台計算服務機器上進行計算。基於netty建立長鏈接,提高TPS
第五步,將符合閾值(ducc)的計算結果put到etcd集群的業務目錄/業務key。Sentinel、Resilience4j
第六步,客戶端對業務目錄/業務key進行訂閱,監聽程序進行數據同步,並更新到每個客戶端jvm內存
業務規則
- 先完成方案一的技術搭建
- 上報模塊SDK開發(空key、異常量、熱key),數據上報通信模塊客戶端開發
- 計算服務端開發(計算模塊),數據上報通信模塊服務端開發
- ducc參數與開關配置:
- 上報數據計算閾值配置
- 上報開關配置
- 是否優先讀取本地緩存配置
改造三:商品介紹數據Etcd兜底(探討,結論:不適合)
目的
- 為商品介紹數據尋找一個兜底數據庫,並且能100%負載大促流量和性能指標的數據庫
影響范圍
大促核心接口:SkuDecCheckService.checkWareIdDecInfo、PopWareDetailService.獲取樣式接口
業務流程
原有架構,核心接口中讀數據由jimdb硬抗。改造后
第一步,業務模塊會進行三寫,jimdb+etcd+mongodb。
第二步,數據請求先訪問本地緩存
第三步,本地緩存沒有查詢jimdb
第四步,jimdb沒有數據回源查詢mongodb
第五步,jimdb異常從etcd查詢
第六步,ducc作為查詢jimdb還是etcd的手動開關
目前jimdb資源占用內存130G,8分片,峰值操作6.7w次。建議Etcd集群指標 QPS 8w、硬盤300G。
以下是官方的性能參考:
集群部署策略:
- 集群磁盤容量不足,分片存儲
- 提高QPS
- 數據分攤,單點故障也能提供有損服務
兜底數據可以考慮使用es。oss
Etcd運維
- etcd搭建(集群) etcd + (nginx/HAProxy) 高可用部署方案
- etcd服務監控(集群健康情況監控告警、新增節點、移除節點、單點故障與恢復)
- etcd方案權限控制(保證開發環境與生產環境的隔離)
- etcd重啟與數據恢復
- etcd磁盤打滿解決方案
其他
發布過的sku數量:27874618(未去重)
不進行全量數據的本地緩存(雖然全量數據不多),因為歷史數據可能就沒有訪問量,存入本地緩存浪費資源。
對非熱點數據不進行本地緩存數據一致性處理,比如場景:容器A接收到請求寫入本地緩存key1后,不將key1同步到容器B、C。
壓縮樣式內容字符串,提高緩存數量
其他:當前業務沒有限流的需求,但基於這樣的架構限流也能做
待確認
1、etcd的集群申請
2、實時計算服務的選型可以考慮kafka,kafka性能:單個Consumer每秒可消費三百萬條消息,單個Producer每秒可成功發送一百多萬條消息
3、災備建議使用jimdb成本較低
4、watch的延時問題,需要通過測試來驗證
1、願意消耗一些內存空間來提升讀性能
2、鍵值會多次被查詢
3、內存適用總量不會超過jvm內容容量