网站建设需要服务器吗,高端轻奢品牌,做网站虚拟主机价格,有啥可以自己做网站的软件更多配置和原理#xff1a;https://blog.csdn.net/liuzhuchen/article/details/81913562
从2016年起就开始接触Consul#xff0c;使用的主要目的就是做服务发现#xff0c;后来逐步应用于生产环境#xff0c;并总结了少许使用经验。最开始使用Consul的人不多#xff0c;为…更多配置和原理https://blog.csdn.net/liuzhuchen/article/details/81913562
从2016年起就开始接触Consul使用的主要目的就是做服务发现后来逐步应用于生产环境并总结了少许使用经验。最开始使用Consul的人不多为了方便交流创建了一个QQ群群号在最后这两年微服务越来越火使用Consul的人也越来越多目前群里已有400多人经常有人问一些问题比如
服务注册到节点后其他节点为什么没有同步Client是干什么的Client有什么作用能不能直接注册到Server是否只有Server节点就够了服务信息是保存在哪里的如果节点挂了健康检查能不能转移到别的节点
有些人可能对服务注册和发现还没有概念有些人可能使用过其它服务发现的工具比如zookeeperetcd会有一些先入为主的经验。这篇文章将结合Consul的官方文档和自己的实际经验谈一下Consul做服务发现的方式文中尽量不依赖具体的框架和开发语言从原理上进行说明希望能够讲清楚上边的几个问题。
为什么使用服务发现
防止硬编码、容灾、水平扩缩容、提高运维效率等等只要你想使用服务发现总能找到合适的理由。
一般的说法是因为使用微服务架构。传统的单体架构不够灵活不能很好的适应变化从而向微服务架构进行转换而伴随着大量服务的出现管理运维十分不便于是开始搞一些自动化的策略服务发现应运而生。所以如果需要使用服务发现你应该有一些对服务治理的痛点。
但是引入服务发现就可能引入一些技术栈增加系统总体的复杂度如果你只有很少的几个服务比如10个以下并且业务不怎么变化吞吐量预计也很稳定可能就没有必要使用服务发现。
Consul内部原理
下面这张图来源于Consul官网很好的解释了Consul的工作原理先大致看一下。 首先Consul支持多数据中心在上图中有两个DataCenter他们通过Internet互联同时请注意为了提高通信效率只有Server节点才加入跨数据中心的通信。
在单个数据中心中Consul分为Client和Server两种节点所有的节点也被称为AgentServer节点保存数据Client负责健康检查及转发数据请求到ServerServer节点有一个Leader和多个FollowerLeader节点会将数据同步到FollowerServer的数量推荐是3个或者5个在Leader挂掉的时候会启动选举机制产生一个新的Leader。
集群内的Consul节点通过gossip协议流言协议维护成员关系也就是说某个节点了解集群内现在还有哪些节点这些节点是Client还是Server。单个数据中心的流言协议同时使用TCP和UDP通信并且都使用8301端口。跨数据中心的流言协议也同时使用TCP和UDP通信端口使用8302。
集群内数据的读写请求既可以直接发到Server也可以通过Client使用RPC转发到Server请求最终会到达Leader节点在允许数据轻微陈旧的情况下读请求也可以在普通的Server节点完成集群内数据的读写和复制都是通过TCP的8300端口完成。
Consul服务发现原理
下面这张图是自己画的基本描述了服务发现的完整流程先大致看一下。 首先需要有一个正常的Consul集群有Server有Leader。这里在服务器Server1、Server2、Server3上分别部署了Consul Server假设他们选举了Server2上的Consul Server节点为Leader。这些服务器上最好只部署Consul程序以尽量维护Consul Server的稳定。
然后在服务器Server4和Server5上通过Consul Client分别注册Service A、B、C这里每个Service分别部署在了两个服务器上这样可以避免Service的单点问题。服务注册到Consul可以通过HTTP API8500端口的方式也可以通过Consul配置文件的方式。Consul Client可以认为是无状态的它将注册信息通过RPC转发到Consul Server服务信息保存在Server的各个节点中并且通过Raft实现了强一致性。
最后在服务器Server6中Program D需要访问Service B这时候Program D首先访问本机Consul Client提供的HTTP API本机Client会将请求转发到Consul ServerConsul Server查询到Service B当前的信息返回最终Program D拿到了Service B的所有部署的IP和端口然后就可以选择Service B的其中一个部署并向其发起请求了。如果服务发现采用的是DNS方式则Program D中直接使用Service B的服务发现域名域名解析请求首先到达本机DNS代理然后转发到本机Consul Client本机Client会将请求转发到Consul ServerConsul Server查询到Service B当前的信息返回最终Program D拿到了Service B的某个部署的IP和端口。
图中描述的部署架构笔者认为是最普适最简单的方案从某些默认配置或设计上看也是官方希望使用者采用的方案比如8500端口默认监听127.0.0.1当然有些同学不赞同后边会提到其他方案。
Consul实际使用
为了更快的熟悉Consul的原理及其使用方式最好还是自己实际测试下。
Consul安装十分简单但是在一台机器上不方便搭建集群进行测试使用虚拟机比较重所以这里选择了docker。这里用了Windows 10需要是专业版因为Windows上的Docker依赖Hyper-V而这个需要专业版才能支持。这里对于Docker的使用不会做过多的描述如果遇到相关问题请搜索一下。
安装Docker
通过这个地址下载安装
https://store.docker.com/editions/community/docker-ce-desktop-windows
安装完成后打开 Windows PowerShell输入docker –version如果正常输出docker版本就可以了。
启动Consul集群
在 Windows PowerShell中执行命令拉取最新版本的Consul镜像 docker pull consul然后就可以启动集群了这里启动4个Consul Agent3个Server会选举出一个leader1个Client。 #启动第1个Server节点集群要求要有3个Server将容器8500端口映射到主机8900端口同时开启管理界面
docker run -d --nameconsul1 -p 8900:8500 -e CONSUL_BIND_INTERFACEeth0 consul agent --servertrue --bootstrap-expect3 --client0.0.0.0 -ui#启动第2个Server节点并加入集群
docker run -d --nameconsul2 -e CONSUL_BIND_INTERFACEeth0 consul agent --servertrue --client0.0.0.0 --join 172.17.0.2#启动第3个Server节点并加入集群
docker run -d --nameconsul3 -e CONSUL_BIND_INTERFACEeth0 consul agent --servertrue --client0.0.0.0 --join 172.17.0.2#启动第4个Client节点并加入集群
docker run -d --nameconsul4 -e CONSUL_BIND_INTERFACEeth0 consul agent --serverfalse --client0.0.0.0 --join 172.17.0.2第1个启动容器的IP一般是172.17.0.2后边启动的几个容器IP会排着来172.17.0.3、172.17.0.4、172.17.0.5。
这些Consul节点在Docker的容器内是互通的他们通过桥接的模式通信。但是如果主机要访问容器内的网络需要做端口映射。在启动第一个容器时将Consul的8500端口映射到了主机的8900端口这样就可以方便的通过主机的浏览器查看集群信息。 进入容器consul1 docker exec -it consul1 /bin/sh#执行ls后可以看到consul就在根目录
ls输入exit可以跳出容器。
服务注册
自己写一个web服务用最熟悉的开发语言就好了不过需要在容器中能够跑起来可能需要安装运行环境比如python、java、.net core等的sdk及web服务器需要注意的是Consul的docker镜像基于alpine系统具体运行环境的安装请搜索一下。
这里写了一个hello服务通过配置文件的方式注册到Consul服务的相关信息
namehello服务名称需要能够区分不同的业务服务可以部署多份并使用相同的name注册。idhello1服务id在每个节点上需要唯一如果有重复会被覆盖。address172.17.0.5服务所在机器的地址。port5000服务的端口。健康检查地址http://localhost:5000/如果返回HTTP状态码为200就代表服务健康每10秒Consul请求一次请求超时时间为1秒。
请将下面的内容保存成文件services.json并上传到容器的/consul/config目录中。 {services: [{id: hello1,name: hello,tags: [primary],address: 172.17.0.5,port: 5000,checks: [{http: http://localhost:5000/,tls_skip_verify: false,method: Get,interval: 10s,timeout: 1s}]}]
}复制到consul config目录 docker cp {这里请替换成services.json的本地路径} consul4:/consul/config重新加载consul配置 consul reload然后这个服务就注册成功了。可以将这个服务部署到多个节点比如部署到consul1和consul4并同时运行。 服务发现
服务注册成功以后调用方获取相应服务地址的过程就是服务发现。Consul提供了多种方式。
HTTP API方式 curl http://127.0.0.1:8500/v1/health/service/hello?passingfalse返回的信息包括注册的Consul节点信息、服务信息及服务的健康检查信息。这里用了一个参数passingfalse会自动过滤掉不健康的服务包括本身不健康的服务和不健康的Consul节点上的服务从这个设计上可以看出Consul将服务的状态绑定到了节点的状态。
如果服务有多个部署会返回服务的多条信息调用方需要决定使用哪个部署常见的可以随机或者轮询。为了提高服务吞吐量以及减轻Consul的压力还可以缓存获取到的服务节点信息不过要做好容错的方案因为缓存服务部署可能会变得不可用。具体是否缓存需要结合自己的访问量及容错规则来确定。
上边的参数passing默认为false也就是说不健康的节点也会返回结合获取节点全部服务的方法这里可以做到获取全部服务的实时健康状态并对不健康的服务进行报警处理。
DNS方式
hello服务的域名是hello.service.dc1.consul后边的service代表服务固定dc1是数据中心的名字可以配置最后的consul也可以配置。
官方在介绍DNS方式时经常使用dig命令进行测试但是alpine系统中没有dig命令也没有相关的包可以安装但是有人实现了下载下来解压到bin目录就可以了。 curl -L https://github.com/sequenceiq/docker-alpine-dig/releases/download/v9.10.2/dig.tgz\|tar -xzv -C /usr/local/bin然后执行dig命令 dig 127.0.0.1 -p 8600 hello.service.dc1.consul. ANY如果报错parse of /etc/resolv.conf failed 请将resolv.conf中的search那行删掉。
正常的话可以看到返回了服务部署的IP信息如果有多个部署会看到多个如果某个部署不健康了会自动剔除包括部署所在节点不健康的情况。需要注意这种方式不会返回服务的端口信息。
使用DNS的方式可以在程序中集成一个DNS解析库也可以自定义本地的DNS Server。自定义本地DNS Server是指将.consul域的请求全部转发到Consul AgentWindows上有DNS AgentLinux上有Dnsmasq对于非Consul提供的服务则继续请求原DNS使用DNS Server时Consul会随机返回具体服务的多个部署中的一个仅能提供简单的负载均衡。
DNS缓存问题DNS缓存一般存在于应用程序的网络库、本地DNS客户端或者代理Consul Sever本身可以认为是没有缓存的为了提高集群DNS吞吐量可以设置使用普通Server上的陈旧数据但影响一般不大DNS缓存可以减轻Consul Server的访问压力但是也会导致访问到不可用的服务。使用时需要根据实际访问量和容错能力确定DNS缓存方案。
Consul Template
Consul Template是Consul官方提供的一个工具严格的来说不是标准的服务发现方式。这个工具会通过Consul监听数据变化然后替换模板中使用的标签并发布替换后的文件到指定的目录。在nginx等web服务器做反向代理和负载均衡时特别有用。
Consul的docker镜像中没有集成这个工具需要自己安装比较简单 curl -L https://releases.hashicorp.com/consul-template/0.19.5/consul-template_0.19.5_linux_amd64.tgz\|tar -xzv -C /usr/local/bin然后创建一个文件in.tpl内容为 {{ range service hello }}
server {{ .Name }}{{ .Address }}:{{ .Port }}{{ end }}这个标签会遍历hello服务的所有部署并按照指定的格式输出。在此文件目录下执行 nohup consul-template -template in.tpl:out.txt 现在你可以cat out.txt查看根据模板生产的内容新增或者关闭服务文件内容会自动更新。
此工具我没有用在生产环境详细使用请访问https://github.com/hashicorp/consul-template
节点和服务注销
节点和服务的注销可以使用HTTP API:
注销任意节点和服务/catalog/deregister注销当前节点的服务/agent/service/deregister/:service_id
注意
如果注销的服务还在运行则会再次同步到catalog中因此应该只在agent不可用时才使用catalog的注销API。
节点在宕机时状态会变为failed默认情况下72小时后会被从集群移除。
如果某个节点不继续使用了也可以在本机使用consul leave命令或者在其它节点使用consul force-leave 节点Id则节点上的服务和健康检查全部注销。
Consul的健康检查
Consul做服务发现是专业的健康检查是其中一项必不可少的功能其提供Script/TCP/HTTPInterval以及TTL等多种方式。服务的健康检查由服务注册到的Agent来处理这个Agent既可以是Client也可以是Server。
很多同学都使用ZooKeeper或者etcd做服务发现使用Consul时发现节点挂掉后服务的状态变为不可用了所以有同学问服务为什么不在各个节点之间同步这个根本原因是服务发现的实现原理不同。
Consul与ZooKeeper、etcd的区别
后边这两个工具是通过键值存储来实现服务的注册与发现。
ZooKeeper利用临时节点的机制业务服务启动时创建临时节点节点在服务就在节点不存在服务就不存在。etcd利用TTL机制业务服务启动时创建键值对定时更新ttlttl过期则服务不可用。
ZooKeeper和etcd的键值存储都是强一致性的也就是说键值对会自动同步到多个节点只要在某个节点上存在就可以认为对应的业务服务是可用的。
Consul的数据同步也是强一致性的服务的注册信息会在Server节点之间同步相比ZK、etcd服务的信息还是持久化保存的即使服务部署不可用了仍旧可以查询到这个服务部署。但是业务服务的可用状态是由注册到的Agent来维护的Agent如果不能正常工作了则无法确定服务的真实状态并且Consul是相当稳定了Agent挂掉的情况下大概率服务器的状态也可能是不好的此时屏蔽掉此节点上的服务是合理的。Consul也确实是这样设计的DNS接口会自动屏蔽挂掉节点上的服务HTTP API也认为挂掉节点上的服务不是passing的。
鉴于Consul健康检查的这种机制同时避免单点故障所有的业务服务应该部署多份并注册到不同的Consul节点。部署多份可能会给你的设计带来一些挑战因为调用方同时访问多个服务实例可能会由于会话不共享导致状态不一致这个有许多成熟的解决方案可以去查询这里不做说明。
健康检查能不能支持故障转移
上边提到健康检查是由服务注册到的Agent来处理的那么如果这个Agent挂掉了会不会有别的Agent来接管健康检查呢答案是否定的。
从问题产生的原因来看在应用于生产环境之前肯定需要对各种场景进行测试没有问题才会上线所以显而易见的问题可以屏蔽掉如果是新版本Consul的BUG导致的此时需要降级如果这个BUG是偶发的那么只需要将Consul重新拉起来就可以了这样比较简单如果是硬件、网络或者操作系统故障那么节点上服务的可用性也很难保障不需要别的Agent接管健康检查。
从实现上看选择哪个节点是个问题这需要实时或准实时同步各个节点的负载状态而且由于业务服务运行状态多变即使当时选择出了负载比较轻松的节点无法保证某个时段任务又变得繁重可能造成新的更大范围的崩溃。如果原来的节点还要启动起来那么接管的健康检查是否还要撤销如果要需要记录服务们最初注册的节点然后有一个监听机制来触发如果不要通过服务发现就会获取到很多冗余的信息并且随着时间推移这种数据会越来越多系统变的无序。
从实际应用看节点上的服务可能既要被发现又要发现别的服务如果节点挂掉了仅提供被发现的功能实际上服务还是不可用的。当然发现别的服务也可以不使用本机节点可以通过访问一个Nginx实现的若干Consul节点的负载均衡来实现这无疑又引入了新的技术栈。
如果不是上边提到的问题或者你可以通过一些方式解决这些问题健康检查接管的实现也必然是比较复杂的因为分布式系统的状态同步是比较复杂的。同时不要忘了服务部署了多份挂掉一个不应该影响系统的快速恢复所以没必要去做这个接管。
Consul的其它部署架构
如果你实在不想在每个主机部署Consul Client还有一个多路注册的方案可供选择这是交流群中获得的思路。 如图所示在专门的服务器上部署Consul Client然后每个服务都注册到多个Client这里为了避免服务单点问题还是每个服务部署多份需要服务发现时程序向一个提供负载均衡的程序发起请求该程序将请求转发到某个Consul Client。这种方案需要注意将Consul的8500端口绑定到私网IP上默认只有127.0.0.1。
这个架构的优势
Consul节点服务器与应用服务器隔离互相干扰少不用每台主机都部署Consul方便Consul的集中管理某个Consul Client挂掉的情况下注册到其上的服务仍有机会被访问到
但也需要注意其缺点
引入更多技术栈负载均衡的实现不仅要考虑Consul Client的负载均衡还要考虑负载均衡本身的单点问题。Client的节点数量单个Client如果注册的服务太多负载较重需要有个算法比如hash一致合理分配每个Client上的服务数量以及确定Client的总体数量。服务发现要过滤掉重复的注册因为注册到了多个节点会认为是多个部署DNS接口不会有这个问题。
这个方案其实还可以优化服务发现使用的负载均衡可以直接代理Server节点因为相关请求还是会转发到Server节点不如直接就发到Server。
是否可以只有Server
这个问题的答案还是有关服务数量的问题首先Server的节点数量不是越多越好3个或者5个是推荐的数量数量越多数据同步的处理越慢强一致性然后每个节点可以注册的服务数量是有上限的这个受限于软硬件的处理能力。所以如果你的服务只有10个左右只有Server问题是不大的但是这时候有没有必要使用Consul呢因此正常使用Consul的时候还是要有Client才好这也符合Consul的反熵设计。