.Net Core微服务系列--服务发现
什么是服务发现
首先我们先思考一个问题,当我们在浏览器中输入一个域名比如baidu.com,然后发生了什么才能让我们访问到百度的网页?简单来说,浏览器会首先从主机的hosts文件中查看是否有baidu.com对应ip的映射,如果有就直接用hosts文件得到的ip来请求数据,如果没有那么就需要去DNS服务器来请求ip地址,Dns服务器在自己数据库中查找域名对应的ip,如果有多个ip那么需要用DNS负载均衡器根据策略返回一个ip。DNS服务器简单来看就是提供了一个域名和服务器映射关系的注册和查询的东西,这个其实就是服务发现。所以我们可以说DNS就是实现了服务发现,当然DNS有两点局限性使得我们无法直接应用到微服务中。
- DNS服务器不支持动态变更。我在前面的文章中有提到过微服务有按需虚拟化的概念,我们的节点可能会根据需要在虚拟化平台中动态的增加,减少,丢弃,DNS服务器就不能支撑我们微服务的动态变化
- DNS服务器也没办法了解到每个实例的情况,因此无法实现真正的负载均衡
为什么有服务发现
以前我们服务一般运行在物理机器上,服务实例的地址相对于固定,我们只需要在调用方用配置的方式获取服务实例的网络地址就行,但是对于现在基于云端,容器化的微服务来说服务实例的网络地址一般都是动态变化的,在实例升级,扩展,离线的时候都会经常改变,所以才有了服务发现。服务发现提供了服务注册,服务目录,服务查询等功能,并且会动态的更新服务目录来保证调用方获取的服务列表是最新可用的。
常用服务发现工具
这个就直接贴网上的图片了

本篇文章就选用Consul来进行Demo的测试了。
服务发现均衡器
当我们从服务发现工具中获取一个实例集群的地址,应该会是多个(当然这个集群也可以直接暴露的是一个负债均衡的地址),客户端可以自己根据策略来进行负载均衡处理,但是这样额外增加了每个客户端工作,所以我们可以结合现在的HA均衡器和服务发现工具来实现这个这个功能,比如 Nginx + Consul Template。大概流程如图

搭建Consul测试环境
Consul的介绍网上一大堆,我就直接贴以下他的特性然后直接进入到测试阶段。
- 服务发现(Service Discovery):客户端通过 Consul 提供服务,其他客户端可以通过 Consul 利用 dns 或者 http 发现依赖服务
- 健康检查(Health Checking): Consul 提供任务的健康检查,可以用来操作或者监控集群的健康,也可以在服务发现时去除失效的服务
- 键值对存储(Key/Value Store): 存储层级键值对
- 多数据中心(Multi Datacenter): Consul 支持开箱即用的多数据中心
因为我只有一台ubuntu和一台windows,准备再ubuntu.docker,windows 分别运行一个Node,docker上的node就只是用来满足三个服务节点,本次测试不会在这个节点上配置服务。
安装
Linux(Ubuntu 18.04)上安装Consul并检查安装结果
到官网根据系统版本下载压缩包https://www.consul.io/downloads.html
解压之后就是一个consul的可执行文件,将其添加到系统的环境变量中,并检查是否可运行
unzip consul_1.4.4_linux_amd64.zip
sudo cp -a consul /usr/bin
consul -v
Ubutu启动Agent
consul必须启动agent才能使用,有两种启动模式server和client,还有一个官方自带的ui。server用与持久化服务信息,集群官方建议3或5个节点。client只用与于server交互。ui可以查看集群情况的。
先启动一个Server
consul agent -bootstrap-expect 3 -server -data-dir /path/to/data-dir -node=linuxnode1 -bind=YourIP -config-dir /path/to/config-dir -enable-script-checks=true -datacenter=dc1 -ui
参数解释:
-bootstrap-expect:集群期望的节点数,只有节点数量达到这个值才会选举leader。
-server: 运行在server模式
-data-dir:指定数据目录,其他的节点对于这个目录必须有读的权限
-node:指定节点的名称
-bind:为该节点绑定一个地址
-config-dir:指定配置文件,定义服务的,默认所有一.json结尾的文件都会读
-enable-script-checks=true:设置检查服务为可用
-datacenter: 数据中心没名称,
-ui: 使用自带的UI
这些命令行参数 也可以直接在配置文件中进行设置,如下所示
{
"datacenter": "dc1,
"data_dir": "/your/data/path,
"log_level": "INFO",
"node_name": "foobar",
"server": true,
"watches": [
{
"type": "checks",
"handler": "/usr/bin/health-check-handler.sh"
}
]
}
*其中Watch节点是用于服务告警
因为我们集群期望节点数是3 所以现在的consul agent 是报错状态

docker启动Agent
docker run -d -p 18500:8500 -p 18300:8300 -p 18301:8301 --name consulserver consul agent -server -node=dockernode1 -client 0.0.0.0 -datacenter=dc1 -retry-join={KnowCluserIP}
windows启动Agent
windows跟linux操作一样下载压缩包 解压之后将consul 可执行文件加入系统的环境变量
打开cmd 执行命令
consul agent -bootstrap-expect 2 -server -data-dir /path/to/data-dir -node=cn1 -bind=YourIP -config-dir /path/to/config-dir -enable-script-checks=true -datacenter=dc1 -retry-join=KnowClusterIp
参数解释
-retry-join:加入到已有的集群中支持重试
再执行 docker members 可以看到我们三个Server已经启动并加入了相同的集群中了

通过ip:8500 访问自带的Web管理器

也可以很直观的看到我们的三个node,我现在停掉dockernode1的容器

可以看到dockernode1处于异常状态了
OK,到现在为止我们consul的测试环境是搭建起来了,但是我们的三个节点中都没有服务,接下来我们会向这几个节点中都加入一些服务。
服务注册
创建一个ASP.NET CORE WebApi程序
打开VS CODE 并运行
dotnet new webapi
一个简单的api程序就建立好了,我们添加一点简单的代码用于健康检查
[Route("api/Health")]
public class HealthController : Controller
{
[HttpGet]
public IActionResult Get() => Ok("ok");
}
使用AntDepoly(https://github.com/yuzd/AntDeployAgent)发布到windows服务器上
编写dockerfile
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /app
# copy csproj and restore as distinct layers
COPY *.csproj ./aspnetapi/
WORKDIR /app/aspnetapi
RUN dotnet restore
# copy everything else and build app
COPY . ./aspnetapi/
WORKDIR /app/aspnetapi
RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS runtime
WORKDIR /app
COPY --from=build /app/aspnetapi/out ./
ENTRYPOINT ["dotnet", "aspnet-healthcheck.dll"]
直接去构建镜像 或者直接用我放到hub中的镜像来运行两个服务
docker run -it --rm -p 8001:80 -d --name ubuntunode1 yhx1990126/aspnetcore-healthcheck:1.0
docker run -it --rm -p 8002:80 -d --name ubuntunode2 yhx1990126/aspnetcore-healthcheck:1.0
OK,现在我们就已经IIS和docker中分别部署了两套服务,接着把这四个服务注册到Consul中
注册服务
在前面运行Consul Agent配置的文件夹中建立一个service.json的配置文件(当指定了config-dir后,consul会到目录中根据词典顺序加载配置文件),service.json的内容如下
{
"services": [{
"id": "ubuntuservice01",
"name": "ubuntuservice",
"tags": ["ubuntu"],
"address": "192.168.0.149",
"port": 8001,
"checks": [{
"http": "http://192.168.0.149:8001/api/Health",
"interval": "10s"
}]
},
{
"id": "ubuntuservice02",
"name": "ubuntuservice",
"tags": ["ubuntu"],
"address": "192.168.0.149",
"port": 8002,
"checks": [{
"http": "http://192.168.0.149:8001/api/Health",
"interval": "10s"
}]
}
]
}
两个服务用的同一个name,当后面从Consul获取IP的时候就会拿到这两个服务的IP,Json文件中的Checks节点是用来进行健康检查的,更多管service的配置可以参照官方文档https://www.consul.io/docs/agent/services.html
在windows上同样建立相同的Json文件,修改一下name和IP就行,最后运行命令
consul reload
这个命令是Consul用来重新加载配置的,支持重新加载的配置如下
- Log level
- Checks
- Services
- Watches
- HTTP Client Address
- TLS Configuration
- Please be aware that this is currently limited to reload a configuration that is already TLS enabled. You cannot enable or disable TLS only with reloading.
- Node Metadata
- Metric Prefix Filter
- Discard Check Output
- RPC rate limiting
OK,骚等几秒,直接去web界面看结果


可以看到我们的服务已经注册成功了,调用接口来获取服务地址试试
http://192.168.0.149:8500/v1/catalog/service/ubuntuservice


可以看到我们返回了我们注册的两个地址。
我们现在是用配置文件的方式注册服务的,当然也可以在asp.net core 程序中进行注册,但是这样对代码有入侵所以还是推荐配置文件的方式来注册。有关其他的配置比如 watch,check可以参考官方,这里就不进行实验了。
服务消费
本来计划接下来是讲解在asp.net core 程序中怎么消费服务的,但是想了下其实没有什么好说的,无外乎就是利用Consul提供的接口来进行服务的寻址,然后利用获取到的接口进行调用,这一块内容就打算放到后期与网关结合那一块去实现。
小结
今天了解了服务发现在微服务中的作用,了解了Consul的基本使用,但是基本没有跟.net core相关的东西,
我之所以还是把这篇文章放到微服务之路的系列文章里是因为服务发现在微服务中地位太重要了,所以还是决定要单独写一篇来介绍服务发现。
最后应该会发现,在微服务的体系中,如果用Consul类似的工具来实现服务发现基础设施,为了保证高可用性,无疑会增加系统的复杂性,所以我们也可以选择一些部署环境内置了服务发现的工具 比如k8s来减少我们自己搭建环境的复杂性和成本。
.Net Core微服务系列--服务发现的更多相关文章
- 玩转Windows服务系列——服务运行、停止流程浅析
通过研究Windows服务注册卸载的原理,感觉它并没有什么特别复杂的东西,Windows服务正在一步步退去它那神秘的面纱,至于是不是美女,大家可要睁大眼睛看清楚了. 接下来研究一下Windows服务的 ...
- 玩转Windows服务系列——服务运行、停止流程浅析
原文:玩转Windows服务系列——服务运行.停止流程浅析 通过研究Windows服务注册卸载的原理,感觉它并没有什么特别复杂的东西,Windows服务正在一步步退去它那神秘的面纱,至于是不是美女,大 ...
- 玩转Windows服务系列——Debug、Release版本的注册和卸载,及其原理
Windows服务Debug版本 注册 Services.exe -regserver 卸载 Services.exe -unregserver Windows服务Release版本 注册 Servi ...
- 玩转Windows服务系列——无COM接口Windows服务启动失败原因及解决方案
将VS创建的Windows服务项目编译生成的程序,通过命令行 “服务.exe -Service”注册为Windows服务后,就可以通过服务管理器进行管理了. 问题 通过服务管理器进行启动的时候,发现服 ...
- 玩转Windows服务系列——Windows服务启动超时时间
最近有客户反映,机房出现断电情况,服务器的系统重新启动后,数据库服务自启动失败.第一次遇到这种情况,为了查看是不是断电情况导致数据库文件损坏,从客户的服务器拿到数据库的日志,进行分析. 数据库工作机制 ...
- 玩转Windows服务系列——Debug、Release版本的注册和卸载,及其原理
原文:玩转Windows服务系列——Debug.Release版本的注册和卸载,及其原理 Windows服务Debug版本 注册 Services.exe -regserver 卸载 Services ...
- 玩转Windows服务系列——给Windows服务添加COM接口
当我们运行一个Windows服务的时候,一般情况下,我们会选择以非窗口或者非控制台的方式运行,这样,它就只是一个后台程序,没有界面供我们进行交互. 那么当我们想与Windows服务进行实时交互的时候, ...
- 玩转Windows服务系列——使用Boost.Application快速构建Windows服务
玩转Windows服务系列——创建Windows服务一文中,介绍了如何快速使用VS构建一个Windows服务.Debug.Release版本的注册和卸载,及其原理和服务运行.停止流程浅析分别介绍了Wi ...
- 玩转Windows服务系列——创建Windows服务
创建Windows服务的项目 新建项目->C++语言->ATL->ATL项目->服务(EXE) 这样就创建了一个Windows服务项目. 生成的解决方案包含两个项目:Servi ...
随机推荐
- Ubuntu18.04安装RTX2080Ti+NVIDIA驱动+CUDA
Ubuntu18.04安装RTX 2080Ti 与 Cuda10 ==========血泪更新========= 如果可以使用ppa安装最方便了 具体参考:https://www.cnblogs.co ...
- @Formula
@Formula 计算临时属性. 相当于可以关联查询字段,然后放在实体中当做属性使用. 任务:在User实体层,增加一个额外的属性,来获取Test表中的name字段. 1 表结构 User表 Tes ...
- offset系列属性
offset系列:获取元素的相关的样式属性的值 offsetwidth:获取元素的宽 offsetheight:获取元素的高 offsetleft:获取元素距离左边位置的值 offsettop;获取元 ...
- PHP Catchable fatal error: Argument 2 passed to Illuminate\Routing\UrlGenerator::__construct()
laravel 项目的根目录下 运行composer update之后,报了包含 PHP Catchable fatal error: Argument 2 passed to Illuminate\ ...
- [笔记]Laravel TDD 胡乱记录
TDD: 测试驱动开发(Test-Driven Development),TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码. -- 载自TDD百度百科 参考 ...
- JAVA算法之简单排序
冒泡排序: 在概念上是排序算法中最简单的,但是运行起来非常慢,冒泡排序遵循以下几个规则(假如我们现在要给一队打乱的足球队员排序): 比较两个队员 如果左边的队员比右边的高,则交换位置 向右移动一位,比 ...
- JavaWeb三大组件—过滤器filter
JavaWeb三大组件 1. 都需要在web.xml中进行配置ServletListener(2个感知监听器不需要配置)Filter 2. 过滤器 它会在一组资源(jsp.servlet..css.. ...
- 使用Navicat连接管理远程linux服务器上的mysql数据库
第一步:选择连接,选择mysql 第二步:填写下面弹出框的信息:连接名随便写,主机名或IP地址:写上服务器的ip. 端口不变 用户名不变. 密码:输入服务器数据库的密码12345678. 接着测 ...
- 动态调整Log4j日志级别
log4j2.xml配置文件中支持配置monitorInterval参数,检测到配置改变后重新加载,达到动态调整日志级别的效果. 故调整日志级别无须手动重启服务. log4j2.xml配置文件示意: ...
- java_打印流
public class transientTest { /** * 反序列化操作2 * 序列化后的文件被修改后进行反序列化时会报错 * 决绝方法: * 手动添加序列号Serializable中有声明 ...