【Go 語言框架與實現 學習資料】第三屆字節跳動青訓營 - 後端專場

語言: CN / TW / HK

theme: juejin

第三屆字節跳動青訓營講師非常用心給大家整理了課前、中、後的學習內容,同學們自我評估,選擇性查漏補缺,便於大家更好的跟上講師們的節奏,祝大家學習愉快,多多提問交流~

第十三節:深入淺出 RPC 框架

概述

本節課程主要分為四個方面:

  1. RPC 相關的基本概念
  1. RPC 框架的分層設計
  1. 衡量 RPC 框架的一些核心指標
  1. 字節內部 RPC 框架 Kitex 實踐分享

課前部分主要羅列課程中涉及到的概念。對於不熟悉的概念,同學們可以提前查詢預習;

課中部分主要羅列每一部分的關鍵思路,幫助同學們跟上課程的進度;

課後部分是一些問題,幫助同學們在課後梳理本課程的重點。

課前

RPC 的基本概念

  • IDL(Interface Definition Language) 文件

    • Thrift
    • Protobuf
  • 生成代碼
  • 編解碼(序列化/反序列化)
  • 通信協議

    • 應用層協議
  • 網絡通信

    • IO 網絡模型

      • blocking IO
      • unblocking IO
      • IO multiplexing
      • signal driven IO
      • asynchronous IO
    • 傳輸層協議

      • TCP
      • UDP

RPC 框架分層設計

  • 編解碼層

    • 數據格式:

      • 語言特定格式

      • 文本格式

      • 二進制編碼

        • TLV 編碼:Thrift 使用 TLV 編碼
        • Varint 編碼:Protobuf 使用 Varint 編碼
    • 選項:

      • 兼容性
      • 通用型
      • 性能
  • 傳輸協議層

    • 消息切分

      • 特殊結束符
      • 變長協議:length+body
    • 協議構造

      • 以 Thrift 的 THeader 協議為例講解
  • 網絡通信層

    • 網絡庫

    • 核心指標

      • 吞吐高
      • 延遲低

RPC 框架的核心指標

  • 穩定性

    • 保障策略

      • 熔斷
      • 限流
      • 超時
    • 請求成功率

      • 負載均衡
      • 重試
    • 長尾請求

      • BackupRequest
  • 易用性

    • 開箱即用
    • 周邊工具
  • 擴展性
  • 觀測性

    • Log
    • Metric
    • Tracing
    • 內置觀測性服務
  • 高性能

字節內部 Kitex 實踐分享

  • 合併部署

課中

基本概念

  • 相比本地函數調用,RPC調用需要解決的問題

    • 函數映射
    • 數據轉換成字節流
    • 網絡傳輸
  • 一次 RPC 的完整過程
  • RPC 帶來的問題將由 RPC 框架來解決

    • 服務宕機如何感知?
    • 遇到網絡異常應該如何應對?
    • 請求量暴增怎麼處理?

RPC 框架分層設計

編解碼層

  • 數據格式

    • 語言特定格式:例如 java.io.Serializable
    • 文本格式:例如 JSON、XML、CSV 等
    • 二進制編碼:常見有 Thrift 的 BinaryProtocol,Protobuf,實現可以有多種形式,例如 TLV 編碼 和 Varint 編碼
  • 選型考察點

    • 兼容性

    • 通用型

    • 性能

      • 空間開銷
      • 時間開銷
  • 生成代碼和編解碼層相互依賴,框架的編解碼應當具備擴展任意編解碼協議的能力

協議層

  • 以 Thrift 的 THeader 協議為例

    - LENGTH 字段 32bits,包括數據包剩餘部分的字節大小,不包含 LENGTH 自身長度 - HEADER MAGIC 字段16bits,值為:0x1000,用於標識 協議版本信息,協議解析的時候可以快速校驗 - FLAGS 字段 16bits,為預留字段,暫未使用,默認值為 0x0000 - SEQUENCE NUMBER 字段 32bits,表示數據包的 seqId,可用於多路複用,最好確保單個連接內遞增 - HEADER SIZE 字段 16bits,等於頭部長度字節數/4,頭部長度計算從第14個字節開始計算,一直到 PAYLOAD 前(備註:header 的最大長度為 64K) - PROTOCOL ID 字段 uint8 編碼,取值有: - ProtocolIDBinary = 0 - ProtocolIDCompact = 2 - NUM TRANSFORMS 字段 uint8 編碼,表示 TRANSFORM 個數 - TRANSFORM ID 字段 uint8 編碼,表示壓縮方式 zlib or snappy - INFO ID 字段 uint8 編碼,具體取值參考下文,用於傳遞一些定製的 meta 信息 - PAYLOAD 消息內容

  • 協議解析

網絡通信層

  • 阻塞 IO 下,耗費一個線程去阻塞在 read(fd) 去等待用足夠多的數據可讀並返回。
  • 非阻塞 IO 下,不停對所有 fds 輪詢 read(fd) ,如果讀取到 n <= 0 則下一個循環繼續輪詢。

第一種方式浪費線程(會佔用內存和上下文切換開銷),第二種方式浪費 CPU 做大量無效工作。而基於 IO 多路複用系統調用實現的 Poll 的意義在於將可讀/可寫狀態通知和實際文件操作分開,並支持多個文件描述符通過一個系統調用監聽以提升性能。
網絡庫的核心功能就是去同時監聽大量的文件描述符的狀態變化(通過操作系統調用),並對於不同狀態變更,高效,安全地進行對應的文件操作。

RPC 框架核心指標

穩定性

  • 保障策略

    • 熔斷
    • 限流
    • 超時控制

從某種程度上講超時、限流和熔斷也是一種服務降級的手段 。

  • 請求成功率

    • 負載均衡
    • 重試
  • 長尾請求

    • BackupRequest

易用性

  • 開箱即用

    • 合理的默認參數選項、豐富的文檔
  • 周邊工具

    • 生成代碼工具、腳手架工具

擴展性

  • Middleware:middleware 會被構造成一個有序調用鏈逐個執行,比如服務發現、路由、負載均衡、超時控制等
  • Option:作為初始化參數
  • 核心層是支持擴展的:編解碼、協議、網絡傳輸層
  • 代碼生成工具也支持插件擴展

觀測性

  • 三件套:Log、Metric 和 Tracing

  • 內置觀測性服務,用於觀察框架內部狀態

    • 當前環境變量
    • 配置參數
    • 緩存信息
    • 內置 pprof 服務用於排查問題

高性能

  • 連接池和多路複用:複用連接,減少頻繁建聯帶來的開銷
  • 高性能編解碼協議:Thrift、Protobuf、Flatbuffer 和 Cap'n Proto 等
  • 高性能網絡庫:Netpoll 和 Netty 等

字節內部 Kitex 實踐分享

  1. 框架文檔 Kitex
  1. 自研網絡庫 Netpoll,背景:

    a. 原生庫無法感知連接狀態
    b. 原生庫存在 goroutine 暴漲的風險

  1. 擴展性:支持多協議,也支持靈活的自定義協議擴展
  1. 性能優化,參考 字節跳動 Go RPC 框架 KiteX 性能優化實踐

    a. 網絡優化

    i.  調度優化  
    ii.  LinkBuffer 減少內存拷貝,從而減少 GC  
    iii.  引入內存池和對象池
    

    b. 編解碼優化

    i.  Codegen:預計算提前分配內存,inline,SIMD等
    ii.  JIT:無生產代碼,將編譯過程移到了程序的加載(或首次解析)階段,可以一次性編譯生成對應的 codec 並高效執行
    
  1. 合併部署

    a. 微服務過微,引入的額外的傳輸和序列化開銷越來越大
    b. 將強依賴的服務統計部署,有效減少資源消耗

課後

  1. 行業內各個流行的 RPC 框架的優劣對比
  1. 從第三章節 RPC 的核心指標來看,Kitex 還有哪些功能是欠缺或者需要加強的?
  1. 瞭解微服務的新趨勢 ServiceMesh,以及 RPC 框架和 ServiceMesh 的關係
  1. 關於 RPC 框架,業界有哪些新的趨勢和概念?
  1. Netpoll 的優勢在哪?相比其他高性能網絡庫例如 Netty 還有什麼不足?
  1. Flatbuffer 和 Cap'n Proto 等編解碼協議為什麼高性能?

參考文獻

  1. 官方文檔 Kitex Netpoll
  1. 字節跳動 Go RPC 框架 KiteX 性能優化實踐_架構_字節跳動技術團隊_InfoQ精選文章
  1. 字節跳動微服務架構體系演進_架構_字節跳動技術團隊_InfoQ精選文章

第十四節:HTTP 框架修煉之道

概述

本節課程主要分為四個方面:

  1. HTTP 協議相關知識
  1. HTTP 框架的設計與實現
  1. HTTP 框架的優化手段
  1. 企業實踐

課前部分主要羅列課程中涉及到的概念。對於不熟悉的概念,同學們可以提前查詢預習;課後部分是一些問題,幫助同學們在課後梳理本課程的重點。

課前

HTTP 協議

  • HTTP 協議出現背景
  • HTTP 協議是什麼
  • HTTP 協議有什麼

可參考百度百科

嘗試寫一個 hello world 服務器

可嘗試用 gin 寫一個 hello world 程序,達到以下效果

HTTP 框架中常見概念

  • 框架路由:根據請求的 URI 選擇對應的處理函數。

    • 首先匹配 HTTP 方法

    • 靜態路由: 精確匹配註冊的路由,如:/a/b/c、/a/b/d

    • 參數路由:

      • 命名參數:形如 :name這類叫做命名參數,命名參數只匹配單個路徑段:
      • ``` Pattern: /user/:user

        /user/gordon match(user = gordon) /user/you match(user = you) /user/gordon/profile no match /user/ no match - 通配參數:形如 **`*action`**這類叫做通配參數,就像名字所暗示的那樣,它們匹配所有內容。因此,它們必須始終位於模式的末尾: - Pattern: /src/*filepath

        /src/ match(filepath = "") /src/somefile.go match(filepath = somefile.go) /src/subdir/somefile.go match(filepath = subdie/somefile.go) ```

    • 路由修復: 如果只註冊了 /a/b,但是訪問的 URI 是 /a/b/,那可以提供自動重定向到 /a/b 能力;同樣,如果只註冊了 /a/b/,但是訪問的 URI 是 /a/b,那可以提供自動重定向到 /a/b/ 能力

    • 衝突路由:同時註冊 /a/b 和 /:id/b,並設定優先級。比如:當請求 URI 為 /a/b 時,優先匹配靜態路由 /a/b

  • 什麼是框架中間件,可參考 ginkratos

Golang

網絡庫

  • C10K Problem
  • Select,Poll,Epoll
  • Epoll ET、LT 區別

SIMD

課後作業

  1. 為什麼 HTTP 框架做要分層設計?分層設計有哪些優勢與劣勢。
  1. 現有開源社區 HTTP 框架有哪些優勢與不足。
  1. 中間件還有沒有其他實現方式?可以用偽代碼説明。
  1. 完成基於前綴路由樹的註冊與查找功能?可以用偽代碼説明。
  1. 路由還有沒有其他的實現方式?

第十五節:微服務架構原理與治理實踐

概述

本課程內容主要分為以下4個方面:

  • 微服務架構介紹

    • 微服務架構的背景由來、架構概覽、基本要素
  • 微服務架構原理及特徵

    • 微服務架構的基本組件、工作原理、流量特徵
  • 核心服務治理功能

    • 核心的服務治理功能,包括流量治理、服務均衡、穩定性治理
  • 字節跳動服務治理實踐

    • 字節跳動在微服務架構穩定性治理中,對請求重試策略的探索及實踐

為了幫助大家更好地預習及理解本節課程,該學員手冊列出了課前、課中、及課後這三個階段所涉及到的專業內容大綱,其中課前部分供同學們提前預習參考,課中部分給出了課程大綱,幫助同學們整理思路,課後部分列出一些擴展性的問題讓同學們進一步延伸思考。

課前

微服務架構介紹

  • 系統架構的演進歷史

    • 單體架構
    • 垂直應用架構
    • 分佈式架構
    • SOA架構
    • 微服務架構
  • 微服務架構的三大要素

    • 服務治理
    • 可觀測性
    • 安全

微服務架構原理及特徵

  • 微服務架構中的基本概念及組件

    • 服務、實例......
  • 服務間通信

    • RPC、HTTP
  • 服務註冊及服務發現

核心服務治理功能

  • 服務發佈

    • 藍綠部署
    • 灰度發佈(金絲雀發佈)
  • 流量治理
  • 負載均衡

    • Round Robin
    • Ring Hash
    • Random
  • 穩定性治理

    • 限流
    • 熔斷
    • 過載保護
    • 降級

字節跳動服務治理實踐

  • 請求重試的意義
  • 請求重試的難點

課中

微服務架構介紹

系統架構的演進歷史

  • 單體架構

    • All in one process
  • 垂直應用架構

    • 按照業務線垂直劃分
  • 分佈式架構

    • 抽出與業務無關的公共模塊
  • SOA架構

    • 面向服務
  • 微服務架構

    • 徹底的服務化

微服務架構概覽

  • 網關
  • 服務配置和治理
  • 鏈路追蹤和監控

微服務架構的三大要素

  • 服務治理(本課程內容)

    • 服務註冊
    • 服務發現
    • 負載均衡
    • 擴縮容
    • 流量治理
    • 穩定性治理
  • 可觀測性

    • 日誌採集
    • 日誌分析
    • 監控打點
    • 監控大盤
    • 異常報警
    • 鏈路追蹤
  • 安全

    • 身份驗證
    • 認證授權
    • 訪問令牌
    • 審計
    • 傳輸加密
    • 黑產攻擊

微服務架構原理及特徵

微服務架構中的基本概念及組件

  • 服務

    • 一組具有相同邏輯的運行實體
  • 實例

    • 一個服務中的每個運行實體
  • 實例與進程的關係

    • 沒有必然對應關係,一般一對一或者一對多
  • 常見的實例承載形式

    • 進程、VM、k8s pod......

服務間通信

  • 微服務之間通過網絡進行通信
  • 常見的通信協議包括 HTTP、RPC

服務註冊及服務發現

  • 基本問題

    • 服務間調用中,如何指定下游服務實例的地址?
  • 簡單方案

    • 直接指定 ip:port?

      • 沒有任何動態能力
      • 有多個實例下游實例怎麼辦?
    • 使用 DNS?

      • 本地 DNS 存在緩存,導致延遲
      • DNS 沒有負載均衡
      • 不支持服務探活檢查
      • DNS 不能指定端口
  • 服務註冊發現

    • 新增一個統一的服務註冊中心,用於存儲服務名到服務實例之間的映射關係
    • 舊服務實例下線前,從服務註冊中心刪除該實例,下線流量
    • 新服務實例上線後,在服務註冊中心註冊該實例,上線流量
  • 微服務流量特徵

    • 統一網關入口
    • 外網通信多數採用 HTTP,內網通信多數採用 RPC(Thrift, gRPC)

核心服務治理功能

服務發佈

  • 何為服務發佈

    • 讓一個服務升級運行新的代碼的過程
  • 服務發佈難點

    • 服務不可用
    • 服務抖動
    • 服務回滾
  • 藍綠部署

    • 將服務分成兩個部分,分別先後發佈
    • 簡單、穩定
    • 但需要兩倍資源
  • 灰度發佈(金絲雀發佈)

    • 先發布少部分實例,接着逐步增加發布比例
    • 不需要增加資源
    • 回滾難度大,基礎設施要求高

流量治理

  • 流量控制

    • 在微服務架構中,可以從各個維度對端到端的流量在鏈路上進行精確控制
  • 控制維度

    • 地區維度
    • 集羣維度
    • 實例維度
    • 請求維度

負載均衡

  • Round Robin
  • Random
  • Ring Hash
  • Least Request

穩定性治理

  • 限流

    • 限制服務處理的最大 QPS,拒絕過多請求
  • 熔斷

    • 中斷請求路徑,增加冷卻時間從而讓故障實例嘗試恢復
  • 過載保護

    • 在負載高的實例中,主動拒絕一部分請求,防止實例被打掛
  • 降級

    • 服務處理能力不足時,拒絕低級別的請求,只響應線上高優請求

字節跳動服務治理實踐

  • 請求重試的意義

    • 本地函數調用

      • 通常沒有重試意義
    • 遠程函數調用

      • 網絡抖動、下游負載高、下游機器宕機......
      • 重試是有意義的,可以避免偶發性的錯誤,提高 SLA
    • 重試的意義

      • 降低錯誤率
      • 降低長尾延時
      • 容忍暫時性錯誤
      • 避開下游故障實例
  • 請求重試的難點

    • 冪等性

      • POST 請求可以重試嗎?
    • 重試風暴

      • 隨着調用鏈路的增加,重試次數呈指數級上升
    • 超時設置

      • 假設調用時間一共1s,經過多少時間開始重試?
  • 重試策略

    • 限制重試比例

      • 設定一個重試比例閾值(例如 1%),重試次數佔所有請求比例不超過該閾值
    • 防止鏈路重試

      • 返回特殊的 status code,表示“請求失敗,但別重試”
    • Hedged Requests

      • 對於可能超時(或延時高)的請求,重新向另一個下游實例發送一個相同的請求,並等待先到達的響應
  • 重試效果驗證

    • 字節跳動重試組件能夠極大限制重試發生的鏈路放大效應

課後

  1. 結合 CAP 等原理,思考微服務架構有哪些缺陷?
  1. 微服務是否拆分得越“微”越好?為什麼?
  1. Service Mesh 這一架構是為了解決微服務架構的什麼問題?
  1. 有沒有可能有這樣一種架構,從開發上線運維體驗上是微服務,但實際運行又類似單體服務?

參考文獻

  1. A Design Analysis of Cloud-based Microservices Architecture at Netflix
  1. 字節跳動微服務架構體系演進
  1. 微服務架構的一知半解