服務發現consul示例
一.服務發現簡介
在微服務開發和部署過程中,每個服務都執行在一個獨立的程序中,服務於服務之間通過輕量級的通訊機制進行溝通(如RESTful API),那麼怎樣管理這些服務呢,當用戶傳送一個請求,應該去請求哪個服務來滿足使用者的請求呢?這時候就用到了服務發現功能.服務發現相當於一個註冊中心,它記錄了分散式系統中全部的服務資訊,以便其他服務能快速找到已註冊的服務,其作用類似於中介.
流程描述:
1. 每個服務啟動時都會將自己的埠,地址,服務名等資訊在服務發現功能中註冊,當然為了服務的穩定性一個功能可能開起了多個服務,如上圖的登入功能;
2. 當客戶端向服務發現發出請求時,服務發現會找到對應請求的註冊資訊返回給客戶端,客戶端就可以拿著註冊資訊訪問想要的服務.
服務發現的工具有很多,如:zookeeper,etcd,eureka,consul等,各有優劣,大家可以根據自己的需求做選擇,這裡主要介紹consul.
二.consul安裝及介紹
1.安裝
官網直接下載: https://www.consul.io/downloads
百度網盤: https://pan.baidu.com/s/1NLEskDQOtipX5BB9v4HeoA 提取碼: v09o
2.consul特性
服務發現(Service Discovery: Consul提供了通過DNS或者HTTP介面的方式來註冊服務和發現服務.一些外部的服務通過Consul很容易的找到它所依賴的服務.
健康檢查(Health Checking: Consul的Client可以提供任意數量的健康檢查,既可以與給定的服務相關聯(“webserver是否返回200 OK”),也可以與本地節點相關聯(“記憶體利用率是否低於90%”)。操作員可以使用這些資訊來監視叢集的健康狀況,服務發現元件可以使 用這些資訊將流量從不健康的主機路由出去.
Key/Value儲存: 應用程式可以根據自己的需要使用Consul提供的Key/Value儲存。 Consul提供了簡單易用的HTTP介面,結合其他工具可以實現動態配置、功能標記、領袖選舉等等功能.
安全服務通訊: Consul可以為服務生成和分發TLS證書,以建立相互的TLS連線。意圖可用於定義允許哪些服務通訊。服務分割可以很容易地進行管理,其目的是可以實時更改的,而不是使用複雜的網路拓撲和靜態防火牆規則.
多資料中心: Consul支援開箱即用的多資料中心. 這意味著使用者不需要擔心需要建立額外的抽象層讓業務擴充套件到多個區域.
3.consul常用命令
consul agent
-
- -bind=0.0.0.0 指定consul所在機器的IP地址
- -http-port=8500 consul使用web訪問時的預設埠.預設值: 8500
- -client=127.0.0.1 指定哪些機器可以訪問consul.指定為: 0.0.0.0 所有機器均可訪問
- -config-dir=/etc/consul.d/ 主動註冊服務時讀取的配置路徑,自定義
- -dat-dir=/tmp/consul/ 註冊過的服務資訊儲存路徑,自定義
- -dev 開發者模式,直接以預設配置啟動consul
- -node=hostname 服務發現的名字
- -rejoin consul啟動時加入到consul叢集
- -server 以服務方式開起consul,允許其他consul連線到此服務,形成叢集.
- -ui 可以通過使用web來檢視服務發現詳情
三.consul主動註冊服務
1.consul啟動
consul agent -dev -server -client=0.0.0.0 -config-dir=/etc/consul.d/ -data-dir=/tmp/consul/ -node=n1 -ui -bind=192.168.79.134
啟動成功時會看到下邊資訊;
==> Starting Consul agent... Version: 'v1.5.2' Node ID: '6738f862-b9ef-3fc0-115a-a0c9778847b6' Node name: 'n1' Datacenter: 'dc1' (Segment: '<all>') Server: true (Bootstrap: false) Client Addr: [0.0.0.0] (HTTP: 8500, HTTPS: -1, gRPC: 8502, DNS: 8600) Cluster Addr: 192.168.79.134 (LAN: 8301, WAN: 8302) Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false, Auto-Encrypt-TLS: false ==> Log data will now stream in as it occurs: 2022/03/10 09:52:52 [DEBUG] tlsutil: Update with version 1 2022/03/10 09:52:52 [DEBUG] tlsutil: OutgoingRPCWrapper with version 1 2022/03/10 09:52:52 [INFO] raft: Initial configuration (index=1): [{Suffrage:Voter ID:6738f862-b9ef-3fc0-115a-a0c9778847b6 Address:192.168.79.134:8300}] 2022/03/10 09:52:52 [INFO] raft: Node at 192.168.79.134:8300 [Follower] entering Follower state (Leader: "") 2022/03/10 09:52:52 [INFO] serf: EventMemberJoin: n1.dc1 192.168.79.134 2022/03/10 09:52:52 [INFO] serf: EventMemberJoin: n1 192.168.79.134 2022/03/10 09:52:52 [DEBUG] tlsutil: OutgoingTLSConfigForCheck with version 1 2022/03/10 09:52:52 [INFO] consul: Handled member-join event for server "n1.dc1" in area "wan" 2022/03/10 09:52:52 [INFO] consul: Adding LAN server n1 (Addr: tcp/192.168.79.134:8300) (DC: dc1) 2022/03/10 09:52:52 [DEBUG] agent/proxy: managed Connect proxy manager started 2022/03/10 09:52:52 [WARN] agent/proxy: running as root, will not start managed proxies 2022/03/10 09:52:52 [INFO] agent: Started DNS server 0.0.0.0:8600 (udp) 2022/03/10 09:52:52 [INFO] agent: Started DNS server 0.0.0.0:8600 (tcp) 2022/03/10 09:52:52 [INFO] agent: Started HTTP server on [::]:8500 (tcp) 2022/03/10 09:52:52 [INFO] agent: started state syncer ==> Consul agent running!
我的虛擬機器ip為192.168.79.134,通過訪問http://192.168.79.134:8500可以看到所有註冊資訊:
2.主動註冊服務
現在我們要主動註冊一個服務,在1中的啟動命令中指定的配置路徑為/etc/consul.d/,所以我們在此目錄下建立一個json檔案並寫入服務配置:
root@master ~ > cd /etc/consul.d/
root@master /etc/consul.d > vim web.josn
{ "service": { "name": "test", # 服務名稱 "tags": ["IT"], # 標籤(可新增多個) "port": 5000, # 埠 } }
3. 儲存重啟consul服務
看到一個叫test的服務已經被註冊成功.
4.健康檢查
consul不僅統計所有服務的資訊,還可以定時檢查服務是否健康,保證向客戶端提供的服務是可以正常請求的服務.consul健康檢查有五種方式:
-
-
- script: 通過外部指令碼檢查
- http: 基於http請求,定時向服務傳送心跳包,如果沒有正常返回則判斷為服務不健康
- tcp: 定時和服務建了tcp連線,連線成功表示服務健康
- grpc: 基於grpc協議判定
- docker: 結合script使用,通過判斷容器是否正常執行判定服務的健康性
-
我們使用http來判斷2中註冊的服務是否正常,開啟2中建立的web.json檔案新增check屬性:
{ "service": { "name": "test", "tags": ["IT"], "port": 5000, "check": { "id": "mytest", "name": "consulTest", # 健康檢查服務名稱 "http": "http://192.168.79.134:5000", # 服務地址 "interval": "5s", # 請求週期 "timeout": "1s" # 超時時長 } } }
5.重啟consul服務
root@master /etc/consul.d > consul reload # 重啟consul服務
看到剛剛註冊的服務Health下有個紅色的×,因為我們只是註冊了一個服務,並沒有真正啟動,所以在consul請求"http://192.168.79.134:5000"時並未收到回覆,所以判定此服務為不健康的,感興趣的可以自己啟動一個服務看consul有什麼變化.
四. protobuf+grpc+consul
現在我們使用go語言,結合protobuf和grpc進行一個服務註冊:
protobuf實現grpc服務參考上一篇文章,這裡就不再細講: go使用grpc通訊示例
上文中已經通過proto檔案建立了grpc服務,並實現了server端和客戶端,接下來我們要做的就是引入服務發現功能.
1.啟動consul服務:
這裡我們直接使用預設配置啟動
命令: consul agent -dev -client 0.0.0.0
2.grpc服務端註冊:
func main() { config := api.DefaultConfig() // 初始化consul配置 config.Address = "192.168.79.134:8500" // 因為我的consul服務在虛擬機器中,grpc服務在windows中,所以必須制定consul地址 client, err := api.NewClient(config) // 初始化consul,將上邊初始化的配置傳入 if err != nil { fmt.Println(err) return } // 服務註冊配置 reg := api.AgentServiceRegistration{ Name: "grpcTest", // 服務名稱 Tags: []string{"grpc"}, // 標籤 Port: 8080, Address: "192.168.1.51", // 配置健康檢查服務 Check: &api.AgentServiceCheck{ CheckID: "grpcCheck", Name: "IT", GRPC: "192.168.1.51:8080", // 使用grpc協議檢查 Interval: "5s", Timeout: "1s", }, } err = client.Agent().ServiceRegister(®) // 攜帶配置註冊服務 if err != nil { fmt.Println(err) return } ///////////////////////////////////////////////////////////////// // 初始化一個grpc物件 // 註冊服務 // 設定監聽 }
3. grpc客戶端:
func main() { consulConfig := api.DefaultConfig() // 初始化配置 consulConfig.Address = "192.168.79.134:8500" // 指定consul地址 consulClient, err := api.NewClient(consulConfig) // 獲取consul操作物件 if err != nil { fmt.Println("client, api.newclient err:", err) return } // 獲取服務地址 // 引數: service: 訪問的服務名稱; tag: 訪問的服務標籤; passingOnly: 是否必須通過健康檢查,一般用true; q: 其它想獲取的服務資訊,沒用用nil // 返回值: s[]*ServiceEntry: services切片(一個功能可能開起了多個服務,返回服務列表客戶端可通過負載均衡演算法選擇最優服務,此處不做詳解) // *QueryMeta 如果請求引數中q有其他資訊,可通過QueryMeta獲取 // error 錯誤資訊 services, _, err := consulClient.Health().Service("grpcTest", "grpc", true, nil) // 拼接出返回的服務地址:埠 addr := services[0].Service.Address + ":" + strconv.Itoa(services[0].Service.Port) /////////////////////////////////////////////////////////////////////////////////////////// // 連線grpc服務, 新增證書,使用consul返回的地址 clientConn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { fmt.Println(err) return } // 初始化grpc客戶端 // 呼叫方法 }
4.測試:
-
- 啟動grpc服務端
- 啟動grpc客戶端
- 網頁檢視consul服務
看到一個名為grpcTest的服務已經註冊完成,並且Health Checks下為綠色,表示服務健康,客戶端啟動後返回結果和上文中返回的結果也是一樣的,所以說在使用了服務註冊後用戶體驗上並沒有什麼太大的變化,但在程式實現上卻有很大的區別.