文档章节

consul服务注册与服务发现的巨坑

梦朝思夕
 梦朝思夕
发布于 03/13 19:51
字数 1121
阅读 3013
收藏 59
点赞 5
评论 31

最近使用consul作为项目的服务注册与服务发现的基础功能。在塔建集群使用中遇到一些坑,下面一个个的记录下来。

consul集群多node

consul集群的node也就是我们所说的consul实例。集群由多个node组成,为了集群的可用性,需要超过半数的node启用server。如5个node中起码3个启用server模式,3个node组成的集群就2个node启用server模式。 看到这里的时候你一定觉得没有什么问题呀,但是consul坑就是多。加入你的集群组成如下:

Node          Address              Status  Type    Build  Protocol  DC                    Segment
BJ-MQTEST-01  10.163.145.117:8301  alive   server  1.0.6  2         iget-topology-aliyun  <all>
BJ-MQTEST-02  10.163.147.47:8301   alive   server  1.0.6  2         iget-topology-aliyun  <all>
BJ-TGO-01     10.163.145.110:8301     alive   client  1.0.6  2         iget-topology-aliyun  <default>

那么client可以使用上述的3个ip连接到consul集群,假设client A使用使用10.163.145.117注册了service,重启后使用地址10.163.145.110注册之前的service信息,此时你就会惊喜的发现,UI可以同时看到在同一个servicename下存在两个相同的serviceid。

这就是consul集群多node的坑,因为service底层虽然使用了KV存储,但是service的KEY与serviceid无关,所以在集群中可以重复。

解决方案一

集群中只有一个node使用server模式,其他的都是client模式。缺点很明显,如果server的node挂了,那么集群的可用性就没有了。

解决方案二

相同的客户端使用相同的node地址,这样就可以确保同一个servicename下不存在两个相同的serviceid。缺点是如果客户端绑定的node挂了,那么client就不能使用。 代码给出

package registry

import (
	"fmt"
	"math"
	"net"
	"sort"
	"strings"

	log "github.com/golang/glog"
)

type ConsulBind struct {
	Addr  string
	IpInt float64
}
type ConsulBindList []ConsulBind

func (s ConsulBindList) Len() int {
	return len(s)
}
func (s ConsulBindList) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}
func (s ConsulBindList) Less(i, j int) bool {
	return s[i].IpInt < s[j].IpInt
}
func (s ConsulBindList) ToStrings() []string {
	ret := make([]string, 0, len(s))
	for _, cbl := range s {
		ret = append(ret, cbl.Addr)
	}
	return ret
}

func BingConsulSort(consulAddrs []string) []string {
	localIpStr, err := GetAgentLocalIP()
	if err != nil {
		return consulAddrs
	}
	localIp := net.ParseIP(localIpStr)
	localIpInt := int64(0)
	if localIp != nil {
		localIpInt = util.InetAton(localIp)
	}
	addrslist := make([]ConsulBind, 0, len(consulAddrs))
	for _, addr := range consulAddrs {
		ads := strings.Split(addr, ":")
		if len(ads) == 2 {
			ip := net.ParseIP(ads[0])
			if ip != nil {
				ipInt := util.InetAton(ip)
				fmt.Println("ip:", ip, ipInt, localIpInt, (ipInt - localIpInt))
				addrslist = append(addrslist, ConsulBind{
					Addr:  addr,
					IpInt: math.Abs(float64(ipInt - localIpInt)),
				})
			}
		}
	}
	consulBindList := ConsulBindList(addrslist)
	sort.Sort(consulBindList)
	log.Infof("sort addrs %v", consulBindList)
	return consulBindList.ToStrings()
}

解决方案三

客户端随机使用集群中的任意一个地址,但是注册之前先判断该servicename是否已经存在要注册的serviceid了,如果存在就删除重新注册。缺点就是watch会有较多事件,可以升级为如果存在并且是健康的就不允许重复注册,我使用的就是该方案。

删除service

一开始很多人都会觉得服务出现问题了下架了挂了,那么就会被移出了。但是在consul中删除service没有那么简单! 请查看官网文档:
catalog文档
Deregister Entity
agent/service文档
Deregister Service

看着似乎任选一个就可以做到正确删除service了!可以继续说一声,没有那么简单,consul的坑就是多。

选择了/agent/service/deregister/:service_id接口,会发现你无法删除别的node的service。比如10.163.145.117中有个serviceid为agent_xxxx_v1,但是客户端连接consul使用的IP为10.163.145.110,那么就无法删除掉agent_xxxx_v1

没事不是还有一个接口没有使用吗?再来看看/catalog/deregister,执行完成后看了UI,嗯嗯的确是删除了agent_xxxx_v1。等等。。。 。。。 30s后发现agent_xxxx_v1又出现了,这是怎么回事????

请查看consul的bugUnable to deregister a service #1188

解决方案

第一步:查询出serviceid所属的servicename所有的列表;
第二步:遍历列表获取到node的地址后删除所有的serviceid;

if len(c.Options.Addrs) > 0 {
		addrMap := make(map[string]string, len(c.Options.Addrs))
		for _, host := range c.Options.Addrs {
			addr, _, err := net.SplitHostPort(host)
			if err != nil {
				log.Warningf("%v is err=%v", host, err)
				continue
			}
			addrMap[addr] = host
		}
		rsp, _, _ := c.Client.Health().Service(s.Name, "", false, nil)
		for _, srsp := range rsp {
			if srsp.Service.ID == serviceId {

				if host, ok := addrMap[srsp.Node.Address]; ok {
					config := consul.DefaultNonPooledConfig()
					config.Address = host
					// 创建consul连接
					client, err := consul.NewClient(config)
					if err != nil {
						log.Warningf("NewClient is err=%v", host, err)
					}
					err = client.Agent().ServiceDeregister(serviceId)
					log.Infof("ServiceDeregister host=%v , serviceId=%v", host, serviceId)
				}
			}
		}
	} else {
		err = c.Client.Agent().ServiceDeregister(serviceId)
		log.Infof("ServiceDeregister  serviceId=%v", serviceId)
	}

可以肯定的是consul还有其他的坑的,但是这两个坑让我记忆深刻,记录下来给准备使用consul或者已经遇到这些坑的同学一个提醒。

© 著作权归作者所有

共有 人打赏支持
梦朝思夕

梦朝思夕

粉丝 67
博文 21
码字总数 29399
作品 2
朝阳
程序员
加载中

评论(31)

编走编想
编走编想
第一个问题其实也是因为第二个问题
哎码
哎码
刚刚被坑了一个项目
梦朝思夕
梦朝思夕

引用来自“Laughing_Vzr”的评论

引用来自“purple_grape”的评论

感觉楼主的姿势有问题。

“3个node组成的集群就2个node启用server模式,”

这明显不对呀,要三个节点都运行在server模式才能选举。
没错,是这样的。所以楼主的用法本身就是错的。client只是用来转述给server端注册或者摘除的一些动作的。

请先测试再来猜测
Laughing_Vzr
Laughing_Vzr

引用来自“purple_grape”的评论

感觉楼主的姿势有问题。

“3个node组成的集群就2个node启用server模式,”

这明显不对呀,要三个节点都运行在server模式才能选举。
没错,是这样的。所以楼主的用法本身就是错的。client只是用来转述给server端注册或者摘除的一些动作的。
海波波bo
海波波bo

引用来自“purple_grape”的评论

consul集群(所有server节点)个数必须是基数,且 >=3 个,推荐5个节点。
它的正确启动姿势是,必须有一个初始节点,且手动指定为leader,然后开启其它server节点,让它们加入集群。
最后初始节点下线,重新加入集群,参与选举。
正解
海波波bo
海波波bo
推荐的是大于3的奇数集群啊
梦朝思夕
梦朝思夕

引用来自“se77en”的评论

不是 consul 的问题,是你完全不会用,而且没仔细看文档,我司机器数量是你的几百倍,没出过这种问题。你启动 server 的方式就不对。

回复@se77en : 或者你把你启动的配置贴一下,我测试看看
梦朝思夕
梦朝思夕

引用来自“se77en”的评论

不是 consul 的问题,是你完全不会用,而且没仔细看文档,我司机器数量是你的几百倍,没出过这种问题。你启动 server 的方式就不对。

回复@se77en : 你是说哪一个问题没有出现呢?还是这两个问题都没有出现?
se77en
se77en
不是 consul 的问题,是你完全不会用,而且没仔细看文档,我司机器数量是你的几百倍,没出过这种问题。你启动 server 的方式就不对。
MockMan
MockMan
当你在容器中使用的时候,你会发现坑更多
史上最简单的 SpringCloud 教程 | 第十四篇: 服务注册(consul)

转载请标明出处: http://blog.csdn.net/forezp/article/details/70245644 本文出自方志朋的博客 这篇文章主要介绍 spring cloud consul 组件,它是一个提供服务发现和配置的工具。consul具有...

forezp ⋅ 2017/04/19 ⋅ 0

【微服务】网关Kong整合SpringBoot和Consul设计

前面的博客已经整理了SpringBoot整合Consul以及Kong的相关文章。这次讲讲对于这套微服务架构如何实施我的理解。 先上图,整体架构图如下: 模块说明: Client: 外部访问应用 Api-GateWay-Cl...

Tree ⋅ 01/11 ⋅ 0

跟大家介绍一下关于Spring Cloud Consul

Spring Cloud Consul项目是针对Consul的服务治理实现。Consul是一个分布式高可用的系统,它包含多个组件,但是作为一个整体,在微服务架构中为我们的基础设施提供服务发现和服务配置的工具。...

明理萝 ⋅ 06/13 ⋅ 0

Consul 服务注册与服务发现

1. 服务注册 对 Consul 进行服务注册之前,需要先部署一个服务站点,我们可以使用 ASP.NET Core 创建 Web 应用程序,并且部署到 Ubuntu 服务器上。 ASP.NET Core Hell World 应用程序示例代码...

林羽恒 ⋅ 2017/06/19 ⋅ 0

从零开始搭建ELK+GPE监控预警系统

作者介绍 本文可能不会详细记录每一步实现的过程,但一定程度上可以引领小伙伴走向更开阔的视野,串联每个环节,呈现予你不一样的效果。 8个平台 100+台服务器 10+个集群分组 微服务600+ 用户...

张志朋 ⋅ 2017/11/20 ⋅ 0

Mac OS、Ubuntu 安装及使用 Consul

Consul 概念(摘录): Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案,比如 Airbnb 的 SmartStack 等相比,Consul 的方...

技术小哥哥 ⋅ 2016/01/11 ⋅ 0

Docker & Consul & Fabio & ASP.NET Core 2.0 微服务跨平台实践

相关博文: Ubuntu 简单安装 Docker Mac OS、Ubuntu 安装及使用 Consul Consul 服务注册与服务发现 Fabio 安装和简单使用 阅读目录: Docker 运行 Consul 环境 Docker 运行 Fabio 环境 使用 ...

那谁爸爸 ⋅ 01/08 ⋅ 0

spring-cloud1:服务注册与发现

spring-cloud1:服务注册与发现 www.blogways.net2017-12-172 阅读 spring服务 目 录 1 spring cloud简介 2 微服务架构 3 服务注册与发现 一、spring cloud简介 Spring Cloud是一个基于Sprin...

www.blogways.net ⋅ 2017/12/17 ⋅ 0

分布式服务注册和发现consul 简要介绍

Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案,Consul的方案更"一站式",内置了服务注册与发现框 架、分布一致性协议实现、...

疯code ⋅ 2016/07/19 ⋅ 0

docker registrator配合consul使用的问题

上一篇文章中有介绍使用registrator将docker容器启动的服务注册到consul,再用consul-template自动更新ngnix配置,实现系统服务的自动发现。 在多个docker主机的情况下存在以下问题: regist...

chris_2009 ⋅ 2016/04/19 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

vim基础-编辑模式-命令模式

编辑模式:可以编辑修改文件。编辑模式下 按“esc”键返回一般模式。 按一次“Insert”键 (一般在键盘回格键右边)作用和“i”一样表示“插入”。按两次“Insert”键表示“替换”,作用为:...

ZHENG-JY ⋅ 10分钟前 ⋅ 0

MaxCompute读取分析OSS非结构化数据的实践经验总结

摘要: 本文背景 很多行业的信息系统中,例如金融行业的信息系统,相当多的数据交互工作是通过传统的文本文件进行交互的。此外,很多系统的业务日志和系统日志由于各种原因并没有进入ELK之类...

阿里云云栖社区 ⋅ 15分钟前 ⋅ 0

Linux操作系统有何优势?Linux学习

  当今世界流行的操作系统有3大类,Linux、Mac OS和Windows操作系统,Linux操作系统因其开源、免费、跨平台、良好的界面等特性,深受广大程序员们的青睐!   Linux操作系统被广泛的应用于...

老男孩Linux培训 ⋅ 16分钟前 ⋅ 0

Spring Cloud Spring Boot mybatis分布式微服务云架构 开发Web应用

静态资源访问 在我们开发Web应用的时候,需要引用大量的js、css、图片等静态资源。 默认配置 Spring Boot默认提供静态资源目录位置需置于classpath下,目录名需符合如下规则: /static /pub...

itcloud ⋅ 20分钟前 ⋅ 0

6月19日任务 设置更改root密码、连接mysql、mysql常用命令

13.1 设置更改root密码 1. /usr/local/mysql/bin/mysql -uroot 设置环境变量 : export PATH=$PATH:/usr/local/mysql/bin/ 永久生效: vim /etc/profile 加入 export PATH=$PATH:/usr/local/m......

吕湘颖 ⋅ 22分钟前 ⋅ 0

MaxCompute读取分析OSS非结构化数据的实践经验总结

摘要: 本文背景 很多行业的信息系统中,例如金融行业的信息系统,相当多的数据交互工作是通过传统的文本文件进行交互的。此外,很多系统的业务日志和系统日志由于各种原因并没有进入ELK之类...

猫耳m ⋅ 23分钟前 ⋅ 0

Spring MVC controller,return重定向redirect:

@RequestMapping(value="/save",method=RequestMethod.POST)public String doSave(Course course) {log.debug("Info of Course");log.debug(ReflectionToStringBuilder.toStr......

颖伙虫 ⋅ 31分钟前 ⋅ 0

JavaSE——线程介绍

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权;凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记。 线程: 介绍:管线程叫多任务处理,首先你得知道...

凯哥学堂 ⋅ 34分钟前 ⋅ 0

ORM——使用spring jpa data实现逻辑删除

前言 在业务中是忌讳物理删除数据的,数据的这个对于一个IT公司可以说是最核心的资产,如果删除直接就物理删除,无疑是对核心资产的不重视,可能扯的比较远,本文最主要是想通过spring jpa ...

alexzhu592 ⋅ 41分钟前 ⋅ 0

CDN caching

Incapsula应用感知CDN使用智能分析和频率分析来动态缓存内容,并最大限度地提高效率。确保可直接从RAM获取最常访问的资源,而不依赖于较慢的访问机制。 1、 静态内容缓存 Incapsula缓存静态内...

上树的熊 ⋅ 44分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部