這邊寫下目前經歷過的 "真" microservice 的設計思路
我們先看一下舊的環境或狀況,假設一個 blog system 為範例,user 需要 login 的狀況,然後每篇 blog 支援 comment,還要記錄每篇的瀏覽量
- 不管 DB auth 或 OAuth2 甚至 PKCE,最終發出一個亂碼的 session_id 到 cookie 去
- user request 拿該 session_id 來對照 DB / Redis 進行登入換得 user_id,確認後得知已登入
- login 後 server return user info 丟到 web site 的 top bar 去
- user create 一篇 blog,DB 用 auto increment primary key 來做 pkey 然後 INSERT
- another user 使用 pkey 來回覆 comment
- 每篇 blog 有人 get 時下一個 redis incrby 的指令
這份設計到這樣,幾乎是所有教科書等級的教學了,所有人保證看到這份應該都不疑有他,但 ... 真的嗎?
這份目前有點問題,下面是疑問的部分
這份目前有點問題,下面是疑問的部分
- frontend / app 需要戳 server 才知道該 session_id 是否過期,且 DB / Redis 才有這把 session_id 與 user_id 之間的對照
- 需要 login 後才能得到 user info 即使每次都是一樣的
- blog 本身 pkey 會連號
- 每次 read 都會需要 trigger write!?
這其實說明幾件事情,有點麻煩,pkey 本身連號同時也代表了 DB table 需在 INSERT 的時候進行 lock,這將會是一個 globle effect,且通常換得 user_id 後會需要和 DB 重新 query,就幾乎無法製作分散式 DB,最後的在某個 path 進行 GET 時,戳了這世界最快的 redis 一下 ... 但戳這下會造成內網連線過多,且事實上也造成了效能瓶頸,因為戳了也會有 latency
這整票看似無解,但 ... 新時代有新的解法,我所感到漂亮的解法:)
========== 以下是手術過程 ==========
- 把 session_id 改為 JWT 並把部分 info 丟到 JWT 內去
- 前端可以弄個 JWT reader 就能知道是否 expired 不用戳 server 才知道
- user basic info 在 JWT 內有,類似 name & avatar 不用戳 server 才知道
- pkey 從 int 改為 rand UUID(包含 user_id)
- table(data) relation 重點是 relation 而非 pkey 的 format
- 不用 auto increment 不會有 global effect 所以 INSERT 會變快且平行處理
- 不用管連號的問題,而你也不該用 pkey 當作 sorting / ordering 的依據,用別的 column 會更好些,類似 nano sec timestamp (NOW) 也行
- 瀏覽量使用 background job 來執行,建立類似 5 sec 一次的 batch update
- 也可以用 logger parsing 的方式完成,如果有專用 logger server 的話
- 任何東西 batch update (batch INSERT) 永遠是最快的,包括 redis 的 mset 系列
- 大幅減少 latency 且保持回應的最高速
- 這樣的 logger / tracer 才不會影響到正常流程的速度
這些是基本思維了,保證瞬間提升 N 個量級,且 ... 我們可以安全地使用 microservice 架構了
舊時代的做法轉成 microservice 架構的問題會是 session <=> user_id 的解構部分,所以每個 sub service 都需要連 user table ... 因為要檢查 user_id 是否存在,他的 permission 有啥,有的沒的
但新時代的 microservice 只需要拿 JWT 為底時,不用驗證這個 user_id (通常也為 UUID 在 JWT 內) 是否存在,因為這 JWT 當初是自己簽的,只要簽章正確,則這個 user_id 一定存在,且一定信任 JWT 內的 permission list / user info 等等 (寫在 JWT payload fields 內) 所以整個系統就能完全解構,sub service 隨便寫,甚至建議每個 sub service 都有自己獨立的一套 DB 的( microservice 的真義 )
如果還要更安全些,能前置個 auth service 來做 JWT exchange,類似從 external JWT 轉換成 internal JWT,之後所有下級的 sub service 只吃 internal JWT 就能保障所有安全的部分了,這樣 external JWT 也不用流出太多 internal info,internal JWT 可以在 auth service 塞更多東西進去給 sub service 使用,這樣 sub service 也不用額外去 query user info 等等
剩下就是 batch 處理的哲學了,MQ + worker / cron background job / aggregate 基本上都是新時代的標準了,不管如何都用 batch 處理的話,一樣的 latency 減少效能增加,大家都開心,傷心的只有多一點點記憶體,何樂不為呢 ...
anyway 推薦給大家 : )
沒有留言:
張貼留言