又拍雲 Redis 的改進之路

作爲推出國內首創可編程 CDN 服務的專業雲服務提供商,又拍雲利用 CDN 邊緣網絡規模和性能,允許客戶自定義編寫規則來滿足常用業務場景。而爲了保證這些源數據,如邊緣重定向、請求限速、自定義錯誤頁面、訪問防盜鏈控制、 HTTP 頭部管理等,能快速同步到邊緣的節點服務器,在對比了多個方案以後,又拍雲於 2014 年初開始使用 Redis2.8 版本作爲數據同步的解決方案。

最初的架構如下:

在繼續談 Redis 改進前,我們要先了解一下技術債。這裏說的技術債指的是技術負債,通常開發人員爲了加速軟件開發,在應該採用最佳方案時可能進行妥協,改用短期內能加速軟件開發的方案。而這種方案在未來給自己帶去了額外開發負擔。這種雖然眼前看起來可以得到好處,但必須在未來償還的選擇,就像債務一樣,所以被叫做技術債。

而我們上面說到的這個方案就埋下了技術債的引子。在過去的幾年裏它雖然起到重要的作用,但架構的缺點明顯,而且隨着邊緣服務器數量和同步數據量的增加,再加上服務器硬件的老化故障等等原因,造成了很多問題,比如如下問題:

  • 出於安全考慮,相互 Redis 之間的通信數據都需要加密,但 Redis 本身不支持 SSL 加密。因此所有的邊緣服務器都必須通過 stunnel 套接做中轉服務器。然而實際工作狀態下,stunnel 的性能不足,導致服務器 CPU 負載過高。

  • Redis 的數據主從都是長連接且儘量保持從同一源做同步,因此早期邊緣服務器都是通過域名解析的方式來獲取源服務器的 IP 地址。這樣的好處是實施部署簡單,缺點是 DNS 無法獲知後端服務器的處理能力,造成每臺機器上的長連接負載不均衡。而且後端服務出故障後 DNS 也無法自動處理, 即便及時對 DNS 進行了切換解析,也會因爲 TTL 生效前的真空期引起數據不一樣, 導致只能使用舊數據應急。

  • 因爲歷史遺留原因, 邊緣 Redis 版本大都是 2.x 低版本,而低版本只能通過 sync 做全量同步。因此中轉服務器和主服務器的異常都會造成全網的雪崩效應,從而同步阻塞,無法快速同步元數據到邊緣。

  • 因爲早期 Redis 只有主從模式可以採用,也沒有實現哨兵和集羣改造。所以讓如今主服務器成爲了單點風險,很容易造成源頭上的重大故障。

因爲之前妥協導致的問題和副作用,以至於我們現在必須要付出額外的時間和精力進行重構,把架構改善爲最佳實現方式。

我們把改造過程分成幾個步驟:

加強 SSL 的安全防護,儘可能升級到 OpenSSL 最新的穩定版本

SSL 可能是大家接觸比較多的互聯網安全協議之一,一般網站地址用了“https://”開頭,就是採用了 SSL 安全協議。OpenSSL 是一種開放源碼的 SSL 實現,用來實現網絡通信的高強度加密,現在被廣泛地用於各種網絡應用程序中。如此重要的項目多年來始終面臨着資金和人手不足的窘境,多數工作都要由爲數不多的黑客和愛好者及志願者來完成。幸好現在納入 Linux 基金會資金資助對象,不過依然有新漏洞不斷暴露,需要及時關注和跟進。

參考最新的 OpenSSL 漏洞危險等級報告:

鑑於 RC4 算法安全漏洞太多,建議編譯時選擇禁用。

使用最新的 stunnel 版本,優化性能,基於安全 OpenSSL 依賴庫,支持 TLSv1.2+ 以上

從下圖的紅色框中可以看出,stunnel 在某些算法下的性能是最強的,所以在配置文件中推薦優先使用:

./configure --prefix=/opt/stunnel --with-ssl=/opt/openssl

來看一下推薦配置中的優化選項:

verify = 3
sslVersionMax = TLSv1.3
sslVersionMin = TLSv1.2
options = NO_SSLv2
options = NO_SSLv3
.......
ciphers = ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE

可以通過亞洲誠信的網站來做 HTTPS 的可信等級檢測和驗證。

編譯最新的 Redis-6.2.x 穩定版,功能強大豐富且無需依賴高版本的 GCC

Redis6.2 與 7.0 對比來看的話,肯定是 7.0 版本更爲強大一點。Redis7.0 幾乎包括了對各個方面的增量改進,其中最值得注意的是 Redis Functions、ACLv2、command introspection 和 Sharded Pub/Sub。7.0 版添加了近 50 個新命令和選項來支持這種演變並擴展 Redis 的現有功能。

但是儘管 Redis7.0 更加強大,可是綜合考慮到與原來的 Redis 代碼的完全兼容性,以及生產環境的穩定,我們最終選擇了 Redis6.2。因爲 Redis6.2 的優點也足夠多,功能也很強大,而且更能滿足我們生產環境的要求,比如:

  • 多線程 IO(Threaded I/O)

  • 衆多新模塊(modules)API

  • 更好的過期循環(expire cycle)

  • 支持 SSL

  • ACLs 權限控制

  • RESP3 協議

  • 客戶端緩存(Client side caching)

  • 無盤複製&PSYNC2

  • Redis-benchmark 支持集羣

  • Redis-cli 優化、重寫 Systemd 支持

  • Redis 集羣代理與 Redis6 一同發佈(但在不同的 repo)

  • RDB 更快加載

  • SRANDMEMBER 和類似的命令具有更好的分佈

  • STRALGO 命令

  • 帶有超時的 Redis 命令更易用

重點介紹一下 PSYNC2 的特性,這也是我們架構改進升級的重點特性之一。

在 Redis cluster 的實際生產運營中,實例的維護性重啓、主實例的故障切換(如cluster failover)操作都是比較常見的(如實例升級、rename command 和釋放實例內存碎片等)。而在 Redis4.0 版本前,這類維護性的處理 Redis 都會發生全量重新同步,導到性能敏感的服務有少量受損。而 PSYNC2 主要讓 Redis 在從實例重啓和主實例故障切換場景下,也能使用部分重新同步。

直接下載源代碼編譯:

# make BUILD_TLS=no

推薦配置,添加以下選項增強性能:

io-threads-do-reads yes
io-threads 8
aof-use-rdb-preamble yes

在我們的測試過程中,發現 Redis+TLS 有幾個問題:

  • Redis 開啓 TLS後,性能下降 30%。

  • Redis 對 OpenSSL 的強依賴性. 考慮到 OpenSSL 的過往高危漏洞不斷, 如果要不斷修復漏洞要重新編譯 Redis,導致運維更新成本過高。

  • Redis 升級後, 要重新同步數據, 增加了出故障的機率或讓生產停擺。

所以, 我們還是決定使用第三方程序 stunnel 來加固安全,方便升級和修復漏洞。又不影響後端連接,從而保障了 Redis 的工作連續性和穩定可靠性。

基於 APISIX+TLS 託管,使用 TCP 的哈希一致性做負載均衡來替換 DNS 的輪詢,效能顯著

APISIX 使用 TCP 代理, 這部分直接配置後就可以使用,和 Redis 改造關係不大,我們就直接略過,大家可以直接看一下改造後的連接數統計截圖。從實際的 APISIX 的連接數可以看出負載被數量均衡地分攤到了不同的後端,而且邊緣服務器重啓也利用 PSYNC2 做了快速的增量同步。

使用 Redis-shake 做定製化的數據同步

在架構改進的過程中,我們也看了 redis-shake 這個工具,它是阿里雲 Redis&MongoDB 團隊開源的用於 Redis數據同步的工具。它支持 解析、恢復、備份、同步 四個功能。給大家主要介紹同步 sync:

恢復 restore:將 RDB 文件恢復到目的 Redis 數據庫。

備份 dump:將源 Redis 的全量數據通過 RDB 文件備份起來。

解析 decode:對 RDB 文件進行讀取,並以 json 格式解析存儲。

同步 sync:支持源 Redis 和目的 Redis 的數據同步,支持全量和增量數據的遷移。

同步 rump:支持源 Redis 和目的 Redis 的數據同步,僅支持全量的遷移。採用 scan 和 restore 命令進行遷移,支持不同雲廠商不同 Redis 版本的遷移。

我們原來有一個做過源代碼修改過的 Redis,只會同步想要的空間。雖然好用,但還是需要在新代碼上重新編譯一個,可是原來的負責人已經找不到了。這也是很多年久失修項目的通病, 但通過 redis-shake 這樣的開源工具,只要通過它簡單配置一下就可以實現我們想要的功能:

  - filter.db.whitelist / blacklist
  - filter.key.whitelist / blacklist
  - filter.command.whitelist / blacklist

現在的架構及未來的展望

在現在的架構中,我們在原來的三層架構基礎上,又拆分和強化了三層架構:

  • DNS 層解析到 VIP,VIP 利用了 BGP/OSPF 的動態網關路由協議,對應後面一組服務器集羣服務。

  • 負載均衡層:利用 “apisix ”+ “tls1.2+ ”+ “tcp的哈希一致性連接”,把 Redis 的主從連接均衡,故障轉移。

  • 邊緣 CDN 節點,利用 Redis 高版本所帶來的技術紅利,psync 的增量同步,加上 stunnel+tls1.2 實現了加密傳輸。

下一個階段, 還要繼續把數據中心的 Redis 主改造成 Redis 哨兵模式(考慮到程序代碼要對哨兵模式做兼容性改造, 第一階段先不上, 一切都爲了生產環境中的穩定性)。

參考文檔:

如何檢查網站的 TLS 版本:https://wentao.org/post/2020-11-29-ssl-version-check/

Redis 特性之複製增強版 PSYNC2:https://www.modb.pro/db/79478

通俗易懂的 Redis 架構模式詳解:https://www.cnblogs.com/mrhelloworld/p/redis-architecture.html

推薦閱讀

【實操乾貨】做好這 16 項優化,你的 Linux 操作系統煥然一新

Golang 常見設計模式之單例模式

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章