ASP.NET Core微服务之基于Consul实现服务治理(2)

释放双眼,带上耳机,听听看~!

Tip: 此篇已加入.NET Core微服务基础系列文章索引

上一篇发布之后,很多人点赞和评论,不胜惶恐,这一篇把上一篇没有弄到的东西补一下,也算是给各位前来询问的朋友的一些回复吧。

一、Consul服务注册之配置文件方式

1.1 重温Consul实验集群

ASP.NET Core微服务之基于Consul实现服务治理(2)

这里我们有三个Consul Server节点,一个Consul Client节点,在Client节点上跑了两个ClientService实例,分别占用8810和8820端口。至于基于Ocelot的API网关服务,还没有实现,留到以后跟各位分享。这里假设我们已经启动了这几个节点,并且能够成功访问这两个ClientService实例(事先把实例启动起来,可以通过IIS,也可以通过命令行启动Kerstel服务器运行)。

实例1:192.168.80.71:8810

ASP.NET Core微服务之基于Consul实现服务治理(2)

实例2:192.168.80.71:8820

ASP.NET Core微服务之基于Consul实现服务治理(2)

1.2 准备好json配置文件

这里我准备了一个如下所示的JSON配置文件(eg.取名为services_config.json),配置了两个服务在里边:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
1{
2    "services":[
3        {
4            "id": "EDC_DNC_MSAD_CLIENT_SERVICE_01",
5            "name" : "CAS Client Service",
6            "tags": [
7                "urlprefix-/ClientService01"
8            ],
9            "address": "192.168.80.71",
10            "port": 8810,
11            "checks": [
12                {
13                    "name": "clientservice_check",
14                    "http": "http://192.168.80.71:8810/api/health",
15                    "interval": "10s",
16                    "timeout": "5s"
17                }
18            ]
19        },
20      {
21            "id": "EDC_DNC_MSAD_CLIENT_SERVICE_02",
22            "name" : "CAS Client Service",
23            "tags": [
24                "urlprefix-/ClientService02"
25            ],
26            "address": "192.168.80.71",
27            "port": 8820,
28            "checks": [
29                {
30                    "name": "clientservice_check",
31                    "http": "http://192.168.80.71:8820/api/health",
32                    "interval": "10s",
33                    "timeout": "5s"
34                }
35            ]
36        }
37     ]
38}
39

至于配置文件的含义,这里不再赘述,和上一篇在代码中进行注册的items一致。

编辑完成后,我们在Consul Client节点中新建一个文件夹,放入json配置文件,然后启动/重启Consul Client服务:

192.168.80.71>consul agent -bind 0.0.0.0 -client 192.168.80.71 -config-dir=C:ServerConsulconfig -data-dir=C:ServerConsultempdata -node EDC.DEV.WebServer -join 192.168.80.100 

ASP.NET Core微服务之基于Consul实现服务治理(2)

启动之后,可以看到Consul已经通过扫描配置文件,去注册了这两个ClientService的实例。

1.3 通过WebUI查看服务状况

ASP.NET Core微服务之基于Consul实现服务治理(2)

可以看到,两个ClientService实例已经成功注册。

1.4 通过API进行服务发现

URL>192.168.80.100:8500/v1/catalog/service/CAS Client Service  

ASP.NET Core微服务之基于Consul实现服务治理(2)

可以看到返回了两个服务实例的信息,当然,这里建议服务名还是不要有空格为好。此外,在服务发现的过程中,会加以一定的负载均衡策略,从这两个服务实例中选择一个返回给服务消费端,比如:随机、轮询、加权轮询、基于性能的最小连接数等等。关于这一块,会在后面的API网关实践中跟大家分享。

二、Consul集群之Key/Value存储

Consul除了可以实现服务注册和服务发现之外,还提供了强大的KV(Key/Value)存储。我们可以使用Consul的分层KV存储干任何事情,比如:动态配置,特征标记,协调,leader选举等。KV存储的API是基于http的。

2.1 查看所有KV

我们可以通过命令行在consul节点中进行查询:

192.168.80.100>curl -v http://192.168.80.100:8500/v1/kv/?recurse  

ASP.NET Core微服务之基于Consul实现服务治理(2)

可以看到,返回的是404 Not Found,可见现在木有一个Key/Value存储项。

*.关于__?recurse__参数=>用来指定查看多个KV

当然我们也可以通过WebUI来查看和管理KV,如下图所示,后续我们都以Shell命令行来调用API,不会进行WebUI界面的调用。

ASP.NET Core微服务之基于Consul实现服务治理(2)

2.2 新增KV

这里假设我们要配置一个视频直播平台的账号:

192.168.80.100>curl -X PUT -d 'edisonchou' http://192.168.80.100:8500/v1/kv/web/vhallaccount

key:vhallaccount, value:edisonchou

添加后可以通过如下命令调用接口查看这个Key的Value

192.168.80.100>curl http://192.168.80.100:8500/v1/kv/web/vhallaccount

ASP.NET Core微服务之基于Consul实现服务治理(2)

*.由于Consul的Value是经过__Base64编码__的(主要是为了允许非UTF-8的字符),所以这里看到的是编码后的结果。我们可以通过解码得到最终的Value值。

2.3 验证KV是否同步

由于我们调用的是Leader节点进行的KV存储,我们想要验证一下是否在另外两个节点进行了同步,否则KV只存在一个节点达不到同步的效果。

192.168.80.101 节点:

ASP.NET Core微服务之基于Consul实现服务治理(2)

192.168.80.102 节点:

ASP.NET Core微服务之基于Consul实现服务治理(2)

可以看到该key值已经在集群中三个节点进行了同步。

2.4 编辑KV和删除KV

编辑KV其实和添加KV完全一致,如下所示:

192.168.80.100>curl -X PUT -d 'andyai' http://192.168.80.100:8500/v1/kv/web/vhallaccount  

删除KV主要用到HTTP DELETE

192.168.80.100>curl -X DELETE http://192.168.80.100:8500/v1/kv/web/vhallaccount  

这里不再演示结果。

三、Consul服务告警之Watch机制

熔断保护在Consul和Ocelot中都有实现,意思就是当一个服务不正常时(比如我们的一个服务实例挂了,Consul的健康检查机制检测到了),应该给系统维护人员给以告警。在Consul中,服务告警也是通过配置文件来实现的。

3.1 添加watch.json配置文件


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1{
2  "watches": [
3    {
4      "type": "checks",
5      "handler_type": "http",
6      "state": "critical",
7      "http_handler_config": {
8        "path": "http://192.168.80.71:9000/notice",
9        "method": "POST",
10        "timeout": "10s",
11        "header": { "Authorization": [ "token" ] }
12      }
13    }
14  ]
15}
16

*.有关watch的细节,请参考:https://www.consul.io/docs/agent/watches.html

这里编辑完成之后,就可以放到config目录下了,后面重启Consul Client Agent服务时会加载新的watches_config.json配置文件。

ASP.NET Core微服务之基于Consul实现服务治理(2)

3.2 添加NoticeService服务

新写一个ASP.NET Core WebAPI程序,其主要功能就是接受Consul POST过来的参数并调用方法发送电子邮件。

(1)Controller编写


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
1    [Route("api/[controller]")]
2    public class HomeController : Controller
3    {
4        public IConfiguration Configuration { get; }
5
6        public HomeController(IConfiguration configuration)
7        {
8            Configuration = configuration;
9        }
10
11        [HttpPost("/notice")]
12        public IActionResult Notice()
13        {
14            var bytes = new byte[10240];
15            var i = Request.Body.ReadAsync(bytes, 0, bytes.Length);
16            var content = System.Text.Encoding.UTF8.GetString(bytes).Trim('\0');
17
18            EmailSettings settings = new EmailSettings()
19            {
20                SmtpServer = Configuration["Email:SmtpServer"],
21                SmtpPort = Convert.ToInt32(Configuration["Email:SmtpPort"]),
22                AuthAccount = Configuration["Email:AuthAccount"],
23                AuthPassword = Configuration["Email:AuthPassword"],
24                ToWho = Configuration["Email:ToWho"],
25                ToAccount = Configuration["Email:ToAccount"],
26                FromWho = Configuration["Email:FromWho"],
27                FromAccount = Configuration["Email:FromAccount"],
28                Subject = Configuration["Email:Subject"]
29            };
30
31            EmailHelper.SendHealthEmail(settings, content);
32
33            return Ok();
34        }
35    }
36

不再解释这段代码。

(2)SendHealthEmail方法编写


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
1    public class EmailHelper
2    {
3        public static void SendHealthEmail(EmailSettings settings, string content)
4        {
5            try
6            {
7                dynamic list = JsonConvert.DeserializeObject(content);
8                if (list != null && list.Count > 0)
9                {
10                    var emailBody = new StringBuilder("健康检查故障:\r\n");
11                    foreach (var noticy in list)
12                    {
13                        emailBody.AppendLine($"--------------------------------------");
14                        emailBody.AppendLine($"Node:{noticy.Node}");
15                        emailBody.AppendLine($"Service ID:{noticy.ServiceID}");
16                        emailBody.AppendLine($"Service Name:{noticy.ServiceName}");
17                        emailBody.AppendLine($"Check ID:{noticy.CheckID}");
18                        emailBody.AppendLine($"Check Name:{noticy.Name}");
19                        emailBody.AppendLine($"Check Status:{noticy.Status}");
20                        emailBody.AppendLine($"Check Output:{noticy.Output}");
21                        emailBody.AppendLine($"--------------------------------------");
22                    }
23
24                    var message = new MimeMessage();
25                    message.From.Add(new MailboxAddress(settings.FromWho, settings.FromAccount));
26                    message.To.Add(new MailboxAddress(settings.ToWho, settings.ToAccount));
27
28                    message.Subject = settings.Subject;
29                    message.Body = new TextPart("plain") { Text = emailBody.ToString() };
30                    using (var client = new SmtpClient())
31                    {
32                        client.ServerCertificateValidationCallback = (s, c, h, e) => true;
33                        client.Connect(settings.SmtpServer, settings.SmtpPort, false);
34                        client.AuthenticationMechanisms.Remove("XOAUTH2");
35                        client.Authenticate(settings.AuthAccount, settings.AuthPassword);
36                        client.Send(message);
37                        client.Disconnect(true);
38                    }
39                }
40            }
41            catch(Exception ex)
42            {
43                Console.WriteLine(ex.Message);
44            }
45        }
46

这里使用的是MailKit库(支持.net core),可以通过NuGet搜索并安装,此外为何接受的参数属性是这些,大家可以看看Consul官方文档中watches页中的checks类型,见下图所示:

ASP.NET Core微服务之基于Consul实现服务治理(2)

(3)发布NoticeService到192.168.80.71服务器中,同样也可以加入Consul配置文件中:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
1{
2    "services":[
3        {
4            "id": "EDC_DNC_MSAD_CLIENT_SERVICE_01",
5            "name" : "CAS.Client.Service",
6            "tags": [
7                "urlprefix-/ClientService01"
8            ],
9            "address": "192.168.80.71",
10            "port": 8810,
11            "checks": [
12                {
13                    "name": "clientservice_check",
14                    "http": "http://192.168.80.71:8810/api/health",
15                    "interval": "10s",
16                    "timeout": "5s"
17                }
18            ]
19        },
20    {
21            "id": "EDC_DNC_MSAD_CLIENT_SERVICE_02",
22            "name" : "CAS.Client.Service",
23            "tags": [
24                "urlprefix-/ClientService02"
25            ],
26            "address": "192.168.80.71",
27            "port": 8820,
28            "checks": [
29                {
30                    "name": "clientservice_check",
31                    "http": "http://192.168.80.71:8820/api/health",
32                    "interval": "10s",
33                    "timeout": "5s"
34                }
35            ]
36        },
37    {
38            "id": "EDC_DNC_MSAD_NOTICE_SERVICE",
39            "name" : "CAS.Notice.Service",
40            "tags": [
41                "urlprefix-/NoticeService"
42            ],
43            "address": "192.168.80.71",
44            "port": 9000,
45            "checks": [
46                {
47                    "name": "noticeservice_check",
48                    "http": "http://192.168.80.71:9000/api/health",
49                    "interval": "10s",
50                    "timeout": "5s"
51                }
52            ]
53        }
54     ]
55}
56

发布完成之后,重启Consul Client节点(192.168.80.71)的Consul服务,可以看到NoticeService也注册成功:

ASP.NET Core微服务之基于Consul实现服务治理(2)

3.3 测试服务告警

(1)手动在IIS中关闭一个ClientService服务,例如:这里我关闭了ClientService.01

ASP.NET Core微服务之基于Consul实现服务治理(2)

(2)查看自动发送的Email内容:从Email中我们可以知道哪个Server节点的哪个Service出了问题,并且可以大概了解原因(Check Output),这时我们的系统维护人员就该起床加班了。

ASP.NET Core微服务之基于Consul实现服务治理(2)

*.需要注意的是确保你的虚拟机可以访问外网,不然是发布出来Email的。

4.小结

本篇将上篇中遗留的内容进行了弥补,下篇将开始基于Ocelot+Polly的API网关服务实践,敬请期待,我要睡了。

ASP.NET Core微服务之基于Consul实现服务治理(2)

参考资料

桂素伟,《Ocelot+Consul实践》

卓一抗,《学习Consul》

陈冲,《Consul分布式集群搭建&简单功能测试&故障恢复》

给TA打赏
共{{data.count}}人
人已打赏
安全经验

3天学会Jenkins_13_自动部署项目到远程服务器

2021-10-11 16:36:11

安全经验

安全咨询服务

2022-1-12 14:11:49

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索