微服務 - Go 語言從單體服務到微服務 -設計方案篇-

作者:stark 張宇

https://juejin.cn/post/7212918993349247031

概述

微服務是一種思想,與編程語言無關,編程語言是思想下具體的一種實現方式,怎麼設計架構方案和實現主要看主要面臨的業務場景。

業務場景

主站核心業務使用的是 yaf(php)開發的,要實現 k8s + x 編程語言 自主微服務實現,受到陳皓 (左耳聽風) 的影響,我選用的編程語言是 Go,Go 語言有更強大的生態,有谷歌,k8s 作爲強大的後盾,摸着石頭過河。

設計方案

有聲微服務_Api-Gateway.png

Api 網關

提到微服務我們就聯想到 Rpc,主流微服務價格設計,微服務之間的調用都使用 Rpc,微服務也有直接用 http 實現的,Rpc 限制了開發時候的靈活性和兼容性,主要 3 點原因:

1.Http 協議是實際通信的標準,靈活性和兼容性得到了很好的市場驗證,對 Rpc 我抱有懷疑態度,在 Api 層進行權限的統一認證 (Token/Cookies) , 後期微服務體系成熟,可以統一接入 Api 網關服務,Api 網關服務是不可缺少的,全使用 Nginx 反向代理的方式,再數據統計的角度上侷限性。

  1. 控制異常,如果發生異常, Rpc 服務掛掉或者遭到網絡攻擊 / 刷請求,請求會直接打到 Rpc 上,如果有網關層,可以在 Redis 中加 Redis 鎖,把無效的網絡請求進行隔離。

數據

拆分微服務最大的兩個問題是數據的一致性性能,系統性能的瓶頸主要是因爲計算機 Cpu,內存 (memory / 內存條、cache/Cpu 的內存) 是非常快的,所有的性能問題大同小異,磁盤 I/O 往往纔是性能的瓶頸。

  1. 數據的一致性的解決辦法

模塊化拆分和遷移微服務功能,把涉及到的整塊進行遷移,可以按比重分流 / 整體功能進行,按比重分流要保留新舊數據的兼容,需要雙寫,現在的有聲業務體量小,可以整塊整塊的遷移。

  1. 性能:有聲的數據量非常小,暫時不使用 redis 緩存可能也不會造成什麼性能問題,所以我把很小的公共部分進行了緩存,主要考慮 C 端用戶的體驗。

Go 中的 Grpc 使用

Go-zero 這個框架使用 goctl 工具開發速度非常高效,對調用外部的 Grpc 服務需要做更多的兼容,這裏做一個解釋說明,protoc-gen-goprotoc-gen-go-grpc這兩個工具是 protobuf 的工具,是Go 1.5版本後新加的,這個地方饒了好大一圈。

GitHub Demo 地址 : https://github.com/grpc/grpc-go

$ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2

在有聲微服務中,是調用 UserRpc 的權限驗證部分,Go-zero 不支持,所以自己寫了一些兼容包。

  1. 首先 pb 文件生成 Pb 和 Grpc 文件
$ ll
-rw-r--r--  1 stark  staff    69K  3 20 15:51 cp_user_internal.pb.go
-rw-r--r--  1 stark  staff    34K  3 20 15:51 cp_user_internal_grpc.pb.go
  1. 調用 UserRpc 服務, 需要實現的包是客戶端部分代碼,本地需要 TLS 加密,服務才能被調用的到,grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})))是 TLS 靈魂。
package client

func Auth(Session string, Action string, Controller string, Param string) bool {
    // 1.建立鏈接
    flag.Parse()
 conn, err := grpc.Dial("testing.gongzicp.com:1443", grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})))
 if err != nil {
  log.Fatalf("did not connect: %v", err)
 }
 defer conn.Close()
 client := pb.NewUserInternalClient(conn)
 
 //2.驗證管理員權限
 resp, err := client.AdminMid(context.Background()&pb.UserInternalParams_AdminMidReq{
  Session: Session,
 })
 
 //3.驗證菜單權限
 
 auth, err := client.AdminAuth(context.Background()&pb.UserInternalParams_AdminAuthReq{
   Action:     Action,
   Controller: Controller,
   Param:      Param,
   Session:    Session,
  })
 
 //....
 
}

問題和反思

  1. 有聲服務和主站的關聯非常小, 但是也有關聯 NovelId 獲取信息的部分,Novel 屬於核心服務,可能每一個地方的需要都不少。

2.Web 端 (Ukey) 、App 安卓 / Ios(Token) 本質上是一個維度的東西,類型上應該只用戶 / 和系統管理員 2 種類型,最好是把服務類抽離出來做成單獨的服務,可能會更好一些。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/f0udYJcglPw2aWh94EJW0g