服务发现

其实简单说,服务发现就是解耦服务与IP地址之间的硬绑定关系,
以典型的集群为例,对于集群来说,是有多个节点的,这些节点对应多个IP(或者同一个IP的不同端口号),集群中不同节点责任是不一样的。
比如说一个数据集群中,可以分为读节点或者写节点,写节点和读节点都是相对的,不是硬绑定的,某一个逻辑节点,随着故障转移及恢复,是可以变换身份的(写变读,读变写;主降从,从升主等等)
集群对外提供服务的时候,对于外界来说,集群中节点身份变换的时候需要对外透明,外界无需因为集群节点的身份变换而更改配置,这就需要一个解耦合的服务。
Consul,zookeeper等中间件,就是做这个透明转换的,也就是服务发现。这里简单测试consul作为服务发现的实现。
Consul是一种服务解耦解决方案(service mesh solution,纠结了好久不知道怎么翻译),提供具有服务发现,配置和分段功能的全功能控制系统(control plane)。
这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建完整的服务解耦。 即便是用了谷歌翻译的情况下,这段翻译纠结了半天,不知道怎么翻译合适。

如下是按照自己对consul做服务发现的理解,简单整理的逻辑结构图,其原理还是比较容易理解的。

Consul is a service mesh solution providing a full featured control plane with service discovery, configuration, and segmentation functionality. Each of these features can be used individually as needed, or they can be used together to build a full service mesh. Consul requires a data plane and supports both a proxy and native integration model. Consul ships with a simple built-in proxy so that everything works out of the box, but also supports 3rd party proxy integrations such as Envoy. https://www.consul.io/intro/index.html
它提供如下几个关键功能:
服务发现:
  Consul的某些客户端可以提供一个服务,例如api或者mysql,其它客户端可以使用Consul去发现这个服务的提供者。
  使用DNS或者HTTP,应用可以很容易的找到他们所依赖的服务。
健康检查:
  Consul客户端可以提供一些健康检查,这些健康检查可以关联到一个指定的服务(服务是否返回200 OK),也可以关联到本地节点(内存使用率是否在90%以下)。
  这些信息可以被一个操作员用来监控集群的健康状态,被服务发现组件路由时用来远离不健康的主机。
键值存储: 
  应用可以使用Consul提供的分层键值存储用于一些目的,包括动态配置、特征标记、协作、leader选举等等。通过一个简单的HTTP API可以很容易的使用这个组件。
多数据中心: 
  Consul对多数据中心有非常好的支持,这意味着Consul用户不必担心由于创建更多抽象层而产生的多个区域。
Consul被设计为对DevOps群体和应用开发者友好,他非常适合现代的、可伸缩的基础设施。
 
 
本文基于docker来实现consul的服务发现配置,方法consul agent是通过json注册的模式实现服务注册,
其中consul的服务端是3节点的集群,客户点是6节点3主3从的redis服务器集群,consul实现redis集群中读写服务注册于发现。
尽管Redis cluster有多IP方式驱动连接,这里仅仅为了测试“服务发现”的。
其实本来想测试MySQL单主模式的MGR,实现读写分离的服务发现,但是MySQL有点太重了,机器配置不够,所以做了Redis的集群来测试服务发现
 
 
consul服务端集群安装配置
作为服务发现的载体,consul是可以使用单节点运行的,作为解析服务的载体,是一个非常重要的角色,集群化具有更强的抗灾性,因此更多的时候是以多节点集群的方式运行解析服务的这个载体。
这里使用三个节点作为consul的集群服务端来运行,三个consul的服务节点IP分别是:172.18.0.11 ,172.18.0.12,172.18.0.13,需要固定IP
docker network create --subnet=172.18.0.11/16 mynetwork 
docker run -itd --name consul01 --net mynetwork --ip 172.18.0.11 -v /usr/local/docker_file/consul01/:/usr/local/ centos  
docker run -itd --name consul02 --net mynetwork --ip 172.18.0.12 -v /usr/local/docker_file/consul02/:/usr/local/ centos  
docker run -itd --name consul03 --net mynetwork --ip 172.18.0.13 -v /usr/local/docker_file/consul03/:/usr/local/ centos  
分别在每个容器中创建consul服务(unzip consul_1.6.2_linux_amd64.zip解压缩即可,非常简单)
三个容器节点的server.json节点配置文件如下,唯一的区别就是bind_addr指定为当前节点的IP
如下是172.18.0.11节点的配置,不同节点仅需修改bind_addr为对应机器(容器)的IP

/usr/local/server.json
{
"datacenter": "dc1",
"data_dir": "/usr/local/",
"log_level": "INFO",
"server": true,
"bootstrap_expect": 3,
"bind_addr": "172.18.0.11",
"client_addr": "0.0.0.0",
"start_join": ["172.18.0.11","172.18.0.12","172.18.0.13"],
"ui":true
}
依次登录三个容器中,以server模式启动consul服务
./consul agent -server -config-dir=/usr/local > /usr/local/consul.log &
由于配置文件中制定了集群的IP列表,因此无需显式加入集群(cluster join),正常情况下,启动三个节点后,会自动组成一个集群,并且自动选举出来一个leader。
consul 集群服务的状态
./consul members --http-addr 172.18.0.11:8500
./consul operator raft list-peers -http-addr=172.18.0.12:8500

consul客户端安装配置

容器客户端节点安装,6个节点IP分别是:172.18.0.21,172.18.0.22,172.18.0.23,172.18.0.24,172.18.0.25,172.18.0.26
docker run -itd --name redis01 --net mynetwork --ip 172.18.0.21 -v /usr/local/docker_file/redis01/:/usr/local/ centos 
docker run -itd --name redis02 --net mynetwork --ip 172.18.0.22 -v /usr/local/docker_file/redis02/:/usr/local/ centos 
docker run -itd --name redis03 --net mynetwork --ip 172.18.0.23 -v /usr/local/docker_file/redis03/:/usr/local/ centos 
docker run -itd --name redis04 --net mynetwork --ip 172.18.0.24 -v /usr/local/docker_file/redis04/:/usr/local/ centos 
docker run -itd --name redis05 --net mynetwork --ip 172.18.0.25 -v /usr/local/docker_file/redis05/:/usr/local/ centos 
docker run -itd --name redis06 --net mynetwork --ip 172.18.0.26 -v /usr/local/docker_file/redis06/:/usr/local/ centos

 
6个client节点的配置以及服务定义,服务探测脚本如下
如下是172.18.0.21节点的配置,不同节点仅需修改bind_addr为对应机器(容器)的IP

client.json
{
"data_dir": "usr/local/consuldata",
"enable_script_checks": true,
"bind_addr": "172.18.0.21",
"retry_join": ["172.18.0.11","172.18.0.12","172.18.0.13"],
"retry_interval": "30s",
"rejoin_after_leave": true,
"start_join": ["172.18.0.11","172.18.0.12","172.18.0.13"]
}
分别启动三个client节点的consul服务,以client的模式运行,启动后,正常情况下会自动加入到consul的服务端集群中。
./consul agent -config-dir=/usr/local/consuldata > /usr/local/consuldata/consul.log &
./consul members --http-addr 172.18.0.11:8500
 
 

consul客户端代理服务注册

6个容器节点依次安装redis,做成一个集群(步骤略),这里的consul客户端代理的是一个3中3从的Redis集群,这里不列出来Redis集群的安装。
Redis集群安装参考https://www.cnblogs.com/wy123/p/12012848.html,还是非常方便的,在本地(容器节点)一键创建6个节点3主3从的集群。
其中主节点是172.18.0.21,172.18.0.22,172.18.0.23,从节点是172.18.0.24,172.18.0.25,172.18.0.26

这里是使用 w-master-redis-8888.service.consul名字作为三个redis集群节点的服务代理。
172.18.0.21节点上的redis-master-8888.json(172.18.0.22,172.18.0.23,172.18.0.24,172.18.0.25,172.18.0.26 类同,仅需修改address)

{
"services":
[
{
"name": "w-master-redis-8888",
"tags": [
"master"
],
"address": "172.18.0.21",
"port": 8888,
"checks": [
{
"args":["sh","-c","/usr/local/consuldata/check_redis_master.sh 172.18.0.21 8888 ******"],
"Shell":"/bin/bash",
"interval": "15s"
}
]
}
]
}

redis-slave-8888.json

{
"services":
[
{
"name": "r-slave-redis-8888",
"tags": [
"master"
],
"address": "172.18.0.21",
"port": 8888,
"checks": [
{
"args":["sh","-c","/usr/local/consuldata/check_redis_slave.sh 172.18.0.21 8888 ******"],
"Shell":"/bin/bash",
"interval": "15s"
}
]
}
]
}

Consul client节点的Redis主节点(写节点)服务检查脚本check_redis_master.sh
以下脚本来源于https://www.cnblogs.com/gomysql/p/8010552.html,做了简单的修改,在节点的身份判断逻辑上需要加强。

#!/bin/bash
host=$
myport=$
auth=$
if [ ! -n "$auth" ]
then
auth='\"\"'
fi
comm="/usr/local/redis_instance/redis8888/bin/redis-cli -h $host -p $myport -a $auth "
role=`echo 'INFO Replication'|$comm |grep -Ec 'role:master'`
echo 'INFO Replication'|$comm
if [ $role -ne ]
then
exit
fi

Consul client节点的Redis从节点服务检查脚本check_redis_slave.sh

#!/bin/bash
host=$
myport=$
auth=$
if [ ! -n "$auth" ]
then
auth='\"\"'
fi
comm="/usr/local/redis_instance/redis8888/bin/redis-cli -h $host -p $myport -a $auth "
role=`echo 'INFO Replication'|$comm |grep -Ec 'role:slave'`
echo $role
echo 'INFO Replication'|$comm if [ $role -ne ]
then
exit
fi

Consul服务发现

redis集群配置成功后,重新加载代理服务,consul reload,一切正常的话,consul服务端就可以解析配置的服务了。
如下注册了两个服务,分别是r-slave-redis-8888,w-master-redis-8888,分别代表Redis集群的读写节点。

可以看到,成功地解析了 w-master-redis-8888.service.consul这个服务,映射到172.18.0.21,172.18.0.22,172.18.0.23三个节点。
需要注意的是,这三个节点都是写节点,这里仅仅是为了实现服务发现(尽管redis 有多IP的驱动支持)

r-slave-redis-8888.service.consul服务的解析,指向了三个从节点,172.18.0.24,172.18.0.25,172.18.0.26

故障转移之后的服务发现:模拟主节点故障,对172.18.0.21节点手动故障转移,现在172.18.0.21与172.18.0.24角色交换

Redis集群故障转以后的服务发现解析结果 对于w-master-redis-8888.service.consul这个服务,成功解析到172.18.0.24,172.18.0.22,172.18.0.23三个主节点

Redis集群故障转以后的服务发现解析结果 对于w-master-redis-8888.service.consul这个服务,成功解析到172.18.0.24,172.18.0.22,172.18.0.23三个主节点

遇到的问题:
1,cosnul服务端集群的时候,clustercenter一开始自定义了一个名称myconsule_datacenter,导致client节点死活加不进来,按照默认的dc1就没有问题
目前还不理解这个datacenter的命名规则是什么?
2,容器节点中的shell脚本要授予可执行权限chmod +x check_XXX.sh
3,其他异常问题,一定要看日志,搜索一下基本上都有结果。
以下纯粹是Redis集群的问题,与Consul没有直接关系,仅作为本测试中遇到的问题。
4,容器节点的Redis集群时,需要移除bind_ip的127.0.0.1节点,直接配置docker创建容器时候的IP,创建集群的时候会一致等待,waiting for the cluster to join
这一点redis-cli --cluster做的很扯淡,明明找不到节点,还要死等,不人为终止的话,他会一直waiting
5,Redis集群时候,因为主从都是相对的,需要相互识别对方,主从节点都要指定“masterauth”和“requirepass”,且密码一致,否则执行cluster  failover提示成功,但故障转移不成功
6,遇到一个灵异的问题(之前单机多实例的时候也遇到过),在启动容器上的Redis服务的时候,如果使用绝对路径启动,在创建集群的时候会出现从节点无法添加到集群中去的情况,停止服务,以相对路径方式重启之后就没有这个问题

总的来说consul这个中间件使用起来还算是比较简单,配置也很清爽,不像某些中间件令人作呕的配置结构(mycat???)
这里没有配置多数据中心模式,仅配置了单数据中心模式,作为一款服务发现的中间件,是完全没有问题的,尤其是作为MySQL集群不支持多IP连接驱动的数据库连接。

参考:

基于Docker的Consul集群实现服务发现的更多相关文章

  1. 庐山真面目之十二微服务架构基于Docker搭建Consul集群、Ocelot网关集群和IdentityServer版本实现

    庐山真面目之十二微服务架构基于Docker搭建Consul集群.Ocelot网关集群和IdentityServer版本实现 一.简介      在第七篇文章<庐山真面目之七微服务架构Consul ...

  2. 基于Docker的redis集群搭建

    Redis集群官方介绍:http://www.redis.cn/topics/cluster-tutorial.html 基于Docker搭建Redis集群 环境:6个节点,三主三从 制作Redis镜 ...

  3. C#使用Consul集群进行服务注册与发现

    前言 我个人觉得,中间件的部署与使用是非常难记忆的:也就是说,如果两次使用中间件的时间间隔比较长,那基本上等于要重新学习使用. 所以,我觉得学习中间件的文章,越详细越好:因为,这对作者而言也是一份珍贵 ...

  4. Docker安装Consul集群

    Docker 安装Consul集群 使用windows 环境,Docker desktop community 构建consul集群. 1.docker 容器网络 docker安装后,默认会创建三种网 ...

  5. 基于Docker部署ETCD集群

    基于Docker部署ETCD集群 关于ETCD要不要使用TLS? 首先TLS的目的是为了鉴权为了防止别人任意的连接上你的etcd集群.其实意思就是说如果你要放到公网上的ETCD集群,并开放端口,我建议 ...

  6. 基于docker安装pxc集群

    基于docker安装pxc集群 一.PXC 集群的安装 PXC集群比较特殊,需要安装在 linux 或 Docker 之上.这里使用 Docker进行安装! Docker的镜像仓库中包含了 PXC数据 ...

  7. Docker部署Consul集群

    服务介绍 Consul是一种分布式.高可用.支持水平扩展的服务注册与发现工具.包含的特性有:服务发现.健康检查.键值存储.多数据中心和服务管理页面等. 官方架构设计图: 图中包含两个Consul数据中 ...

  8. vagrant+docker搭建consul集群开发环境

    HashiCorp 公司推出的Consul是一款分布式高可用服务治理与服务配置的工具.关于其配置与使用可以参考这篇文章 consul 简介与配置说明. 一般,我们会在多台主机上安装并启动 consul ...

  9. Docker学习-Docker搭建Consul集群

    1.环境准备 Linux机器三台 网络互通配置可以参考 https://www.cnblogs.com/woxpp/p/11858257.html 192.168.50.21 192.168.50.2 ...

随机推荐

  1. Jpofiler

    参考链接: https://blog.csdn.net/u010638673/article/details/81703942

  2. Java:谈谈控制线程的几种办法

    目录 Java:谈谈控制线程的几种办法 join() sleep() 守护线程 主要方法 需要注意 优先级 弃用三兄弟 stop() resume suspend 中断三兄弟 interrupt() ...

  3. Spring框架学习笔记(9)——API接口设计相关知识及具体编码实现

    最近需要设计一个API服务器,想要把API接口搞得规范一下,就通过网上搜集到了一些资料,以下便是自己的一些理解以及相关的具体实现 本文采用的是spring boot+maven的方案 restful规 ...

  4. Bayesian Non-Exhaustive Classification A case study:online name disambiguation using temporal record streams

    一 摘要: name entity disambiguation:将对应多个人的记录进行分组,使得每个组的记录对应一个人. 现有的方法多为批处理方式,需要将所有的记录输入给算法. 现实环境需要1:以o ...

  5. Codeforces_816

    A.不断增加时间,直到符合要求. #include<bits/stdc++.h> using namespace std; int a,b; char c; int f(int x) { ...

  6. HDU 6602 Longest Subarray (线段树)

    题意: 1e5的数组,c(1e5)种数字求最长的子串,使得其中每个出现的数字出现的次数为0次或者大于k次 思路: 枚举右端点i,维护当前右端点时,每个左端点的可行元素数量,当且仅当可行元素为c时更新答 ...

  7. SpringBoot学习笔记 文件访问映射

    通过SpringBoot可以把磁盘内所有的文件都访问到 有一张图片存放在 E://images/acti/123.jpg import org.springframework.context.anno ...

  8. css中flex布局

    一.Flex布局是什么? Flex是Flexible Box的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性. 任何一个容器都可以指定为Flex布局. .box{ display: flex; ...

  9. javascript A*算法 寻路算法 获取最短路径算法

    //A算法 自动寻路 路径 class GetAutoPath{ constructor(id, map, sPos, ePos, mapArr){ //this.type = id.type; th ...

  10. Hapi+MySql项目实战环境初始化(一)

    因为项目要求特殊的原因,公司要求使用Nodejs+HApi(纯英文的API)+Mysql构建新的项目.网上找了一堆资料,看了半天一脸懵逼.结论就是:版本的差异,资料国内几乎都是旧的17年前的了.根据资 ...