微服务学习--实践

1、服务发布和引用的那些坑

  • 建议预定义各项参数:例如超时时间、超时重试参数等(预防小白使用者
  • 最好的办法是把服务发布端的详细服务配置信息转移到服务引用端(预防网络风暴

 XML 配置方式的服务发布和引用的具体流程,简单来说就是服务提供者定义好接口,并且在服务发布配置文件中配置要发布的接口名,在进程启动时加载服务发布配置文件就可以对外提供服务了。而服务消费者通过在服务引用配置文件中定义相同的接口名,并且在服务引用配置文件中配置要引用的接口名,在进程启动时加载服务引用配置文件就可以引用服务了。

在业务具体实践过程中可能会遇到引用服务的服务消费者众多,对业务的敏感度参差不齐的问题,所以在服务发布的时候,最好预定义好接口的各种配置。在服务规模不大,业务比较简单的时候,这样做比较合适。但是对于复杂业务,虽然服务发布时预定义好接口的各种配置,但在引用的服务消费者众多且同时访问的时候,在极端情况下(例如节点配置变动或者网络频繁抖动时)可能会引起网络风暴(导致注册中心网络带宽被全部消耗,参考DDos攻击)。这种情况下,比较保险的方式是,把接口的各种配置放在服务引用配置文件里。

在进行服务配置升级过程时,要考虑好步骤,在所有服务消费者完成升级之前,服务提供者还不能把服务的详细信息去掉,否则可能会导致没有升级的服务消费者引用异常。

注册中心落地

注册中心存储的服务信息一般包含三部分内容:分组、服务名以及节点信息,节点信息又包括节点地址和节点其他信息。

注册中心具体是如何工作的,包括四个流程。

  • 服务提供者注册流程。

  • 服务提供者反注册流程。

  • 服务消费者查询流程。 ( 一般按照本地内存---本地快照--注册中心的次序查询,兼顾效率和可用性。)

  • 服务消费者订阅变更流程。( a、服务消费者从注册中心获取了服务的信息后,就订阅了服务的变化,会在本地保留Cluster的sign值。b、服务消费者每隔一段时间,调用getSign()函数,从注册中心获取服务端该Cluster的sign值,并与本地保留的sign值做对比,如果不一致,就从服务端拉取新的节点信息,并更新localcache和snapshot。)

2、注册与发现的几个问题

1. 多注册中心

对于服务消费者来说,要能够同时从多个注册中心订阅服务;对于服务提供者来说,要能够同时向多个注册中心注册服务。

2. 并行订阅服务

并行订阅的方式,每订阅一个服务就单独用一个线程来处理,这样的话即使遇到个别服务节点连接超时,其他服务节点的初始化连接也不受影响,最慢也就是这个服务节点的初始化连接耗费的时间,最终所有服务节点的初始化连接耗时控制在了30秒以内。

3. 批量反注册服务

通过优化反注册逻辑,对于下线机器、节点销毁的场景,通过调用注册中心提供的批量反注册接口,一次调用就可以把该节点上提供的所有服务同时反注册掉,从而避免了“僵尸节点”的出现。

4. 服务变更信息增量更新

为了减少服务消费者从注册中心中拉取的服务可用节点信息的数据量,这个时候可以通过增量更新的方式,注册中心只返回变化的那部分节点信息,尤其在只有少数节点信息变更时,此举可以大大减少服务消费者从注册中心拉取的数据量,从而最大程度避免产生网络风暴。

3、  开源注册服务中心选型

当下主流的服务注册与发现的解决方案,主要有两种:

  • 应用内注册与发现:注册中心提供服务端和客户端的SDK,业务应用通过引入注册中心提供的SDK,通过SDK与注册中心交互,来实现服务的注册和发现。

  • 应用外注册与发现:业务应用本身不需要通过SDK与注册中心打交道,而是通过其他方式与注册中心交互,间接完成服务注册与发现。

1. 应用内

采用应用内注册与发现的方式,最典型的案例要属Netflix开源的Eureka

Eureka主要由三个重要的组件组成:

  • Eureka Server:注册中心的服务端,实现了服务信息注册、存储以及查询等功能。

  • 服务端的Eureka Client:集成在服务端的注册中心SDK,服务提供者通过调用SDK,实现服务注册、反注册等功能。

  • 客户端的Eureka Client:集成在客户端的注册中心SDK,服务消费者通过调用SDK,实现服务订阅、服务更新等功能。

2. 应用外

采用应用外方式实现服务注册和发现,最典型的案例是开源注册中心Consul

Consul实现应用外服务注册和发现主要依靠三个重要的组件:

  • Consul:注册中心的服务端,实现服务注册信息的存储,并提供注册和发现服务。

  • Registrator:一个开源的第三方服务管理器项目,它通过监听服务部署的Docker实例是否存活,来负责服务提供者的注册和销毁。

  • Consul Template:定时从注册中心服务端获取最新的服务提供者节点列表并刷新LB配置(比如Nginx的upstream),这样服务消费者就通过访问Nginx就可以获取最新的服务提供者信息。

对比小结一下,这两种解决方案的不同之处在于应用场景,应用内的解决方案一般适用于服务提供者和服务消费者同属于一个技术体系;应用外的解决方案一般适合服务提供者和服务消费者采用了不同技术体系的业务场景,比如服务提供者提供的是C++服务,而服务消费者是一个Java应用,这时候采用应用外的解决方案就不依赖于具体一个技术体系。同时,对于容器化后的云应用来说,一般不适合采用应用内SDK的解决方案,因为这样会侵入业务,而应用外的解决方案正好能够解决这个问题。

两个需要关注的问题

注册中心选型还有两个最值得关注的问题,一个是高可用性,一个是数据一致性。

1、实现高可用性的方法主要有两种(参考架构设计):

  • 集群部署,顾名思义就是通过部署多个实例组成集群来保证高可用性,这样的话即使有部分机器宕机,将访问迁移到正常的机器上就可以保证服务的正常访问。

  • 多IDC部署,就是部署在不止一个机房,这样能保证即使一个机房因为断电或者光缆被挖断等不可抗力因素不可用时,仍然可以通过把请求迁移到其他机房来保证服务的正常访问。

2、数据一致性

分布式系统中著名的CAP理论,即同时满足一致性、可用性、分区容错性这三者是不可能的。

CP型注册中心,牺牲可用性来保证数据强一致性,最典型的例子就是ZooKeeper,etcd,Consul了。ZooKeeper集群内只有一个Leader,而且在Leader无法使用的时候通过Paxos算法选举出一个新的Leader。

AP型注册中心,牺牲一致性来保证可用性,最典型的例子就是Eureka了。对比下Zookeeper,Eureka不用选举一个Leader,每个Eureka服务器单独保存服务注册地址,因此有可能出现数据信息不一致的情况。但是当网络出现问题的时候,每台服务器都可以完成独立的服务。

对于注册中心来说,最主要的功能是服务的注册和发现,在网络出现问题的时候,可用性的需求要远远高于数据一致性。即使因为数据不一致,注册中心内引入了不可用的服务节点,也可以通过其他措施来避免,比如客户端的快速失败机制等,只要实现最终一致性,对于注册中心来说就足够了。因此,选择AP型注册中心,一般更加合适。

总结

总的来说,在选择开源注册中心解决方案的时候,要看业务的具体场景。

  • 如果业务体系都采用Java语言的话,Netflix开源的Eureka是一个不错的选择,并且它作为服务注册与发现解决方案,能够最大程度的保证可用性,即使出现了网络问题导致不同节点间数据不一致,你仍然能够访问Eureka获取数据。

  • 如果业务体系语言比较复杂,Eureka也提供了Sidecar的解决方案;也可以考虑使用Consul,它支持了多种语言接入,包括Go、Python、PHP、Scala、Java,Erlang、Ruby、Node.js、.NET、Perl等。

  • 如果业务已经是云原生的应用,可以考虑使用Consul,搭配Registrator和Consul Template来实现应用外的服务注册与发现。

发布了130 篇原创文章 · 获赞 62 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/hgstclyh/article/details/98472395