近两年Springboot、Springcloud使用的越来越多。先了解下概念:
SpringBoot:旨在简化创建产品级的 Spring 应用和服务,简化了配置文件,使用嵌入式web服务器,含有诸多开箱即用微服务功能,可以和spring cloud联合部署。
SpringCloud:微服务工具包,为开发者提供了在分布式系统的配置管理、服务发现、断路器、智能路由、微代理、控制总线等开发工具包。
SpringCloud整合了一套较为完整的微服务解决方案框架,而Dubbo只是解决了微服务的几个方面的问题。
content | Dubbo | SpringCloud |
---|---|---|
服务注册中心 | zookeeper | Spring Cloud Netflix Eureka |
服务调用方式 | RPC | REST API |
服务网关 | 无 | Spring Cloud Netflix Zuul |
断路器 | 不完善 | Spring Cloud Netflix Hystrix |
分布式配置 | 无 | Spring Cloud Config |
服务跟踪 | 无 | Spring Cloud Sleuth |
消息总线 | 无 | Spring Cloud Bus |
数据流 | 无 | Spring Cloud Stream |
批量任务 | 无 | Spring Cloud Task |
当然,虽然dubbo没有提供很多解决方案,但他也可以整合第三方的项目来实现。
SpringCloud服务注册中心(eureka-server)和一个服务的提供方(eureka-provider)。
1、在使用dubbo时,一般都结合zk(作为注册中心)来使用。为什么SpringCloud中使用Eureka,而不是zk呢?
在CAP理论中,zk更看重C和P,即一致性和分区容错性。但Eureka更在意的是A和P,A为高可用。
在分布式环境中,相同的业务应用分布在不同的机器上,有些业务逻辑(例如一些耗时的计算,网络I/O处理),往往只需要让整个集群中的某一台机器进行执行,其余机器可以共享这个结果,这样可以大大减少重复劳动,提高性能,于是这Leader选举便是这种场景下的碰到的主要问题。
ZooKeeper需要在所有的服务(可理解为服务器)中选举出一个Leader,然后让这个Leader来负责管理集群。此时,集群中的其他服务器则成了此Leader的follower。 一个简单的方案是,让所有的Follower监视leader所对应的节点。当Leader发生故障时,Leader所对应的临时节点(eg: /election/sessionId_3 )会被自动删除,此操作将会触发所有监视Leader的服务器的watch。这样这些服务器就会收到Leader故障的消息,进而进行下一次的Leader选举操作。 这种操作将会导致“从众效应”的发生,尤其是当集群中服务器众多并且宽带延迟比较大的时候更为明显。在ZooKeeper中,为了避免从众效应的发生,它是这样来实现的:每一个Follower为Follower集群中对应着比自己节点序号小的节点中x序号最大的节点设置一个watch。只有当Followers所设置的watch被触发时,它才惊醒Leader选举操作,一般情况下它将成为集群中的下一个Leader。 并且,当Leader出现故障的时候,ZooKeeper要能够快速地在Follower中选举出下一个Leader。这就是ZooKeeper的Leader机制,当进入选举模式时,就无法正常对外提供服务。但Eureka中,集群是对等的,地位是相同的,虽不能保证一致性,但至少可以提供注册服务。 根据不同的业务场景,各有取舍吧。
2、zookeeper的Leader选举机制原理是什么?
下面以一个简单的例子来说明整个选举的过程。
假设有五台全新服务器组成的zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依序启动,来看看会发生什么。
1)服务器1启动,此时只有它一台服务器启动了,它发出去的报没有任何响应,所以它的选举状态一直是LOOKING状态。
2)服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1,2还是继续保持LOOKING状态。
3)服务器3启动,根据前面的理论分析,服务器3成为服务器1,2,3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的leader。
4)服务器4启动,根据前面的分析,理论上服务器4应该是服务器1,2,3,4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了。
5)服务器5启动,同4一样,当小弟。
那么,初始化的时候,是按照上述的说明进行选举的,但是当zookeeper运行了一段时间之后,有机器down掉,重新选举时,选举过程就相对复杂了。
需要加入数据id、leader id和逻辑时钟。
数据id:数据新的id就大,数据每次更新都会更新id。
Leader id:就是我们配置的myid中的值,每个机器一个。
逻辑时钟:这个值从0开始递增,每次选举对应一个值,也就是说: 如果在同一次选举中,那么这个值应该是一致的 ; 逻辑时钟值越大,说明这一次选举leader的进程更新.
选举的标准就变成:
1)逻辑时钟小的选举结果被忽略,重新投票。
2)统一逻辑时钟后,数据id大的胜出。
3)数据id相同的情况下,leader id大的胜出。
根据这个规则选出leader。
3、Eureka的高可用方案,如何避免单点问题呢?
可以采用集群的方式来解决。 比如现在有三台机器:Server1、Server2和Server3,在高可用方案中,三台机器要两两注册。比如S1要向S2、S3分别进行注册,目前他无法实现注册的传递性。 这样一来,如果Server1宕机,我们还可以继续从Server2和Server3中获取服务。
4、restful API是一种设计理念,那么Restful和RPC到底什么关系?
接口调用通常包含两个部分,序列化和通信协议。 常见的序列化协议包括json、xml、hession、protobuf、thrift、text、bytes等;通信比较流行的是http、soap、websockect,RPC通常基于TCP实现,常用框架例如netty。
Restful架构是基于Http应用层协议的产物,RPC架构是基于TCP传输层协议的产物。
restful(http+json)首先是要求必须把所有的应用定义成为“resource”,然后只能针对资源做有限的四种操作。所谓“resource”,可以举个列子,在OA系统查看当月的工资情况,需要先登录公司主页,然后进入我的薪资页面,输入密码才可以看见当月工资。整个流程,都是依赖于前一步操作,只要前置操作不成功,后续操作就无法执行。此时可以把每一步作为资源或状态,抛开所有资源或状态直接打开当月工资页面,就是一个最简单的restful风格。有太多现实中需要的API,无法顺当的融入到restful所定义的规范中。比方说,user login / resetpassword等等。 如果硬要把login / password等也纳入为某种资源,然后进行增删改查。这在我看来,纯粹是在解决一些原本不存在,根本不需要解决的问题,纯浪费。所有的接口,服务器端原本就存在有相应的函数,它们本来就有自身的命名空间,接受的参数、返回值、异常等等。采用轻便的方式暴露出来即可。无需把一堆函数重新归纳到“资源”,再削减脑袋把所有的操作都映射为“增删改查”。对应到web上,rpc的成熟方案非常多,有古老的soap(基于xml数据序列化进行http协议的一种规范),也有轻量的json rpc(基于json序列化进行二进制传输,而不是http)。
Restful | HTTP+JSON | 偏向对外提供 | |
RPC | JSON-RPC | TCP+JSON | 偏向web项目 |
WebSocket | TCP+JSON | ||
SOAP | TCP+XML |
restful,仅适用与业务非常简单的场景,就是为了提供少量数据表单的增删改查。
websocket,批量调用,乱序返回,这些都可以显著提高API的输出吞吐,这些是在json rpc的设计考量内。 调用更方便,性能也更好,两全其美是完全可能的。想当然的为了“快”,为了“简单”就必须牺牲别的,这是严重的思维误区。
http相对更规范,更标准,更通用,无论哪种语言都支持http协议。如果你是对外开放API,例如开放平台,外部的编程语言多种多样,你无法拒绝对每种语言的支持,相应的,如果采用http,无疑在你实现SDK之前,支持了所有语言,所以,现在开源中间件,基本最先支持的几个协议都包含RESTful。
RPC协议性能要高的多,例如Protobuf、Thrift、Kyro等,(如果算上序列化)吞吐量大概能达到http的二倍。响应时间也更为出色。千万不要小看这点性能损耗,公认的,微服务做的比较好的,例如,netflix、阿里,曾经都传出过为了提升性能而合并服务。如果是交付型的项目,性能更为重要,因为你卖给客户往往靠的就是性能上微弱的优势。