經過對gRPC的介紹咱們知道,當正常啓動服務後,咱們只須要知道ip,port就能夠進行gRPC的鏈接。能夠想到,這種方式並不適合用於線上環境,由於這樣直連的話就失去了擴展性,當須要多機部署的時候,就沒法在線上環境直接使用,並且當線上項目鏈接的那臺服務器宕了的話,整個項目也會出錯,這並非咱們想要的結果。
因而,咱們須要一個服務註冊與發現的機制。也就是說當咱們的rpc服務啓動的時候註冊到另外一個服務器,而後客戶端鏈接的時候去查找對應的服務,獲得相應的ip,port,而後就能夠順利進行鏈接了。這種方式也就是服務註冊與發現,目前有zoomkeper, consul, 由於本身對zookeeper不熟悉,因此這裏選用consul。整個流程如圖所示html
經過docker
運行以下命令:
docker run -d -p 8500:8500 consul consul agent -data-dir=/consul/data -config-dir=/consul/config -dev -client=0.0.0.0 -bind=0.0.0.0
python
經過其它方式
安裝方式參考https://www.consul.io/intro/getting-started/install.html
安裝完後運行:
consul agent --data-dir . -server -ui -bootstrap -bind=127.0.0.1
docker
不管哪一種方式,運行完以後在瀏覽器中打開 http://127.0.0.1:8500/ui, 能夠看到以下內容
json
已以前介紹的gRPC代碼爲基礎,咱們加入服務註冊部分(注:本人環境爲python3, 須要python2的,本身進行修改)bootstrap
import time import grpc import consul import json from concurrent import futures import test_pb2_grpc import test_pb2 def test(request, context): # 實際調用到的函數 json_response = test_pb2.JSONResponse() json_response.rst_string = json.dumps({"ret":"Hi gRPC"})# 構造出proto文件中定義的返回值格式 return json_response class OrderHandler(test_pb2_grpc.OrderHandlerServicer): def create_order(self, request, context): return test(request, context) def register(server_name, ip, port): c = consul.Consul() # 鏈接consul 服務器,默認是127.0.0.1,可用host參數指定host print(f"開始註冊服務{server_name}") check = consul.Check.tcp(ip, port, "10s") # 健康檢查的ip,端口,檢查時間 c.agent.service.register(server_name, f"{server_name}-{ip}-{port}", address=ip, port=port, check=check) # 註冊服務部分 print(f"註冊服務{server_name}成功") def unregister(server_name, ip, port): c = consul.Consul() print(f"開始退出服務{server_name}") c.agent.service.deregister(f'{server_name}-{ip}-{port}') def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) test_pb2_grpc.add_OrderHandlerServicer_to_server(OrderHandler(), server) server.add_insecure_port('[::]:{}'.format(12006)) register("order_server", "0.0.0.0", 12006) server.start() try: while True: time.sleep(186400) except KeyboardInterrupt: unregister("order_server", "0.0.0.0", 12006) server.stop(0) serve()
要運行此服務須要先安裝 python-consul pip install python-consul
運行此服務,在瀏覽器中會出現咱們剛剛註冊的服務,和可用節點,健康信息,如圖瀏覽器
當使用ctrl+c
退出服務時,會取消註冊。也就是會從consul列表裏消失。
注意: 當健康檢測失敗時,並不意味着服務有問題,僅表示consul服務器和對應的rpc服務的端口連不上而已服務器
客戶端須要向consul服務器請求,獲得可用的rpc服務的ip,端口,在進行鏈接,咱們仍是基於以前的客戶端代碼進行修改,完整代碼以下:tcp
import grpc from dns import resolver from dns.exception import DNSException import test_pb2_grpc import test_pb2 # 鏈接consul服務,做爲dns服務器 consul_resolver = resolver.Resolver() consul_resolver.port = 8600 consul_resolver.nameservers=["127.0.0.1"] def get_ip_port(server_name): '''查詢出可用的一個ip,和端口''' try: dnsanswer = consul_resolver.query(f'{server_name}.service.consul', "A") dnsanswer_srv = consul_resolver.query(f"{server_name}.service.consul", "SRV") except DNSException: return None, None return dnsanswer[0].address, dnsanswer_srv[0].port ip, port = get_ip_port("order_server") channel = grpc.insecure_channel(f"{ip}:{port}") stub = test_pb2_grpc.OrderHandlerStub(channel) # 要完成請求須要先構造出proto文件中定義的請求格式 ret = stub.create_order(test_pb2.OrderRequest(phone="12990", price="50")) print(ret.rst_string)
至此,咱們已經搭建好了一套簡單服務註冊-發現系統。固然consul的功能遠不止這一點,它還支持分佈式,多節點部署。須要瞭解更多,能夠去官網作進一步瞭解。分佈式
ctrl+c
信號,在實際中,服務會由於一些奇怪的問題宕掉,而此時,該節點信息會一直在consul裏面,除非手動註銷,因此須要捕獲全部異常信號。