源宝导读:在微服务架构体系中,由于微服务众多,服务之间又有互相调用关系,因此,一个通用的分布式配置管理是必不可少的。本文将介绍如何使用Consul Watch机制实现配置集中管理与热更新。
前言
随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关、参数的配置、服务器的地址等等,对程序配置的期望值也越来越高:配置修改后实时生效,分环境、分集群管理配置,代码安全、审核机制。在这样的大环境下,传统的通过配置文件、数据库等方式已经越来越无法满足开发人员对配置管理的需求。所以,配置中心应运而生。
在微服务架构体系中,由于微服务众多,服务之间又有互相调用关系,因此,一个通用的分布式配置管理是必不可少的。一般来说,配置管理需要解决配置集中管理、在系统运行期间可实现动态配置、配置修改后支持自动刷新等问题。
一、Consul在集成开放平台的使用场景
天际集成开放平台深度集成Consul,实现微服务架构中的以下场景:
1 .服务注册:Consul提供了通过DNS或者HTTP接口的方式将我们的服务信息注册给Consul
2 .服务发现:Consul提供了通过DNS或者HTTP接口的方式查询发现注册的服务。这样外部可以很容易的发现它所依赖的服务
3.服务负载均衡:Consul的服务注册是集群式的。我们可用通过负载均衡算法从Consul注册的服务列表中负载出一个可以被访问的服务
4 .Key/Value配置中心:应用程序可以根据自己的需要使用Consul提供的Key/Value存储。Consul提供了简单易用的HTTP接口,结合其他工具可以实现动态配置、功能标记、领袖选举等等功能
5 .健康检查:Consul的Client可以提供任意数量的健康检查,可以与给定的服务相关联(HTTP服务是否返回200)。系统可以使用这些信息来监视集群的健康状况,服务发现组件可以使用这些信息将流量从不健康的主机路由出去
二、Consul K/V查询与Blocking Query
2.1 Consul提供的Watch类型
1. Key – 监视指定K/V键值对
2. Keyprefix – 监视指定的Keyprefix
3. Services – 监视服务列表
4.nodes – 监控节点列表
5. service – 监视服务实例
6. checks- 监视健康检查的值
2.2 Consul K/V 查询
2.2.1 K/V查询
通过Consul提供的K/V HTTP API。我们可以很容易的对Consul的K/V进行写入,修改,查询操作。
通过Consul管理控制台,我们新建一个Key为Config的配置项并设置值为 {"title":"测试标题","MaxTaskCount":3}。
调用Consul K/V查询API http://127.0.0.1:8500/v1/kv/{key}可以查询key下Value的值,此处,我们需要查询是Key是Config。所以,完整的Uri是http://127.0.0.1:8500/v1/kv/Config。
查询结果
{"LockIndex": 0,"Key": "Config","Flags": 0,"Value": "ewoidGl0bGUiOiLmtYvor5XmoIfpopgiLAoiTWF4VGFza0NvdW50IjozCn0=","CreateIndex": 7319758,"ModifyIndex": 7319803}
通过查询结果可以获取Config的Value信息,HTTP API查询的Value一般是字节的Base64表现形式。当然,在实际的编码过程中,我们不会直接使用HTTP API调用。而是通过Consul Client SDK进行调用。
C#使用Consul Client SDK查询K/V
var uri = new UriBuilder("http", "127.0.0.1", 8500);
IConsulClient client = new ConsulClient(config => config.Address = uri.Uri);
var response =await client.KV.Get("Config");
var value = string.Empty;if (response?.StatusCode == System.Net.HttpStatusCode.OK){value = Encoding.UTF8.GetString(response.Response?.Value);
}
上述查询代码可以获取Config的真实配置值 {"title":"测试标题","MaxTaskCount":3}。
2.2.2 Keyprefix查询
2.2.1章节中介绍了如何进行Consul的K/V查询。而在实际的使用过程中,不仅仅会进行的K/V查询。还会使用Keyprefix方式来查询某个prefix下的所有K/V信息。
在Consul管理控制台,新建Key Students,在Students Key下新建多个K/V,如下图所示:
设置查询的prefix为Students,查询结果应该为Students下配置的所有的K/V数据列表。
C#使用Consu Client Sdk执行Keyprefix查询
var uri = new UriBuilder("http", "127.0.0.1", 8500);IConsulClient client = new ConsulClient(config => config.Address = uri.Uri);var response =await client.KV.List("Students");var kvList = new List<string>();if (response?.StatusCode == System.Net.HttpStatusCode.OK){foreach (var kVPair in response.Response){if (kVPair.Value != null){var value = Encoding.UTF8.GetString(kVPair.Value);kvList.Add(value);}}}var outPutString = JsonSerializer.Serialize(kvList);
查询结果
[{"name":"Nick","address":"test address","age":18},{"name":"Tom","address":"test address","age":18}
]
2.3 Consul Blocking Query
上述2.1、2.2章节介绍了Consul的K/V查询的两种方式。要实现配置实时更新通知Consul K/V查询只是第一步,而下面要介绍的就是关键的第二步,Consul的Blocking Query。
Blocking Query官方定义:
Many endpoints in Consul support a feature known as "blocking queries". A blocking query is used to wait for a potential change using long polling. Not all endpoints support blocking, but each endpoint uniquely documents its support for blocking queries in the documentation.
Endpoints that support blocking queries return an HTTP header named X-Consul-Index. This is a unique identifier representing the current state of the requested resource.
On subsequent requests for this resource, the client can set the index query string parameter to the value of X-Consul-Index, indicating that the client wishes to wait for any changes subsequent to that index.
When this is provided, the HTTP request will "hang" until a change in the system occurs, or the maximum timeout is reached. A critical note is that the return of a blocking request is no guarantee of a change. It is possible that the timeout was reached or that there was an idempotent write that does not affect the result of the query.
In addition to index, endpoints that support blocking will also honor a wait parameter specifying a maximum duration for the blocking request. This is limited to 10 minutes. If not set, the wait time defaults to 5 minutes. This value can be specified in the form of "10s" or "5m" (i.e., 10 seconds or 5 minutes, respectively). A small random amount of additional wait time is added to the supplied maximum wait time to spread out the wake up time of any concurrent requests. This adds up to wait / 16 additional time to the maximum duration.
简单来说就是当客户端请求Consul获取K/V时,需要携带一个版本号信息,Consul会比较这个客户端版本号是否和Consul服务端的版本号一致,如果一致,则Consul会阻塞这个请求,直到Consul中的K/V发生变化,或者到达阻塞时间上限;如果版本号不一致,则立即返回。这个阻塞时间默认是5分钟,支持自定义。
利用阻塞查询的机制,我们可以发起一个“挂起”的查询。这个查询直到K/V的值发生变更才会返回,这样,查询发起方既能收到K/V值发生变更的通知,又能接收变更后的最新值。
Consul Blocking Query查询
Task.Factory.StartNew(async () => {ulong waitIndex = 0;var uri = new UriBuilder("http", "10.20.21.13", 8500);IConsulClient client = new ConsulClient(config => config.Address = uri.Uri);while (true){var response = await client.KV.Get("Config", new QueryOptions { WaitIndex = waitIndex });if (response.StatusCode == System.Net.HttpStatusCode.OK){if (response.Response?.Value != null){var value = Encoding.UTF8.GetString(response.Response?.Value);waitIndex = response.Response.ModifyIndex;}}}});
上述代码的Blocking Query经历下面步骤:
1 .声明客户端查询版本号,默认值0
2 .执行初始查询,获取K/V值
3 .将查询结果中Consul服务端该K/V的最新版本号赋值给客户端查询版本号
4 .使用最新的客户端版本号进行阻塞查询
5 .最新客户端发起的查询将会"挂起",直到Config中Value值发生变更,查询才会返回
上述操作是在一个后台循环线程中运行的,所以,在”挂起“的查询返回时即完成一次K/V更改通知。随后进入下一次查询”挂起操作“,直到又一次发生变更。这样,程序在运行期间便能一直保持对某个Key的Blocking Query达到配置更改通知的目的。
三、集成开放平台使用Consul Blocking Query实现实时生效配置中心
第2节描述了如何使用Consul的Blocking Query实现配置实时更改通知。在集成开放平台中,不同微服务的配置会放置在Consul的不同路径下。现在各服务配置之间的隔离,每个服务在启动时会对需要在运行期间热更新的配置发起Blocking Query,当配置管理模块更改了服务监控的配置时,服务“挂起”的配置查询就会收到更新通知。
四、后续思考
整体来说,集成开放平台利用Consul实现的配置实时通知还属于使用阶段。而配置行为,配置管理,配置Consul更改通知等等并未独立为单独的配置服务与配置管理模块。配置相关的代码还是分散在各服务中。在之后的架构演变中,可以考虑将配置单独出一个配置服务与管理。而各微服务使用的只应该是配置服务对应的SDK。这样整体架构就指责清晰,领域独立了。
----- END ------
作者简介
刘同学: 研发工程师,目前负责集成开放平台相关工作。
也许您还想看:
Jekins持续集成在ERP研发中的应用实践
基于PaaS平台的多应用自集成方案之公共数据集成
更多明源云·天际开放平台场景案例与开发小知识,可以关注明源云天际开发者社区公众号:
【DevOps】获取流水线部署信息,查看部署快人一步
【建模】ERP日志分表,提升海量日志存取性能