热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

关于微服务

原创不易,求分享、求一键三连微服务会让我们的应用变多,并且为了高可用一个服务会在线上部署多台,那么进行服务调用就存在节点之间的负载均衡和服务发现,负载均衡是为了让各个节点的负载尽量

原创不易,求分享、求一键三连


微服务会让我们的应用变多,并且为了高可用一个服务会在线上部署多台,那么进行服务调用就存在节点之间的负载均衡和服务发现,负载均衡是为了让各个节点的负载尽量平均,而服务发现是为了解耦服务中provider和consumer的发现和调用。

通常服务发现有两种常用的方式:一种是服务端服务发现,服务发现的和请求路由实现逻辑放在服务端;另外一种是客户端服务发现,因为这种发现和路由逻辑是由发送请求的客户端来实现的,像我们现在使用的kratos微服务框架就是用这种方式进行负载均衡的:


微服务进行服务发现和负载均衡中经常用到一个重要的组件就是注册中心,接下来我们先说一下我们用到的注册中心discovery(参考地址:https://github.com/bilibili/discovery/blob/master/doc/arch.md) 以下是discovery的架构图:


涉及三种角色:



  1. 提供服务的是service Provider;

  2. 服务订阅是Service Consumer ;

  3. 注册中心是Discovery Server;

接下来我们分别说一下注册中心是如何来进行服务注册、发现、注册中心节点之间的数据同步、以及遇到一些问题是如何避免的。


服务注册

当一个Provider启动的时候,首先需要判断服务是否启动成功,一般会定一个监控检测的接口,判断项目运行的依赖是否正常比如:mysql、redis或者mq等。

检测成功则会向discovery server发起register请求,请求成功之后,后续会以心跳的方式发送renew请求保证该服务能在注册中心续租成功,当服务下线会先将自己的健康检测的healthcheck设置下线状态,再发送Cancel到注册中心进行注销,将未处理的业务处理完成等待一段时候时间之后注销服务。


服务发现

discovry中consumer通过长轮询的方式获取使用的provider最新数据,有数据更新则进行本地数据变更,那么来看下什么是长轮询(HTTP Long-Polling)


长轮询通常被叫做“Hanging GET”,大致是这样的:

如果服务器没有数据可供客户端使用,则服务器不会发送空响应,而是保留请求并等待某些数据变为可用;一旦数据可用,将向客户端发送完整响应。

然后客户端立即从服务端重新请求信息,以便服务器几乎总是有一个可用的等待请求,它可以使用该请求来传递数据以响应事件。

使用HTTP长轮询的应用程序的基本生命周期如下:



  1. 客户端使用常规HTTP发出初始请求,然后等待响应

  2. 服务器会延迟其响应,知道更新可用数据或者发生超时。

  3. 当更新可用时,服务器会向客户端发送完整响应。

  4. 客户端通常会在收到响应后立即发送新的长轮询请求,或者在暂停后发送请求,以允许可接受的延迟期。

  5. 每个长轮询请求都有一个超时。由于超时,客户端必须在链接关闭后定期重新链接。


Discovery 节点的数据同步

当集群中的discovery接收到provider节点的请求之后,会讲请求转发到其他discovery进行数据同步,保持每个节点都能保持全部的最新数据,这种同步会有一些延迟,后面会说到这种延迟对服务发现的注册中心这种业务场景来说是影响不大的。


go-grpc内置的负载均衡


grpc在官网文档中提供了实现LoadBalance的方法,不同语言的grpc代码API中也提供了命名解析和负载均衡接口供扩展。默认提供的是DNS resolver的实现,接口规范实现简单,只需实现服务注册和服务监听和解析的逻辑就可以了,运行机制如下:

Resolver 解析器,用于从注册中心实时获取当前服务端的列表,同步发送给Balancer;

当grpc注册服务发现时,实际时注册的resolver.Builder, Builder会开启单独的groutine,进行watch逻辑,当调用UpdateState 向ClientConn发送服务地址表的更新;

resolver中的ClientConn结构提供了resolver通知ClientConn更新服务列表的回调方法。

Balancer 平衡器,接收从Resolver发送的服务端列表,建立维护长链接;client发起rpc调用时,按照一定的算法从连接池中选择一个连接进行rpc调用;

Register 注册,用于服务端初始化和在线时,将自己信息上报到注册中心,主要信息包含Ip+端口。


grpc HealthCheck

grpc提供了一个标准的健康检测协议,在grpc的所有语言实现中基本都提供了生成代码和用于设置运行状态的功能。

主动健康检查health check,可以在服务提供者服务不稳定时,被消费者感知,临时从负载节点中移除,减少错误请求。

有了上面说到的服务注册中心和负载均衡的支持,下面看如何实现平滑发布和平滑下线。


平滑发布

外置服务调用 Provider health check 接口,发现接口不通就不会注册,发现通就会注册,外挂有个旁者帮你去注册。

一般服务启动会进行一些数据初始化,环境初始化,等所有完成,然后将接口的 health check 接口状态改为可用,这时候docker 容器就可以放流量进来了,这就是常用的外挂方式。


平滑下线

如果我们这时候有个新功能需要上线,这时候需要先下线走 滚动更新。

k8s 发送 kill 进程id

go main 拦截 sigterm 信号,先告诉服务发现注册中心服务要注销,然后服务发现通知其他服务将自己本地的负载均衡连接池 close 掉,并且流量不要再发送过去了。但是服务发现通知其他 consumer 需要一定的同步时间,所以下一步我们将自己服务的 health check 接口标记为 下线状态。

最终我们一般要等到 2 个服务发现心跳周期,这是最差的情况,一般是实时的退出。

当然,不可避免依旧会遇到一些问题:


当注册中心挂了会怎样?

我们现在技术栈用的是B站开源的Kratos微服务框架,做的是客户端负载均衡,会把用到的数据缓存在客户端内存里,当注册中心挂掉了,就无法获取到注册中心的provider节点变更信息,这段时间不发版本,正常情况下就不会有大量的节点变更,注册中心做好监控告警,快速恢复注册中心。


当注册的节点未全局同步完成会怎样?

注册中心做了高可用会启动多个节点,节点之间的数据同步会遵循 CAP 定理 一致性(Consistency)(等同于所有节点访问同一份最新的数据副本);

可用性(Availability)(每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据);

分区容错性(Partition tolerance)(以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择);

分布式系统智能满足三项中的两项不可能全部满足。Discovry是一个ap系统,数据同步会出现同步不成功、同步延迟等问题,对于未同步到的节点会延迟同步,只有部分节点可能会收到延迟,但是最终会都会同步成功。


当注销的节点未下线掉会怎样?

上面已经说到go-grpc支持健康检查的机制,如果节点未下线,但在provider下线前将健康检查接口置为不可用,则节点会从调用地址列表中移除,即使注册中心延迟下线,也不会有影响。

discovry中的provider是定期发送renew的方式进行续租,超过剔除心跳周期后,服务端会将对应的下线节点踢掉。


注册中心新节点上线,内存无数据会怎样?

新启动一个discovery节点到集群,这个时候新启动内存中没有其他节点的数据,discovery做了处理,在启动2-3个心跳周期才能提供consumer节点发现的服务,等待其他节点的数据全部同步之后才能提供服务。


discovery内部的自保护机制。

如果provider集群和discovery之间存在网络出现异常,但provider服务正常,只是心跳异常的情况,会启到保护的作用。

网络闪断和分区时自我保护模式

60s内丢失大量(小于Instance总数20.85)心跳数,“好”“坏”Instance信息都保留 所有node都会持续提供服务,单个node的注册和发现功能不受影响 最大保护时间,防止分区恢复后大量原先Instance真的已经不存在时,一直处于保护模式

参见(https://github.com/bilibili/discovery/blob/master/doc/arch.md)


染色环境(泳道环境)

为什么需要泳道环境?

我们同时存在几十个需求迭代同时开发,且不同的迭代可能会修改同一个项目,代码的冲突可以通过不同的分支解决,但开发阶段的联调都在同一个开发环境上的话会存在相互影响,造成开发效率低。

许多迭代的代码在同一个开发环境上联调会造成许多问题,研发人员解决这些问题开销的时间和精力成本很大。

这样的环境管理时间一久便造成了开发环境的联调不太稳定,研发人员转而将开发阶段的联调放到了测试环境,从而污染了测试环境,进而影响了测试阶段的效率。我们期望保证研发同学能够在不同的迭代情况下能够独立开发联调,测试同学期望保证测试环境的稳定。

"泳道",顾名思义是可以让不同的迭代开发能够在其自己的"泳道"上玩,不会影响其他的"泳道"。

我们选择了kratos框架,它本来就已经支持节点染色的功能,根据请求节点染色来进行负载能友好的解决上面提到的一些问题,在discovery注册到的节点中有个metadata用来存放节点的一些扩展字段,其中color就用来表示每个节点的染色环境:


在发送http请求的时候将需要访问的染色请求 设置到http header里面,在interface层解析放到ctx中,当去调用其他provider服务的时候,client端进行负载均衡进行节点选择,优先根据ctx中color选择对应染色的节点,不存在则默认color为空的节点进行调用。

上面说的这种情况我们只需要一套测试的基准环境,所有服务的color都是空,当同一个服务不同的需求变更就部署不同的color的多个节点,就能根据上面的方式进行测试。

好了,今天的分享就到这,喜欢的同学可以四连支持:


想要更多交流可以加我微信:




推荐阅读
  • 调试利器SSH隧道
    在开发微信公众号或小程序的时候,由于微信平台规则的限制,部分接口需要通过线上域名才能正常访问。但我们一般都会在本地开发,因为这能快速的看到 ... [详细]
  • 本文详细介绍了如何在 Ubuntu 14.04 系统上搭建仅使用 CPU 的 Caffe 深度学习框架,包括环境准备、依赖安装及编译过程。 ... [详细]
  • 利用Node.js实现PSD文件的高效切图
    本文介绍了如何通过Node.js及其psd2json模块,快速实现PSD文件的自动化切图过程,以适应项目中频繁的界面更新需求。此方法不仅提高了工作效率,还简化了从设计稿到实际应用的转换流程。 ... [详细]
  • 七大策略降低云上MySQL成本
    在全球经济放缓和通胀压力下,降低云环境中MySQL数据库的运行成本成为企业关注的重点。本文提供了一系列实用技巧,旨在帮助企业有效控制成本,同时保持高效运作。 ... [详细]
  • 为何Compose与Swarm之后仍有Kubernetes的诞生?
    探讨在已有Compose和Swarm的情况下,Kubernetes是如何以其独特的设计理念和技术优势脱颖而出,成为容器编排领域的领航者。 ... [详细]
  • H5技术实现经典游戏《贪吃蛇》
    本文将分享一个使用HTML5技术实现的经典小游戏——《贪吃蛇》。通过H5技术,我们将探讨如何构建这款游戏的两种主要玩法:积分闯关和无尽模式。 ... [详细]
  • Docker安全策略与管理
    本文探讨了Docker的安全挑战、核心安全特性及其管理策略,旨在帮助读者深入理解Docker安全机制,并提供实用的安全管理建议。 ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • Requests库的基本使用方法
    本文介绍了Python中Requests库的基础用法,包括如何安装、GET和POST请求的实现、如何处理Cookies和Headers,以及如何解析JSON响应。相比urllib库,Requests库提供了更为简洁高效的接口来处理HTTP请求。 ... [详细]
  • 本文详细介绍了 Java 中 org.apache.jena.atlas.lib.ByteBufferLib 类下的 acopyArray 方法,并提供了多个实际应用中的代码示例,帮助开发者更好地理解和使用该方法。 ... [详细]
  • 理解浏览器历史记录(2)hashchange、pushState
    阅读目录1.hashchange2.pushState本文也是一篇基础文章。继上文之后,本打算去研究pushState,偶然在一些信息中发现了锚点变 ... [详细]
  • 流处理中的计数挑战与解决方案
    本文探讨了在流处理中进行计数的各种技术和挑战,并基于作者在2016年圣何塞举行的Hadoop World大会上的演讲进行了深入分析。文章不仅介绍了传统批处理和Lambda架构的局限性,还详细探讨了流处理架构的优势及其在现代大数据应用中的重要作用。 ... [详细]
  • flea,frame,db,使用,之 ... [详细]
  • 如何高效解决Android应用ANR问题?
    本文介绍了ANR(应用程序无响应)的基本概念、常见原因及其解决方案,并提供了实用的工具和技巧帮助开发者快速定位和解决ANR问题,提高应用的用户体验。 ... [详细]
  • 本文探讨了如何高效地计算数组中和为2的幂的偶对数量,提供了从基础到优化的方法。 ... [详细]
author-avatar
thofarq
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有