近一段時間在學習和實踐用go來實現微服務架構的開發,本文來記錄下什麼狀況下要使用微服務架構,分析下利弊。而且用grpc初步實現微服務的模型。java
在 Web 應用程序發展的早期,大部分工程是將全部的服務端功能模塊打包成單個巨石型應用,最終會造成以下圖所示的架構。golang
優勢:算法
缺點:數據庫
隨着單體應用愈來愈龐大,單體架構中不一樣業務模塊的差別就會顯現,將大應用拆分紅一個個單體結構的應用。垂直分層是一個典型的對複雜系統進行結構化思考和抽象聚合的通用性方法。編程
優勢:windows
缺點:網絡
微服務是一種小型的SOA架構(面向服務的架構),其理念是將業務系統完全地組件化和服務化,造成多個能夠獨立開發、部署和維護的服務或者應用的集合,以應對更快的需求變動和更短的開發迭代週期。架構
優勢:併發
缺點:負載均衡
微服務特色:
近幾年,隨着微服務架構的火熱,也誕生了不少微服務框架,如 Java 語言的 Spring Cloud、Go 語言的 Go Kit 和 Go Micro 以及 Node.js 的 Seneca。充分說明了微服務架構的火熱態勢。雖然微服務架構的實踐落地獨立於編程語言,可是 Go 語言在微服務架構的落地中仍有其獨特的優點。所以,Go 語言的微服務框架也相繼涌現,各方面都較爲優秀的有 Go Kit 和 Go Micro 等。
Go 語言十分輕量,運行效率極高,原生支持併發編程,相較其餘語言主要有如下優點:
遠程過程調用(Remote Procedure Call)是一個計算機通訊協議。該協議容許運行於一臺計算機的程序調用另外一臺計算機的子程序。簡單地說就是能使應用像調用本地方法同樣的調用遠程的過程或服務。
Protobuf 是由 Google 開源的消息傳輸協議,用於將結構化的數據序列化、反序列化經過網絡進行傳輸。Protobuf 首先解決的是如何在不一樣語言之間傳遞數據的問題,目前支持的編程語言有C++、Java、Python、Objective-C、C#、JavaScript、Ruby、Go、PHP 等。
對比XML、JSON
優勢:XML、JSON 也能夠用來存儲此類結構化數據,可是使用ProtoBuf表示的數據能更加高效,而且將數據壓縮得更小。(比XML小3-10倍,快20-100倍)
缺點:因爲是二進制,沒法直接閱讀
gRPC是由Google公司開源的一款高性能的遠程過程調用(RPC)框架。
grpc結合protobuf實現遠程服務調用的使用步驟展現:
syntax = "proto3"; package services; //訂單請求參數 message OrderRequest { string orderId = 1; int64 timeStamp = 2; } //訂單信息 message OrderInfo { string OrderId = 1; string OrderName = 2; string OrderStatus = 3; } //訂單服務service定義 service OrderService{ rpc GetOrderInfo(OrderRequest) returns (OrderInfo); }
protoc --go_out=plugins=grpc:. *.proto
func (os \*OrderServiceImpl) GetOrderInfo(ctx context.Context, request \*OrderRequest) (\*OrderInfo, error) { fmt.Println("收到請求訂單號:", request.OrderId) return &OrderInfo{OrderId: request.OrderId, OrderName: "訂單名稱", OrderStatus: "已經支付"}, nil }
addr :\= "127.0.0.1:8972" rpcServer :\= grpc.NewServer() services.RegisterOrderServiceServer(rpcServer, new(services.OrderServiceImpl)) listen, err :\= net.Listen("tcp", addr) if err != nil { log.Fatalf("啓動網絡監聽失敗 %v\\n", err) } //啓動服務 if err :\= rpcServer.Serve(listen); err != nil { fmt.Println("啓動錯誤", err) } else { fmt.Println("服務開啓") }
addr :\= "127.0.0.1:8972" conn, err :\= grpc.Dial(addr, grpc.WithInsecure()) if err != nil { log.Fatalf("鏈接GRPC服務端失敗 %v\\n", err) } defer conn.Close() //實例客戶端 orderServiceClient :\= sOrder.NewOrderServiceClient(conn) //模擬訂單號 orderId :\= "order\_" + strconv.Itoa(time.Now().Second()) //組織請求體 orderRequest :\= &sOrder.OrderRequest{OrderId: orderId, TimeStamp: time.Now().Unix()} //rpc調用GetOrderInfo orderInfo, err :\= orderServiceClient.GetOrderInfo(context.Background(), orderRequest) if orderInfo != nil { fmt.Println(orderInfo.GetOrderId(), orderInfo.GetOrderName(), orderInfo.GetOrderStatus()) return orderInfo.GetOrderStatus() } else { return "訂單服務讀取失敗" }
在微服務架構中,通常每個服務都是有多個拷貝,來保證高可用。一個服務隨時可能下線,也可能應對臨時訪問壓力增長新的服務節點。這就出現了新的問題:
service啓動時向註冊中心註冊
註冊中心和service之間會保持心跳檢查,來維護註冊表裏的service是否存活
client向註冊中心獲取可用的service
Consul 是 HashiCorp 公司推出的開源工具,用於實現分佈式系統的服務發現與配置。Consul 使用 Go 語言編寫,所以具備自然可移植性(支持Linux、windows和Mac OS X)。Consul 內置了服務註冊與發現框架、分佈一致性協議實現、健康檢查、Key/Value 存儲、多數據中心方案,再也不須要依賴其餘工具,使用起來也較爲簡單。
etcd 是用 go 開發的,出現的時間並不長,不像 zookeeper 那麼悠久和有名,可是前景很是好。etcd 是由於 kubernetes 而被人熟知的,kubernetes 的 kube master 使用 etcd 做爲分佈式存儲獲取分佈式鎖,這爲 etcd 的強大作了背書。etcd 使用 RAFT 算法實現的一致性,比 zookeeper 的 ZAB 算法更簡單
zookeeper 起源於 Hadoop,後來進化爲 Apache 的頂級項目。如今已經被普遍使用在 Apache 的項目中,例如 Hadoop,kafka,solr 等等。是用java 開發的,部署的時候要裝JAVA環境。歷史悠久,功能豐富,因此比較重,易用性不如以上2個。
我暫時選用了etcd來作註冊中心,如下展現加入註冊中心後的grpc調用代碼。
package main import ( "fmt" "google.golang.org/grpc" "goshare/etcd" "grpc-service/services" "log" "net" ) func main() { addr := "127.0.0.1:8972" rpcServer := grpc.NewServer() services.RegisterOrderServiceServer(rpcServer, new(services.OrderServiceImpl)) listen, err := net.Listen("tcp", addr) if err != nil { log.Fatalf("啓動網絡監聽失敗 %v\n", err) } //etcd服務註冊 reg, err := etcd.NewService(etcd.ServiceInfo{ Name: "mirco.service.order", IP: addr, //grpc服務節點ip }, []string{"172.24.132.232:2379"}) // etcd的節點ip if err != nil { log.Fatal(err) } go reg.Start() //啓動服務 if err := rpcServer.Serve(listen); err != nil { fmt.Println("啓動錯誤", err) } else { fmt.Println("服務開啓") } }
r := etcd.NewResolver([]string{"172.24.132.232:2379"}, "mirco.service.order") resolver.Register(r) addr := fmt.Sprintf("%s:///%s", r.Scheme(), "") //addr := "127.0.0.1:8972" fmt.Println("addr", addr) conn, err := grpc.Dial(addr, grpc.WithInsecure()) if err != nil { log.Fatalf("鏈接GRPC服務端失敗 %v\n", err) } defer conn.Close() orderServiceClient := sOrder.NewOrderServiceClient(conn) orderId := "order_" + strconv.Itoa(time.Now().Second()) orderRequest := &sOrder.OrderRequest{OrderId: orderId, TimeStamp: time.Now().Unix()} orderInfo, err := orderServiceClient.GetOrderInfo(context.Background(), orderRequest) if orderInfo != nil { fmt.Println(orderInfo.GetOrderId(), orderInfo.GetOrderName(), orderInfo.GetOrderStatus()) return orderInfo.GetOrderStatus() } else { return "訂單服務讀取失敗" }
以上就實現了註冊中心來作服務註冊和發現,咱們測試效果的時候能夠啓用2個service,一個監聽8972,一個監聽8973。client經過註冊中心(172.24.132.232:2379)來作服務發現,當2個service其中任何一個關閉,咱們的服務依然能正常提供服務,實現了高可用。
tips:另外推薦你們本人蔘與的而且以爲不錯的學習渠道
一個是拉鉤教育上的《Go微服務實戰38講》98元。
另外一個是58沈劍的《架構師訓練營》399元。微服務對架構知識體系由必定要求,這個課程是沈老師10多年的架構經驗成體系的整理,能夠幫助咱們從簡到深的理解架構層面的知識。另外若是不花錢報課,每週基本都有免費的互聯網架構直播課,通常1個多小時,都是乾貨知識。