@[toc]
一、注册中心的概念
- 概念
能够注册微服务地址【ip:端口】的组件就是注册中心。
如图: 目的
保证微服务的动态伸缩性。二、注册中心的使用场景
- 场景
主要场景是在微服务中使用。
如图:
三、注册中心的技术选型
类型
- zookeeper
- consul
- etcd
- eureka
- 特点
| Feature | Consul | zookeeper | etcd | euerka |
| --- | --- | --- | --- | --- |
| 服务健康检查 | 服务状态,内存,硬盘等 | (弱)长连接,keepalive | 连接心跳 | 可配支持 |
| 多数据中心 | 支持 | - | - | - |
| kv存储服务 | 支持 | 支持 | 支持 | - |
| 一致性 | raft | paxos | raft | - |
| cap | ca | cp | cp | ap |
| 使用接口(多语言能力) | 支持http和dns | 客户端 | http/grpc | http(sidecar) |
| watch支持 | 全量/支持long polling | 支持 | 支持 long polling | polling 支持 long polling/大部分增量 |
| 自身监控 | metrics | - | metrics | metrics |
| 安全 | acl /https | acl | https支持(弱) | - |
| spring cloud集成 | 支持 | 支持 | 支持 | 支持 | Consul的三个概念
- server:存储微服务地址【ip:端口】
- client:连接Consul
- agent:后台服务
- 应用架构集成原理
如图:
四、注册中心的项目落地
工具
- Consul
网盘下载地址:
链接:https://pan.baidu.com/s/1zN4P...
提取码:lnk7 - demo项目
- Consul
步骤
Consul运行命令
# 在根目录下启动运行 consul.exe agent -dev #在开发模式下启动命令 consul agent -server -bootstrap-expect [节点数据量] -data-dir d:/consul/data [数据存储地址]
demo项目
nuget 安装
Consul
appsettings.json 添加配置信息
{ ...... "ConsulRegistry": { "Name": "testService", "RegistryAddress": "http://127.0.0.1:8500", "HealthCheckAddress": "/HealthCheck" } }
新增配置实体类,通过json文件映射到实体配置类
public class ServiceRegistryConfig { ///
/// 服务ID /// public string Id {get;set;} ////// 服务名称 /// public string Name {get;set;} ////// 服务标签 /// public string[] Tags { get; set; } ////// 服务地址 /// public string Address { get; set; } ////// 服务端口号 /// public int Port { get; set; } ////// 服务注册地址 /// public string RegistryAddress { get; set; } ////// 服务健康检查地址 /// public string HealthCheckAddress { get; set; } }微服务注册
创建服务注册实现类
public class ServiceRegistry : IServiceRegistry { public void Register(ServiceRegistryConfig serviceRegistryConfig) { //1 建立consul客户端的连接 var consulClient = new ConsulClient(configuration => { configuration.Address = new Uri(serviceRegistryConfig.RegistryAddress); }); //2 创建 consul服务注册对象 var registration = new AgentServiceRegistration() { ID = serviceRegistryConfig.Id, Name = serviceRegistryConfig.Name, Address = serviceRegistryConfig.Address, Port = serviceRegistryConfig.Port, Tags = serviceRegistryConfig.Tags, //健康检查 Check = new AgentServiceCheck() { //设置健康检查超时时间 Timeout = TimeSpan.FromSeconds(10), //服务停止5秒后注销服务 DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(50), //健康检查地址 HTTP = serviceRegistryConfig.HealthCheckAddress, //健康检查间隔时间 Interval = TimeSpan.FromSeconds(10) } }; //服务注册 consulClient.Agent.ServiceRegister(registration); //关闭连接释放资源 consulClient.Dispose(); } ///
/// 注册中心注销 /// /// public void Deregister(ServiceRegistryConfig serviceRegistryConfig) { var consulClient = new ConsulClient(configuration => { configuration.Address = new Uri(serviceRegistryConfig.Address); }); consulClient.Agent.ServiceDeregister(serviceRegistryConfig.Id); } }创建服务注册看接口类
public interface IServiceRegistry { void Register(ServiceRegistryConfig serviceRegistryConfig); void Deregister(ServiceRegistryConfig serviceRegistryConfig); }
创建服务注册扩展类
//consul服务注册类 public static class ConsulExtensions { ///
/// 注册中心扩展 /// /// /// ///public static IServiceCollection AddConsul(this IServiceCollection services, IConfiguration Configuration) { //将json文件映射到实体类 services.Configure (Configuration.GetSection("ConsulRegistry")); services.AddSingleton (); return services; } } // 服务启动时注册服务 public static class ConsulApplicationBuilderExtension { public static IApplicationBuilder UseConsulRegistry(this IApplicationBuilder app) { //获取配置信息 var serviceNode = app.ApplicationServices.GetRequiredService >().Value; //获取生命周期 var lifetime = app.ApplicationServices.GetRequiredService (); //获取服务注册实力 var consulRegistry = app.ApplicationServices.GetRequiredService (); //获取服务地址信息 var features = app.Properties["server.Features"] as FeatureCollection; var address = features.Get ().Addresses.First(); var uri = new Uri(address); //服务注册 serviceNode.Id = Guid.NewGuid().ToString(); serviceNode.Address = $"{uri.Scheme}://{ uri.Host}"; serviceNode.Port = uri.Port; serviceNode.HealthCheckAddress = $"{uri.Scheme}://{uri.Host}:{uri.Port}{serviceNode.HealthCheckAddress}"; consulRegistry.Register(serviceNode); //服务器关闭时注销服务 lifetime.ApplicationStopping.Register(() => { consulRegistry.Deregister(serviceNode); }); return app; } } //在startup类中ConfigureServices 方法中注册服务 services.AddConsul(Configuration); //在startup类中Configure 方法启动服务 app.UseConsulRegistry(); 运行结果如下:
微服务发现
在appsettings.json 文件中新增Consul注册地址配置
...... "ConsulDiscoverys": { "RegistryAddress": "http://127.0.0.1:8500" } .....
新建配置类
public class ServiceDiscoveryConfig { public string RegistryAddress { get; set; } }
新增服务发现接口类
public interface IConsulDiscovery { Task
- > Discovery(string ServiceName);
}
新增服务发现实现类
public class ConsulDiscovery : IConsulDiscovery { private readonly IConfiguration Configuration; public ConsulDiscovery(IConfiguration _Configuration) { Configuration = _Configuration; } ///
/// 服务发现 /// /// 服务名称 ///返回一个集合 public async Task- > Discovery(string ServiceName)
{
List
list = new List (); ServiceDiscoveryConfig serviceDiscoveryConfig = new ServiceDiscoveryConfig(); serviceDiscoveryConfig = Configuration.GetSection("ConsulDiscoverys").Get< ServiceDiscoveryConfig >(); //1 建立连接 var consulClient = new ConsulClient(Options => { Options.Address = new Uri(serviceDiscoveryConfig.RegistryAddress); }); // 2 根据服务名称获取注册的服务地址 var queryResult = await consulClient.Catalog.Service("ServiceName"); // 3 将注册的地址注入集合中 foreach (var item in queryResult.Response) { list.Add(new ServiceUrl() { Url = item.Address+":"+ item.ServicePort }); } return list; } } 在扩展类中新增发现服务的扩展
public static IServiceCollection AddConsulDiscovery(this IServiceCollection services) { services.AddSingleton
(); return services; } 在Startup类ConfigureServices方法中进行注册
//服务发现 services.AddConsulDiscovery();
在控制器构造函数中注入下服务发现的接口
private readonly IConsulDiscovery consulDiscovery; public HomeController(IConsulDiscovery _consulDiscovery) { consulDiscovery = _consulDiscovery; } ..... //然后在其他方法中根据服务名称获取服务地址;注意:返回值是一个集合。
五、注册中心Consul的高可用
集群搭建 【最好有3个实例】
步骤
节点1
# 1、新建配置文件,路径:D:/Assembly/Consul/node1/basic.json { "datacenter": "dc1", "data_dir": "D:/Assembly/Consul/node1", "log_level": "INFO", "server": true, "node_name": "node1", "ui": true, "bind_addr": "127.0.0.1", "client_addr": "127.0.0.1", "advertise_addr": "127.0.0.1", "bootstrap_expect": 3, "ports":{ "http": 8500, "dns": 8600, "server": 8300, "serf_lan": 8301, "serf_wan": 8302}} # 2、运行命令 # 2、切换到consul根目录下: consul.exe agent -config-file=D:/Assembly/Consul/node1/basic.json
节点2
# 1、新建配置文件,路径:D:/Assembly/Consul/node2/basic.json { "datacenter": "dc1", "data_dir": "D:/Assembly/Consul/node2", "log_level": "INFO", "server": true, "node_name": "node2", "bind_addr": "127.0.0.1", "client_addr": "127.0.0.1", "advertise_addr": "127.0.0.1", "ports":{ "http": 8510, "dns": 8610, "server": 8310, "serf_lan": 8311, "serf_wan": 8312}} # 2、切换到consul根目录下: consul.exe agent -config-file=D:/Assembly/Consul/node2/basic.json -retry-join=127.0.0.1:8301
节点3
# 1、新建配置文件,路径:文件地址:D:/Assembly/Consul/node3/basic.json { "datacenter": "dc1", "data_dir": "D:/Assembly/Consul/node3", "log_level": "INFO", "server": true, "node_name": "node3", "bind_addr": "127.0.0.1", "client_addr": "127.0.0.1", "advertise_addr": "127.0.0.1", "ports":{ "http": 8520, "dns": 8620, "server": 8320, "serf_lan": 8321, "serf_wan": 8322}} # 2、切换到consul根目录下: consul.exe agent -config-file=D:/Assembly/Consul/node3/basic.json -retry-join=127.0.0.1:8301
查看主节点
#切换到consul根目录下 consul.exe info
集群搭建命令
-bind:为该节点绑定一个地址 -enable-script-checks=true:设置检查服务为可用 -join:加入到已有的集群中 -server 表示当前使用的server模式 -node:指定当前节点在集群中的名称 -config-file - 要加载的配置文件 -config-dir:指定配置文件,定义服务的,默认所有以.json结尾的文件都会读 -datacenter: 数据中心没名称,不设置的话默认为dc -client: 客户端模式 -ui: 使用consul自带的ui界面 -data-dir consul存储数据的目录 -bootstrap:用来控制一个server是否在bootstrap模式,在一个datacenter中只能有一个server处于bootstrap模式,当一个server处于bootstrap模式时,可以自己选举为raft leader。 -bootstrap-expect:在一个datacenter中期望提供的server节点数目,当该值提供的时候,consul一直等到达到指定sever数目的时候才会引导整个集群,该标记不能和bootstrap公用 这两个参数十分重要, 二选一,如果两个参数不使用的话,会出现就算你使用join将agent加入了集群仍然会报 2018/10/14 15:40:00 [ERR] agent: failed to sync remote state: No cluster leader
配置文件参数
ui: 相当于-ui 命令行标志。 acl_token:agent会使用这个token和consul server进行请求 acl_ttl:控制TTL的cache,默认是30s addresses:一个嵌套对象,可以设置以下key:dns、http、rpc advertise_addr:等同于-advertise bootstrap:等同于-bootstrap bootstrap_expect:等同于-bootstrap-expect bind_addr:等同于-bindca_file:提供CA文件路径,用来检查客户端或者服务端的链接 cert_file:必须和key_file一起 check_update_interval: client_addr:等同于-client datacenter:等同于-dc data_dir:等同于-data-dir disable_anonymous_signature:在进行更新检查时禁止匿名签名 enable_debug:开启debug模式 enable_syslog:等同于-syslog encrypt:等同于-encrypt key_file:提供私钥的路径 leave_on_terminate:默认是false,如果为true,当agent收到一个TERM信号的时候,它会发送leave信息到集群中的其他节点上。 log_level:等同于-log-level node_name:等同于-node ports:这是一个嵌套对象,可以设置以下key:dns(dns地址:8600)、http(http api地址:8500)、rpc(rpc:8400)、serf_lan(lan port:8301)、serf_wan(wan port:8302)、server(server rpc:8300) protocol:等同于-protocol rejoin_after_leave:等同于-rejoin retry_join:等同于-retry-join retry_interval:等同于-retry-interval server:等同于-server syslog_facility:当enable_syslog被提供后,该参数控制哪个级别的信息被发送,默认Local0 ui_dir:等同于-ui-dir