Hi,大家好,我叫consul,翻译成中文叫做“领事”,其实我更喜欢叫自己为中介,因为我觉得自己做的事情和房产中介非常像。比如说想要卖房的房东到我这边登记,我将房屋信息登录到我的表格中(服务注册),有买家来咨询时,我再查询表格将符合条件的房子返回给买家(服务发现),平时我也要做点房源的维护工作,比如每隔一天就打电话问下房东:“你的房子还卖么?(服务健康检查)”。

  我的诞生也和现在互联网项目的开发模式有关,从之前的三层架构衍化成现在有微服务架构,把原来BLL和DAL层做事按业务拆成独立的分布式服务(其实很多人就是把CURD放到单独的服务中而已),为了高可用&高扩展,又把这些服务(进程)集群化,就出现一堆的地址和端口。客户端由原来的进程内调用变成跨进程或跨网络调用服务,把这些一堆地址和端口放到配置文件中。这样做其实没什么问题,但维护起来比较麻烦,比如说增加一个服务,就要修改配置文件并重启客户端,同理,删掉一个服务也要同样的操作。

  我的作用主要是管理这些集群服务的配置,整体流程是这样子的:服务(进程)启动的时候把服务名和自己的IP、端口通过HTTP告诉我,我将这些信息记到自己的内存表格中,客户端调用时带上要查询的服务名通过HTTP发送给我,我再自己的内存表中找到叫这服务名的所有配置发送给客户端。

  平时我还要做一些服务健康检查的事儿,在上面服务启动的时候,服务还要给我配置一个检查接口和检查频率等一些参数,我会按这些参数每隔一段时间,比如10秒钟去请求一下这个接口,如果不通,我就隔5秒再重试下,如果重试3次还不通,我就认定这个服务挂掉了,就从内存表格中删掉这个服务配置,不然客户端要请求到这个不通服务,我就罪过了。

说了这么多,还是看下我的整个流程图吧,一图胜千言:

image.png

 

最后,再用代码实现下吧,语言是C#,其实语言类似,反正都有现成的sdk。

1、VS中建个控制台应用,并通过nuget安装consul包

image.png

 

2、注册几个服务

 1 static void Main(string[] args)
 2         {
 3             string serviceName = "OrderService";
 4 
 5             // 注册服务
 6             RegisteService(serviceName, new DnsEndPoint("127.0.0.1", 16005));
 7             RegisteService(serviceName, new DnsEndPoint("127.0.0.1", 16007));
 8             RegisteService(serviceName, new DnsEndPoint("127.0.0.1", 16008));
 9             Console.ReadKey();
10         }
11 
12        static bool RegisteService(string serviceName, DnsEndPoint dnsEndPoint)
13         {
14             var serviceId = GenServiceId(serviceName, dnsEndPoint);
15             var checkId = GenCheckId(serviceName, dnsEndPoint);
16             var checkName = GenCheckName(serviceName, dnsEndPoint);
17             var check = new AgentCheckRegistration
18             {
19                 ID = checkId,
20                 Name = checkName,
21                 TCP = $"{dnsEndPoint.Host}:{dnsEndPoint.Port}",
22                 Interval = TimeSpan.FromSeconds(10),
23                 Status = HealthStatus.Passing,
24                 DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(20),
25             };
26             var service = new AgentServiceRegistration
27             {
28                 ID = serviceId,
29                 Name = serviceName,
30                 Address = dnsEndPoint.Host,
31                 Port = dnsEndPoint.Port,
32                 Check = check
33             };
34 
35             var _client = new ConsulClient(config => 
36             {
37                 var uriBuilder = new UriBuilder("http://localhost:8500");
38                 config.Address = uriBuilder.Uri;
39             });
40             var res = _client.Agent.ServiceRegister(service).Result;
41             if (res.StatusCode != HttpStatusCode.OK)
42                 return false;
43             return true;
44         }
 

image.png

 

3、服务发现

 1         static void Main(string[] args)
 2         {
 3             string serviceName = "OrderService";
 4 
 5             // 服务发现
 6             List<string> targets = FindServiceEndpoints(serviceName);
 7             foreach(var item in targets)
 8             {
 9                 Console.WriteLine(item);
10             }
11             Console.ReadKey();
12         }
13 
14         static List<string> FindServiceEndpoints(string serviceName)
15         {
16             var _client = new ConsulClient(config =>
17             {
18                 var uriBuilder = new UriBuilder("http://localhost:8500");
19                 config.Address = uriBuilder.Uri;
20             });
21 
22             var targets = new List<string>();
23             try
24             {
25                 var r = _client.Health.Service(serviceName, "", true).Result;
26                 if (r.StatusCode != HttpStatusCode.OK)
27                     throw new ApplicationException($"query consul server error");
28 
29                 targets = r.Response.Select(x => $"{x.Service.Address}:{x.Service.Port}").ToList();
30             }
31             catch { }
32             return targets;
33         }

 

更多精彩请关注我的关注号:

 

 

posted @ 2020-02-28 16:07 刘珍宝 阅读(321) 评论(0) 推荐(0) 编辑
摘要: C#线程间互相通信主要用到两个类:AutoResetEvent和ManualResetEvent。一、AutoResetEventAutoResetEvent允许线程通过发信号互相通信,线程通过调用AutoResetEvent上的WaitOne来等待信号。如果AutoResetEvent为非终止状态... 阅读全文
posted @ 2014-04-18 08:08 刘珍宝 阅读(5244) 评论(14) 推荐(9) 编辑
摘要: CLR环境中给我们内置了几个常用委托Action、 Action、Func、Predicate,一般我们要用到委托的时候,尽量不要自己再定义一 个委托了,就用系统内置的这几个已经能够满足大部分的需求,且让代码符合规范。一、ActionAction封装的方法没有参数也没有返回值,声明原型为:1 pub... 阅读全文
posted @ 2014-04-17 20:03 刘珍宝 阅读(16122) 评论(11) 推荐(26) 编辑
摘要: 序列化是把一个内存中的对象的信息转化成一个可以持久化保存的形式,以便于保存或传输,序列化的主要作用是不同平台之间进行通信,常用的有序列化有json、xml、文件等,下面就逐个讲下这三种序列化的方法。一、序列化为jsonC#中用于对象和json相互转换的原生类有两个:DataContractJsonS... 阅读全文
posted @ 2014-04-17 13:47 刘珍宝 阅读(25971) 评论(6) 推荐(15) 编辑
摘要: Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数。通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数。在C#中的Linq中的大部分就是由扩展方法和Lambda 表达式共同来实现,如:1 public static IEnumerable Where(this IEnumerable source, Func predicate);2 public static IEnumerable Select(this IEnumerable source, Func selector);下面使用一个Where方法,体现委托向Lambda 表达式优化的 阅读全文
posted @ 2014-04-10 09:07 刘珍宝 阅读(2083) 评论(0) 推荐(0) 编辑
摘要: C#中的事件是建立在委托的基础上,标准的事件模型应该包括以下几点:声明一个用于定义事件的委托,这里用系统自带的泛型委托原型EventHandler,如:public delegate void EventHandler(object sender,TEventArgse);这里面的TEventArgs是由我们自定义的参数类型,继承自EventArgs基类事件参数的名称以EventArgs结束声明事件的委托原型即EventHandler,它的返回值为void声明事件的委托原型即EventHandler,它有两个参数:sender和e,sender表示事件触发者,e表示事件触发时的参数事件的声明是 阅读全文
posted @ 2014-04-09 14:21 刘珍宝 阅读(1049) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示