厦门网站制作开发收费,wordpress 优缺点,中国石化工程建设有限公司怎么样,wordpress 漏洞攻击上一次我们介绍了 Ocelot 网关的基本用法。这次我们开始介绍服务注册发现组件 Consul 的简单使用方法。服务注册发现首先先让我们回顾下服务注册发现的概念。在实施微服务之后#xff0c;我们的调用都变成了服务间的调用。服务间调用需要知道IP、端口等信息。再没有微服务之前… 上一次我们介绍了 Ocelot 网关的基本用法。这次我们开始介绍服务注册发现组件 Consul 的简单使用方法。服务注册发现首先先让我们回顾下服务注册发现的概念。在实施微服务之后我们的调用都变成了服务间的调用。服务间调用需要知道IP、端口等信息。再没有微服务之前我们的调用信息一般都是写死在调用方的配置文件里当然这话不绝对有些公司会把这些信息写到数据库等公共的地方以方便维护。又由于业务的复杂每个服务可能依赖N个其他服务如果某个服务的IP端口等信息发生变更那么所有依赖该服务的服务的配置文件都要去修改这样显然太麻烦了。有些服务为了负载是有个多个实例的而且可能是随时会调整实例的数量。如果每次调整实例数量都要去修改其他服务的配置并重启那太麻烦了。为了解决这个问题业界就有了服务注册发现组件。假设我们有服务A需要调用服务B并且有服务注册发现组件R。整个大致流程将变成大噶3部服务B启动向服务R注册自己的信息服务A从服务R拉取服务B的信息服务A调用服务B有了服务注册发现组件之后当修改A服务信息的时候再也不用去修改其他相关服务了。ConsulConsul 是 HashiCorp 公司推出的一套服务注册发现工具。它使用 golang 编写并且开源。由于使用 golang 的缘故所以它天生跨平台而且部署简单。它带有 web 管理后台方便用户查看维护 Consul 集群。其实除了服务注册发现功能Consul 还支持 Key/Value 存储可以当一个简单的配置中心使用。架构上面是 Consul 官网上画的架构图。从图上可以看到 Consul 天生支持多数据中心部署。每个数据中心内部有多个 Consul 节点。Consul 的节点分为2种。ServerServer 模式的节点是真正意义上集群的节点。它通过RAFT算法实现CAP里的CA。当Leader Server 挂掉的时候会自动选举出新的 Leader 使集群继续正常工作。ClientClient 模式的节点虽然也叫节点但是它并不会持久化数据不维持状态它仅仅是转发客户端的请求给后面的 Server 节点同时负责注册到该 client 节点的服务的健康检测。它非常轻量级按照 Consul 的说法最好是每个服务都配一个 client 。为什么要有client模式的节点我初看 Consul 这套架构的时候觉得很奇怪为什么要在 Server 节点跟真正的服务之间插入一层 client 模式的节点。按照按照 Consul 的说法还得每个服务配一个 client 节点。经过思考说说我的一些看法。在这个模式下服务不在关心真正的集群在哪集群的节点有哪些只需要知道这个伴随的 client 节点的地址就行了。通过这个 client 节点去感知到真正可用的 server 节点所有跟 server 节点的交互全部交给 client 节点代理去完成这就简化了服务跟 consul 交互的难度。还有一个好处是服务的健康检测由 client 节点负责在一定程度上减轻了 server 节点的压力。当然这也会带来一个问题那就是如果 client 挂了那么服务可能就连不上 Consul 集群了因为对于服务来说这个 client 节点相当于是单点的。使用 docker 运行 Consuldocker run -p 8500:8500 --nameconsulserver consul agent -server -bootstrap -client0.0.0.0 -ui -node0
使用 docker 命令运行初始化一个 consul 的 server 模式的节点。-server 启动为Server模式-bootstrap 设置为启动模式这是第一个server节点等待其它节点的加入-client 指定可以访问的客户端IP 。-ui 开启管理界面-node 节点的名字docker run -d --nameconsulserver1 consul agent -server -node1 -join172.17.0.2
有了第一个节点我们可以开始创建更多的 Server 节点来构造集群。Consul 推荐至少3个 Server 来组建集群。上面的 docker 命令表示启动第二个 Server 然后加入第一个节点构造的集群。-join 加入某个集群这里的 IP 为第一个启动的节点的内网 IP 。可以通过 docker exec XXX consul members 命令查看。后面会演示。docker run --nameconsulclient0 -e consul agent -client0.0.0.0 -nodeclient0 -retry-join172.17.0.2
我们有了 Server 集群现在可以开始建立 Consul 的 client 节点然后加入集群。启动 Consul client 的命令跟启动 Consul server 的差不多。去掉了 -server 就代表这个 agent 为 client 模式。使用 docker-compose 运行 Consul上面分步骤演示了如何使用 docker 命令来运行 Consul 集群。一行行敲还是太麻烦为了简化部署这里整理成了 docker-compose 启动文件。version: 3.9
services:consulserver1:image: consul:1.9.4restart: alwayscontainer_name: consulserver1hostname: consulserver1command: agent -server -bootstrap -client0.0.0.0 -ui -nodeconsulserver1ports:- 8500:8500consulserver2:image: consul:1.9.4restart: alwayscontainer_name: consulserver2hostname: consulserver2command: agent -server -joinconsulserver1 -nodeconsulserver2depends_on:- consulserver1consulserver3:image: consul:1.9.4restart: alwayscontainer_name: consulserver3hostname: consulserver3command: agent -server -joinconsulserver1 -nodeconsulserver3depends_on:- consulserver1consulclient1:image: consul:1.9.4restart: alwayscontainer_name: consulclient1hostname: consulclient1command: agent -client0.0.0.0 -retry-joinconsulserver1 -nodeconsulclient1depends_on:- consulserver2- consulserver3ports:- 8600:8500consulclient2:image: consul:1.9.4restart: alwayscontainer_name: consulclient2hostname: consulclient2command: agent -client0.0.0.0 -retry-joinconsulserver1 -nodeconsulclient2depends_on:- consulserver2- consulserver3ports:- 8700:8500consulclient3:image: consul:1.9.4restart: alwayscontainer_name: consulclient3hostname: consulclient3command: agent -client0.0.0.0 -retry-joinconsulserver1 -nodeconsulclient3depends_on:- consulserver2- consulserver3ports:- 8800:8500
这个 docker-compose 文件描述了启动3个 server 模式的实例3个 client 模式的实例。其中 consulserver1 开启了ui端口映射8500consulclient1,、consulclient2、consulclient3 端口分别映射为 8600、8700、8800 记住这些端口后面要用到。[rootlocalhost myservices]# docker-compose up -d
[rootlocalhost myservices]# docker exec consulserver1 consul members
Node Address Status Type Build Protocol DC Segment
consulserver1 172.18.0.2:8301 alive server 1.9.4 2 dc1 all
consulserver2 172.18.0.3:8301 alive server 1.9.4 2 dc1 all
consulserver3 172.18.0.4:8301 alive server 1.9.4 2 dc1 all
consulclient1 172.18.0.5:8301 alive client 1.9.4 2 dc1 default
consulclient2 172.18.0.6:8301 alive client 1.9.4 2 dc1 default
consulclient3 172.18.0.7:8301 alive client 1.9.4 2 dc1 default
使用 docker-compose up -d 命令启动所有的容器。启动完成后使用 docker exec consulserver1 consul members 查看整个集群的状态。它列出了所有节点的类型IP是否存活等信息。如果上面的操作一切正常在浏览器里输入 http://宿主机IP8500 访问 web 管理界面。界面上会显示6个绿色的节点。表示所有节点都正常运行中。在 asp.net core 应用内使用 Consul好了现在我们已经有了 Consul 集群现在可以开始编写代码来注册跟拉取我们的服务了。我们需要完成4点操作。定义一个健康检测的接口在服务启动的时候自动注册该服务的基础信息在服务关闭的时候自动移除该服务拉取服务列表健康检测我们的服务注册到 consul 节点后节点会定时去轮询我们的服务所以需要提供一个 http 接口如果返回 200 ok 就表示服务存活否则代表服务故障。 [ApiController][Route([controller])]public class HealthController : ControllerBase{[HttpGet]public string Get(){return ok;}}
}
添加一个HealthController里面就实现一个Get方法简单的返回ok就可以了。服务注册、移除我们实现一个HostedService来实现自动注册跟移除服务。HostedService 有2个方法start 跟 stop 。start 方法会在 app 启动的时候触发 stop 会在 app 关闭的时候触发。跟我们的需求完美符合。Install-Package Consul -Version 1.6.10.1
使用 nuget 安装 consul .net client 类库。我们跟 consul 节点的通讯需要它来完成。 public class ServiceInfo{public string Id { get; set; }public string Name { get; set; }public string IP { get; set; }public int Port { get; set; }public string HealthCheckAddress { get; set; }}
定义一个类存储服务的基本信息。public class ConsulRegisterService : IHostedService{IConsulClient _consulClient;ServiceInfo _serviceInfo;public ConsulRegisterService(IConfiguration config, IConsulClient consulClient){_serviceInfo new ServiceInfo();var sc config.GetSection(serviceInfo);_serviceInfo.Id sc[id];_serviceInfo.Name sc[name];_serviceInfo.IP sc[ip];_serviceInfo.HealthCheckAddress sc[HealthCheckAddress];_serviceInfo.Port int.Parse(sc[Port]);_consulClient consulClient;}public async Task StartAsync(CancellationToken cancellationToken){Console.WriteLine($start to register service {_serviceInfo.Id} to consul client ...);await _consulClient.Agent.ServiceDeregister(_serviceInfo.Id, cancellationToken);await _consulClient.Agent.ServiceRegister(new AgentServiceRegistration{ID _serviceInfo.Id,Name _serviceInfo.Name,// 服务名Address _serviceInfo.IP, // 服务绑定IPPort _serviceInfo.Port, // 服务绑定端口Check new AgentServiceCheck(){DeregisterCriticalServiceAfter TimeSpan.FromSeconds(0),//服务启动多久后注册Interval TimeSpan.FromSeconds(5),//健康检查时间间隔HTTP $http://{_serviceInfo.IP}:{_serviceInfo.Port}/ _serviceInfo.HealthCheckAddress,//健康检查地址Timeout TimeSpan.FromSeconds(5)}});Console.WriteLine(register service info to consul client Successful ...);}public async Task StopAsync(CancellationToken cancellationToken){await _consulClient.Agent.ServiceDeregister(_serviceInfo.Id, cancellationToken);Console.WriteLine($Deregister service {_serviceInfo.Id} from consul client Successful ...);}}
定义一个 ConsulRegisterService 类实现 IHostedService 接口。在 start 方法内使用 consulclient 注册服务 。在 stop 方法内取消注册该服务。 public void ConfigureServices(IServiceCollection services){//注册Consulclient对象services.AddSingletonIConsulClient(new ConsulClient(x {x.Address new Uri(Configuration[consul:clientAddress]);}));//注册ConsulRegisterService 这个servcie在app启动的时候会自动注册服务信息services.AddHostedServiceConsulRegisterService();services.AddControllers();}
在 startup 的 ConfigureServices 方法内先注入一个 IConsulClient 的实例。再注册我们的 ConsulRegisterService 服务。 serviceInfo: {id: hote_base_01, //服务idname: hote_base, //服务名ip: 192.168.0.200, //服务部署的ipport: 6002, //服务对应的端口healthCheckAddress: health //健康检测的请求path},consul: {clientAddress: http://192.168.0.117:8700 //consul client 的地址}
以我们的演示项目 hotel_base 为例在 appsettings.json 文件内添加以上配置信息。其中 consulclientAddress 为 consule client 节点的地址。注意这里的 ip 不要使用 localhost 因为如果使用 docker 部署 localhost 会出现网络访问方面的问题。好了让我们运行一下我们的项目。等待项目启动完成后打开 consul 的 web 管理界面。查看 consulclient1 节点可以看到我们的 hotelbase01 服务被注册上去了。我们强制把启动的app关闭可以看到 consul 管理界面显示 hotel_base 服务红色代表故障。注意要演示故障这种情况要先注释掉 ConsulRegisterService 的 stop 方法不然关闭的时候会先取消注册这样 consul 管理界面上就找不到对应的服务了。我们按照 hotel_base 的套路把其他几个服务都添加服务注册的代码。然后全部运行起来拉取服务列表下面我们演示下如何通过 consul client 读取服务列表。 public interface IConsulService{TaskListAgentService GetServicesAsync(string serviceName);}public class ConsulService : IConsulService{public IConsulClient _consulClient;public ConsulService(IConsulClient consulClient){_consulClient consulClient;}public async TaskListAgentService GetServicesAsync(string serviceName){var result await _consulClient.Health.Service(serviceName, , true);return result.Response.Select(x x.Service).ToList();}}
定义一个ConsulService类里面有个GetServicesAsync方法。该方法通过服务名称从 consul 集群获取服务的列表。 public void ConfigureServices(IServiceCollection services){services.AddSingletonIConsulClient(new ConsulClient(x {x.Address new Uri(Configuration[consul:clientAddress]);}));//注册ConsulService里面封装了一些方法services.AddSingletonIConsulService, ConsulService();services.AddHostedServiceConsulRegisterService();services.AddControllers();}
在 ConfigureServices 方法内把 ConsulService 注册到容器内。 [ApiController][Route([controller])]public class OrderController : ControllerBase{private static readonly ListOrderVM _orders new ListOrderVM() { new OrderVM { Id OD001,StartDay 2021-05-01,EndDay 2021-05-02,RoomNo 1001,MemberId M001,HotelId H8001,CreateDay 2021-05-01}};private IConsulService _consulservice;public OrderController(ILoggerOrderController logger, IConsulService consulService){_consulservice consulService;}[HttpGet({id})]public async TaskOrderVM Get(string id){var order _orders.FirstOrDefault(xx.Id id);if (!string.IsNullOrEmpty(order.MemberId)){var memberServiceAddresses await _consulservice.GetServicesAsync(member_center);var memberServiceAddress memberServiceAddresses.FirstOrDefault();using (var httpClient new HttpClient()){httpClient.BaseAddress new Uri($http://{memberServiceAddress.Address}:{memberServiceAddress.Port});var memberResult await httpClient.GetAsync(/member/ order.MemberId);var json await memberResult.Content.ReadAsStringAsync();var member JsonConvert.DeserializeObjectMemberVM(json);order.Member member;}}return order;}}
我们通过在 ordering 服务项目的一个获取订单详细信息的接口来演示下如何使用ConsulService 。订单详细信息需要根据会员id获取会员的详细信息。我们通过 ConsulService 获得 member_center 的服务列表后取出一个配置信息获取 IP 跟端口号。组装成服务的真正的请求地址使用 HttpClient 来请求这个接口获取会员的基本信息。当然这里我们有很多可以改进的地方比如我们可以在本地缓存服务列表这样不用每次都通过 consul client 拉取。比如我们可以写一个随机算法每次从服务列表中随机取一个对象从而达到负载均衡的目的在这就不再演示了。把所有项目都跑起来使用 postman 去访问一下获取订单详情接口可以看到订单详情的返回值包含了会员信息。总结通过以上我们回顾了服务注册发现的概念。演示了如何通过 docker/docker-compose 环境来部署 Consul 集群。还通过简单的 .NET Core 代码演示了如何注册服务信息到 Consul 集群如何通过代码获取服务列表并调用它。相信现在大家对服务注册发现、Consul 组件有了一个比较直观的了解。谢谢阅读。项目地址https://github.com/kklldog/myhotel_microservice相关文章NET Core with 微服务 - 什么是微服务.Net Core with 微服务 - 架构图.Net Core with 微服务 - Ocelot 网关关注我的公众号一起玩转技术