python api、grpc consul 服务注册发现使用记录

consul 是一个服务注册、服务发现平台,可以接受api 或grpc 服务连接, 具有健康检查功能,consul的作用是将多个相同服务的服务器ip+端口收集为一个服务进行管理

consul 安装配置

使用docker 安装consul

docker pull consul

docker run -d -p 8500:8500 -p 8300:8300 -p 8301:8301 -p 8302:8302 -p 8600:8600/udp  
consul consul agent  -dev -client=0.0.0.0

8500 端口是用于服务注册的端口,8600是用于api网关进行服务发现的端口,其余参数可自行百度

grpc服务注册consul
from dataclasses import dataclass, field

import aiohttp
import redis
import consul
import requests
from common.aiologer import logger


@dataclass()
class RegisterConsul:
    host: str
    port: int
    connection: consul.Consul = field(init=False)

    # 等到实例化对象的时候自动调用,类似于 __init__ 方法
    def __post_init__(self):
        self.connection = consul.Consul(host=self.host, port=self.port)
        self.redis_register_key = ""

    def register(self, name: str, service_id: str, address: str, port: int, tags: list, redis_config: dict) -> bool:
        check = {
            "GRPC": "{}:{}".format(address, port),
            "GRPCUseTLS": False,
            "Timeout": "5s",
            "Interval": "5s",
            "DeregisterCriticalServiceAfter": "15s"
        }
        redis_conn = redis.Redis(host=redis_config["host"], port=redis_config["port"],
                                 password=redis_config["password"], db=redis_config["db"])

        # 防止统一服务器上监听同一端口的服务重复注册
        if self.prevent_re_register(address, port, redis_conn):
            return True

        logger.info("正在注册服务")
        ret = self.connection.agent.service.register(name=name, service_id=service_id, address=address
                                                     , port=port, tags=tags, check=check)
        redis_conn.delete(self.redis_register_key)
        return ret

    # 防止重复注册
    def prevent_re_register(self, address, port, redis_conn) -> bool:

        self.redis_register_key = "register_server_" + address + ":" + str(port)
        # redis 分布式锁防止重复注册
        register_lock_ret = redis_conn.set(self.redis_register_key, 1, nx=True, ex=60)
        if register_lock_ret is None:
            logger.info("redis_register_key: 服务已注册")
            return True

        filter_server = self.filter_server({"Address": address, "Port": port})
        # 查询服务是否存在,防止重复注册
        if filter_server:
            for _, v in filter_server.items():
                if v["Address"] == address and v["Port"] == port:
                    logger.info("filter_server: 服务已注册")
                    return True
        return False

    def del_server(self, server_id: str) -> None:
        return self.connection.agent.service.deregister(server_id)

    def get_all_server(self) -> dict:
        return self.connection.agent.services()

    def filter_server(self, filter: dict) -> dict:
        url = f"http://{self.host}:{self.port}/v1/agent/services?"
        params_list = []
        for k, v in filter.items():
            params_list.append(f"{k}={v}")

        url += "&".join(params_list)
        return requests.get(url).json()

    # 通过srv name 获取服务的ip + 端口
    async def get_host_port_by_srv_name(self, srv_name):
        url = f"http://{self.host}:{self.port}/v1/catalog/service/{srv_name}"
        # 异步获取srv name 的服务ip、端口 列表
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                data = await response.json()
        return data

grpc 注册健康检查,

	from common.grpc_health.v1 import health, health_pb2_grpc, _async

    grpc_server = grpc.aio.server()
    grpc_server.add_insecure_port("0.0.0.0:{}".format(port))

    # 注册用户信息查询grpc 服务
    user_info_pb2_grpc.add_UserServicer_to_server(user_info_server, grpc_server)

    # 注册grpc 健康检查服务
    health_pb2_grpc.add_HealthServicer_to_server(_async.HealthServicer(), grpc_server)

grpc 健康检查模块下载: grpc健康检查

api 注册consul
from dataclasses import dataclass, field

import aiohttp
import redis
import consul
import requests

from common.aiologger import logger


@dataclass()
class RegisterConsul:
    host: str
    port: int
    connection: consul.Consul = field(init=False)

    # 等到实例化对象的时候自动调用,类似于 __init__ 方法
    def __post_init__(self):
        self.connection = consul.Consul(host=self.host, port=self.port)
        self.redis_register_key = ""
        self.aiohttp_session = None

    def register(self, name: str, service_id: str, address: str, port: int, tags: list, redis_config: dict) -> bool:
        check = consul.Check().tcp(address, port, '5s', '5s', '15s')
        redis_conn = redis.Redis(host=redis_config["host"], port=redis_config["port"],
                                 password=redis_config["password"], db=redis_config["db"])

        # 防止统一服务器上监听同一端口的服务重复注册
        if self.prevent_re_register(address, port, redis_conn):
            return True

        logger.info("正在注册服务")
        ret = self.connection.agent.service.register(name=name, service_id=service_id, address=address
                                                     , port=port, tags=tags, check=check)
        redis_conn.delete(self.redis_register_key)
        return ret

    # 防止重复注册
    def prevent_re_register(self, address, port, redis_conn) -> bool:

        self.redis_register_key = "register_server_" + address + ":" + str(port)
        # redis 分布式锁防止重复注册
        register_lock_ret = redis_conn.set(self.redis_register_key, 1, nx=True, ex=60)
        if register_lock_ret is None:
            return True

        filter_server = self.filter_server({"Address": address, "Port": port})
        # 查询服务是否存在,防止重复注册
        if filter_server:
            for _, v in filter_server.items():
                if v["Address"] == address and v["Port"] == port:
                    return True
        return False

    def del_server(self, server_id: str) -> None:
        return self.connection.agent.service.deregister(server_id)

    def get_all_server(self) -> dict:
        return self.connection.agent.services()

    def filter_server(self, filter: dict) -> dict:
        url = f"http://{self.host}:{self.port}/v1/agent/services?"
        params_list = []
        for k, v in filter.items():
            params_list.append(f"{k}={v}")

        url += "&".join(params_list)
        return requests.get(url).json()

    # 通过srv name 获取服务的ip + 端口
    async def get_host_port_by_srv_name(self, srv_name):
        url = f"http://{self.host}:{self.port}/v1/catalog/service/{srv_name}"
        # 异步获取srv name 的服务ip、端口 列表
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                data = await response.json()
        return data

api就不需要健康检查模块了,consul会自动调用http接口

效果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值