【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. 微服務架構的一知半解