go-ums 從需求分析到設計實現( v0.1.0 )

tsingson發表於2019-05-12

_ gocn 的編輯器完全支援 markdown 啊, 這下發長文方便了. :P

_

專案原始碼地址 https://github.com/tsingson/go-ums

文字有點長, 儘量寫得簡單明瞭

文章概括內容都寫上了, 由於文件進一步細化並補充更多需求後, 需要拆分為設計文件/介面文件/測試文件/評審文件.....等等, 這裡不再持續更新.

後續補充變更, 請訪問 專案原始碼地址

0. go-ums 是什麼

go-ums 開發目標是一個開源專案, 核心由 golang 開發, 提供使用者管理(user-management-subsystem) / AAA 認證/鑑權/授 / 多業務會話共享與管理等, 以支援分散式部署及雲部署為主要目標

這是一個從零開始的小專案, 持續漸進

reading-go 夜讀 相關 issue 討論中, 有個 gin 的練手專案, 有點意思.

這是一個類似的專案, 不同的地方是, 這個專案是以文件開始的.

更多專案關聯文件, 請訪問 https://github.com/tsingson/go-ums , 在 readme 中列示並持續新增中

先有文件, 再寫程式碼. 在文件簡單說明一些我的設計套路

注: 這裡的設計, Design, 不限於架構設計, 程式設計, 也包含個人在攝影/印刷/書籍/海報中找出問題/解決問題的一些"套路".

先文件, 後實施, 也是曾經作 SA/SE 的習慣了吧. 當年曾戲稱自己是 Simple Editor , 哈, 懷念那8年, 大鬍子, yaho BB, black more, 北京香山, 上海文廣,三角洲島.......

稍後在持續更新中一一道來, 看看橫向之間的有趣關聯.

1. 業務場景

不談業務需求, 與業務場景中的人兒們,再好的技術也難以落地變現.

這就是原始需求的收集/整理/清理/梳理, 是開發貫串始終的目標與仲裁準則:

  1. 是什麼? 有什麼價值?
  2. 是誰在用? 如何用( 業務操作流程)? 哪些是關鍵節點(不能省掉的業務行為), 重點與難點是什麼?
  3. 在這些業務場景中, 邊界在哪裡( 哪些情況是正常, 哪些是異常, 如何判定, 什麼時間什麼情況下有哪些處理方式)

從一個簡單而典型的業務場景開始, 來

1.1 業務場景/需求描述

這個開源專案是從 goim 在開源社群交流討論後, 在 reading-go 討論中偶然開始的

從業多年, 個人幾乎不在網路上談論個人在 iT 技術職業經歷, 尤其是專案細節, 這裡, 算是換個方式來公開談談吧

所以, 這裡也從 goim 作為起點


很多朋友, 在閱讀 goim 原始碼時, 都會感覺到, 就算是 im 業務完整實施, 需要與使用者管理結合:

  1. 使用者註冊後, 提供一個使用者唯一標識, , 對應 goim 中的 mid
  2. 使用者認證, 讓使用者可以長連線到 goim , 在認證成功時
    1. 提供一個 token , 該 token 中包含使用者可以進入的房間列表
    2. 提供使用者傳送 im 資訊的入口地址( logic 部署多個情況下)
  3. 使用者在 goim 中涉及會話的業務功能( 變更房間.....)

所以, 我們可以從上面描述到的, (不能省掉的) 基本業務功能開始

來, 來, 來 ...GO!

1.1.1 場景與流程簡述

( 省略)

稍後補充示意圖

1.1.2 業務指標(效能要求)

(簡化)

  1. 要求業務響應, 排除網路延遲, 業務響應要求在 100ms 以內
  2. 支援10K tps 高併發
  3. 年度業務中斷時間低於5次, 業務中斷時間低於30分鐘
  4. 業務資料保留期限 1年
  5. 業務操作記錄要求支援審計

1.2.3 部署要求

(簡化)

  1. 伺服器部署中國骨幹網路IDC (電信網路為主, 廣州/上海兩地IDC ) 及美國骨幹網路IDC ( 略)
  2. 以部署服務端優先支援 linux 與 docker
  3. 客戶端支援 windows / mac / linux 的 terminal 命令列, 支援主流瀏覽器( 當前市場佔80%的主流版本, 相當於 IE 10+)

    1.2.4 開發/運維/運營要求

(省略)

1.2.5 成本要求

(省略)

1.2 feature list 需求列表

注, 以下按開發進度作了分組.

分組的意思, 就是排優先順序, 排優先順序即是排重要/緊急程度(按 SWOT Analysis 方式), 以決定先後處理順序.

1.2.1 prototype 開發需求 v0.1.0

使用者相關操作

  • [ ] 使用者註冊 register 使用者以 email + 密碼 註冊提交個人資訊, 提交後驗證 email 是否存在唯一衝突, 如果沒有, 註冊成功( 分配使用者ID) 注意, 這裡隱藏著一個檢查使用者是否存在的操作
  • [ ] 使用者登入與登出 login / logout 使用者以 email + passwrd 或 使用者名稱 + password 或 userID + password 可以進行登入, 登入成功, 給使用者傳送通行令牌 accessToken 注意, 這裡隱藏著一個檢查使用者登入成功返回一個 access token 的操作
  • [ ] 使用者認證 authentication 針對具體業務, 使用者訪問具體業務時, 傳送 access token 進行認證, 如果使用者認證成功, 可以訪問指定業務, 否則拒絕. 一般來說, 使用者認證成功即表示建立一個合法的業務會話
  • [ ] 使用者通行令牌驗證 verify 使用者訪問指定業務時, 驗證 token 是否在有效期內, 以及相關授權是否有變更, 如不符合業務授許可權制, 則拒絕提供服務

1.2.2 trial 試執行 v0.1.1

使用者相關操作

  • [ ] 使用者啟用 active 使用者註冊後, 向使用者郵箱傳送 email 驗證的啟用郵件, 使用者從郵件中獲取啟用碼後, 進行啟用操作
  • [ ] 使用者登入與登出 login / logout 使用者以 email + passwrd 或 使用者名稱 + password 或 userID + password 可以進行登入, 登入成功, 給使用者傳送通行令牌 accessToken
    • [ ] 使用者鎖定 suspend 禁止使用者業務消費行為, 一般來說, 使用者在具體業務上, 會有指定的服務週期, 超出服務週期, 使用者被鎖定
    • [ ] 使用者恢復 resume 恢復使用者授權的業務行為
    • [ ] 使用者刪除 deleted 使用者刪除自己或管理後臺刪除使用者, 注意, 在商用中, 使用者“刪除”一般意味著使用者狀態修改為 deleted 並停止所有訪問與所有業務, 但保留所有關聯資料( 這些關聯資料, 只有在一定期限後, 會手動或自動清除 purge )

2. 概要設計之模型設計

參照 1.2.1 小節, 很容易作一個簡單設計

2.1 資料模型

使用者物件名稱 account

  1. 使用者ID, 與 goim 配合, 就用 int64 吧, 一個全域性唯一的正整數
  2. email , (簡化), 都是字串, email 格式也不驗證, 其中 email 字串長不得少於5個字元( >=5 ) ,
  3. password, (簡化) 都是字串, 密碼不得少於6個字元( >= 6), 字元為 a..zA..Z0..9$%-
  4. access tokdn 通告令牌, 也用字串代替吧, 字串長度 >=32 字元
  5. 使用者角色, 分別為 非會員, 會員
  6. 使用者狀態, 分別為註冊未啟用, 已啟用, 禁用, 已刪除
  7. 使用者建立時間, 簡單點, 用 int64 或 UTC timestamp
  8. 使用者資訊變更時間, 簡單點, 用 int64 或 UTC timestamp

操作結果(狀態)定義

  1. transaction ID 事務唯一標識
  2. 狀態碼, 整數, 操作成功返回 200 / 操作失敗返回 500 / 請求接受並在處理中返回202
  3. 操作結果文字資訊, 少於255字元, 操作成功, 文字資訊, 要求標記業務操作名稱, 如 register ), 操作失敗, 返回失敗原因( 文字資訊 )

注: transaction ID 事務唯一標識, 支援非同步操作, 以支援分散式或叢集, 以及操作失敗時, 進行操作重試( 這樣可以讓服務端處理上次操作失敗的資料, 例如進行清理, 或繼續使用, 以及在日誌中進行檢查/審計)

原型實現的約束與限制:

  1. 為了快速實現原型, 使用者密碼直接儲存, 不加密
  2. 使用者ID , 直接用使用者建立的 utc 時間截( 納秒 )
  3. 簡化操作結果(狀態定義), 這裡先按 golang 實現習慣方式, 操作結果修改為 go 的 error 返回( 即 error = nil 或 != nil ) 注: 這個地方, 只是針對 go 的簡化

2.2 使用者操作與約束

(簡化)

  1. 使用者註冊 register ------> 呼叫 exists 檢查是否重複註冊, 如果不是, 建立使用者ID 並儲存使用者信資訊, 返回使用者資料( 不返回密碼), 返回操作結果狀態碼
  2. 檢查使用者是否重複存在 exists, 返回操作結果
  3. 使用者登入 login ------> 以 email + pwd 登入, 登入成功, 建立並返回 access token, 返回操作結果狀態碼
  4. 使用者登出 logout -----> 清除 access token , 返回操作結果狀態碼
  5. 使用者認證 auth -------> 輸入使用者ID 或 token , 呼叫 verify 檢查 會話中的token 是否合法, 如果 token 合法則返回成功, 返回操作結果狀態碼
  6. 使用者令牌驗證 verify --------> 檢查 token 是否存在, 並且是否相等, 返回操作結果狀態碼

2.3 業務流程設計 (僅以 register 使用者註冊為例)

2.3.1 register 使用者註冊

業務流程描述: 客戶端 ----------> 服務端, 進行使用者註冊, 傳送註冊資料, 由伺服器端返回註冊成功(獲取使用者ID ) 或失敗資訊

----> 輸入:
  1. transaction ID 事務唯一標識
  2. email 合法郵箱地址
  3. password 密碼
----> 內部邏輯實現
  1. 檢查 email 是否重複( 即被成功註冊過), 判斷沒有重複, 則進行 2, 判斷有重複, 進行下說明 3
  2. 生成使用者 ID , 並儲存到檔案或資料庫, 儲存成功, 返回成功結果輸出, 儲存失敗, 進行下說明 3
  3. 處理錯誤輸出
  4. 以上處理, 每一步均以 事務 ID 與時間為主鍵存日誌
----> 輸出
輸出 (成功, 返回使用者資訊, 遮蔽密碼欄位)
  1. account ID 使用者ID
  2. email
  3. 使用者角色
  4. 使用者狀態
  5. 建立時間
  6. 變更時間

    輸出 (失敗, 返回事務標識, 錯誤狀態碼, 錯誤原因文字)
  7. transaction ID 事務唯一標識
  8. 返回操作結果狀態碼
  9. 操作結果文字描述

2.3.2 介面設計

大白話:

介面就是兩個網元之間, 進行互動/通訊的網路協議/控制通訊命令(信令)/以約定格式傳輸相關資料(資料封裝)的簡稱

例如 web 瀏覽器與 web 伺服器這兩個網元之間, 一般採用 HTTP 協議, 信令是 GET / POST / PUT / PATCH / DELETE ...., 資料封裝通常是以 MIME 來指定, 比如下面用到的 "application/json; charset=utf-8"

設計實現以下介面

  1. RESTful 介面 ( 描述省略, 見程式碼)
  2. gRPC ( protobuf ) 介面 ( 略 )
  3. gRPC ( flatbuffers ) 介面( 對接 android java SDK , 詳細說明略)
  4. websocket 介面 ( 略 )
  5. TCP 介面 ( 略 )
2.3.2.1 RESTful 介面設計

關於 RESTful 介面, 相關推薦規範, 請自行查詢

這裡先簡要說明一下:

RESTful 通常是 HTTP + json 實現的介面, 其中

  1. 類似 /api/v1/account 這樣的 URI 就是一個介面, 其中 /api/v1 字首只是輔助管理

    在下面我們示例實現的使用者註冊介面, 可以定義為 /api/v1/register 或者 /xxx/yyyy 這樣你喜歡的方式

  2. HTTP 的 method 就是操作方式, 例如:
    • GET:讀取(Read)
    • POST:新建(Create)
    • PUT:更新(Update)
    • PATCH:更新(Update),通常是部分更新
    • DELETE:刪除(Delete)
  3. 資料編碼(序列化/反序列化) 是 "application/json; charset=utf-8” 標的 JSON 格式

  4. 少量操作關聯資料, 可以在 HTTP header 中傳遞, 比如 transactionID/ token / cookie , 這些關聯資料, 一般用來協助狀態跟蹤
2.3.2.1.1 使用者註冊

對照 2.3.1 , 使用者註冊的介面, 可以設計如下

--------->input請求

請求資源

POST 請求以下網址 http://localhost:3001/api/v1/register

request header

 Context-Type:  "application/json; charset=utf-8"
 TransactionID: "201001419845668864"

request body

{
  "email": "test@email.com",
  "password": "201001419845668864"
}

--------->output返回

response header

 Context-Type:  "application/json; charset=utf-8"
 TransactionID: "201001419845668864"

操作成功, 返回 http 狀態碼 200, 返回資料如下

response body

{
  "email": "test@email.com",
  "password": "201001419845668864"
}

操作失敗, 返回狀態碼 500, 返回資料如下

**

{
  "transactionID":"201001419845668864"
  "code": 500,
  "msg": "使用者Email已經被其他使用者使用, 請選擇其他email重新註冊"
}

其他部分, 稍後補充.........

2.3.3 測試用例如下

  1. 檢查 email 無重複, 操作成功
  2. 檢查 email 有重複, 操作失敗
  3. 異常, 主要關注兩個, 儲存失敗或異常, 通訊異常中斷 (詳細說明, 省略)

3.概要設計之架構設計

先簡化為以下架構作為驗證原型開發

client ( 多個) <----> gateWay( HA熱備, 支援路由/分流等) <-----> AAA (本地快取, 多個部署)<-------> UMS ( 雙機熱備)

其中:

  • client 到 AAA 首先實現 RESTful
  • AAA 到 UMS 之間, 選擇 gRPC + flatbuffers
  • UMS 後儲存, 選擇 redis + postgreSQL

稍後補充.........

4. 詳細設計

4.1 設計目標與原則

由於需求原因, 我們需要考慮達成以下目標:

  • 低延遲, 高容量, 高併發
  • 可擴充套件的多點部署, 雲部署

所以, 先拍腦袋隨意定義一下要實現目標, 如下所示. 接下來, 再評估哪些真正需要, 優先順序, 以及具體實現方案

  • 網元之間無狀態
  • 執行緒之間無鎖
  • 儘可能快的網元間介面通訊
  • 儘可能減少介面之間資料序列化/反序列化的次數, 加快介面之間資料序列化/反序列化的效率
  • 網元支援按需動態擴充套件或收縮部署, 簡單點, 就是網元健康檢查 + 路由 + 分流可控制
  • 支援 QOS 控制, 先支援限流

4.2 設計實現 ( golang 為例)

稍後補充說明部分

4.2.1 模型的實現

使用者模型與操作的 golang 實現

見 [https://github.com/tsingson/go-ums/blob/master/model/account.go]

(說明省略)

4.2.2 介面設計的實現

見 [https://github.com/tsingson/go-ums/blob/master/model/account.go]

(說明省略)

4.2.3 業務邏輯實現

https://github.com/tsingson/go-ums/blob/master/pkg/services/account.go

(說明省略)

4.2.4 UT ( Unit Test) 單元測試

測試用例如下

  1. 檢查 email 無重複, 操作成功
  2. 檢查 email 有重複, 操作失敗
  3. 其他異常( 略)

見 /pkg/service 下測試程式碼

4.3 LIT ( local integration test) 網元整合測試

見 /pkg/web 下各測試程式碼

4.4 SIT ( system intergration test ) 系統整合測試

見 /cmd/cli 下程式碼

稍後補充..........

4.5 編譯/部署/運維

參見 go-ums v0.1.0 測試/編譯/執行

稍後補充.............

5. 效能測試/部署測試/ trial 驗證

省略 ...

6. 附註/參考

6.1 介面設計相關參考

_

_

關於我

網名 tsingson (三明智, 江湖人稱3爺)

原 ustarcom IPTV/OTT 事業部播控產品線技術架構溼/解決方案工程溼角色(8年), 自由職業者,

喜歡音樂(口琴,是第三/四/五屆廣東國際口琴嘉年華的主策劃人之一), 攝影與越野,

喜歡 golang 語言 (商用專案中主要用 postgres + golang )

_

題圖: 2018/12/24 香港黑白攝影展前, 與深圳影友在香港街頭

_

tsingson 寫於中國深圳

小羅號口琴音樂中心, 2019/05/11

相關文章