微服务是什么?
我第一次接触到这个词汇,以为是一个基于微信的服务,听起来感觉有些low。其实不然。微服务是一种架构模式,一种分布式的架构风格。顾名思义,micro service,将一个庞大的单体应用拆分成若干个“微小”的服务,服务间通过进程通讯完成原本在单体应用中的调用。其中必要的六个基本技术为:1、服务注册与发现;2、进程间通信;3、负载均衡;4、分布式配置中心;5、熔断器;6、网关路由。根据以上六点,以及现有的优秀开源技术,在技术选型上,稍微做下排列组合,你可能好几个月都试不完。之前没有了解的朋友可以阅读一下Chris Richardson 大师的微服务系列文集,对微服务会有一个初步的认识。也欢迎你与我,一同探讨微服务的技术选型,以及高可用方案。
初次尝试——遇见Spring Cloud
国内已经有一些公司使用springcloud实现微服务。我开始调研的时候,也在SpringCloud的体系里花了一些时间,拿出了一套基于SpringCloud+Docker的方案。SpringCloud整合了Netflix公司的一套组件。国外Netflix公司也算是比较早实践微服务的公司了,Netflix的一套开源项目,为微服务提供了比较完善的方案。我之前拿出的SpringCloud微服务实现方案,大部分的技术都是来源于Netflix
- 注册中心——Eureka
之前我是选用Netflix公司提供的eureka作为注册中心。在以前,我接触的分布式体系大多数是一个zookeeper+dubbo的组合。目前国内短期内还是dubbo的天下。zookeeper也常常被用作注册中心,在国内的使用率非常高。注册中心可以说的上是一个微服务体系的核心,它承载了很多的调度与负载。在分布式领域有个著名的CAP定理(C:数据一致性;A:服务可用性;P:服务队网络分区故障的容错性,这三点一般不能同时满足,最多同时满足两个)。为什么不使用zookeeper而使用eureka呢?答案就从CAP定理中去寻找,显然zk是一个CP,为了保证数据的一致性,zk有一个选举leader节点的过程,了解zk的朋友一定知道,zk对于leader的选举,有一个“法定人数”:n+1,如果达不到这个“法定人数”,这个网络分区就会从zk中断开,也就不能提供相应的service发现服务了。显然,这不是我们想要看到的结果。
再来看看Eureka,它是一个典型的客户端发现模式,且是自注册的。
再者,它是一个AP,可以更好的保证系统的可用性。正常配置下,Eureka内置了心跳服务,用于淘汰一些“濒死”的服务,如果再eureka中注册的服务,它的“心跳”变得迟缓,Eureka会将其剔除管理范围。有的朋友可能就会问,那如果也是因为网络问题,eureka服务器失去了客户端大量的心跳,可怎么办?Netflix充分考虑到了这个问题,Eureka存在自我保护机制,当一段时间内,客户端提供的心跳低于80,将会自动进入自我保护模式,将该分片保护起来。Eureka Server除了单点运行之外,还可以通过运行多个实例,并进行互相注册的方式来实现高可用的部署:
Eureka server1
server.port=1111
eureka.instance.hostname=peer1
eureka.client.serviceUrl.defaultZone=http://peer2:1112/eureka/
- 1
- 2
- 3
Eureka server2
server.port=1112
eureka.instance.hostname=peer2
eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/
- 1
- 2
- 3
Client comput-service
server.port=2222
eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/,http://peer2:1112/eureka/
- 1
- 2
-
负载均衡——Ribbon
负载均衡,一个多么耳熟又常见词汇~在我看来,不论是客户端实现还是服务器端的实现,都逃不开那些个负载均衡的常见算法。常见的服务端实现有:Ngnix、HA Proxy等。这里我们主要还是探讨一下客户端等实现,Netflix Ribbon。它的负载均衡策略也很常见:
1.随机选择(RandomRule)
2.线性轮询(RoundRobinRule)
3.重试机制(RetryRule)
4.加权响应(WeightedResponseTimeRule)
5.最小并发数(BestAvailableRule)
-
进程间通信——Restful
终于谈到进程间通信。在分布式体系之中,进程通信的重要程度可以说的上是最基本、最重要的。它承载了进程间的数据交互。在SpringCloud的坑中,多半会使用Restful作为进程通信的方式。基于Http协议,效率你也是可想而知。我们退一步说,当你的服务拆分粒度越来越细,服务间或可能存在链式的调用,效率就成了至关重要的一个问题,所以在我看来,能使用RPC尽量使用RPC,dubbo、thrift、grpc都是非常优秀的rpc技术。
-
分布式配置中心——SpringCloud
既然已经走进了SpringCloud的体系,配置中心自然可以选择一套的,SpringCloud Config,实现配置文件的集中配置化管理。同样,国内也有比较优秀的开源分布式配置管理中心。如:阿里diamond,百度disconf等
-
熔断器——Hystrix
熔断器,顾名思义,作用和物理上的保险丝差不多,线路一旦过载,就断开。
在分布式架构中,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。
从图中不难看出其工作流程:
1.检查缓存
2.检查circuit breaker状态
3.执行相应指令
4.记录数据,计算失败比率
-
网关路由 ——Zuul
Zuul是Netflix出品的一个基于JVM路由和服务端的负载均衡器。Zuul使用Ribbon定位服务注册中的实例,
并且所有的请求都在hystrix的command中执行, 所以失败信息将会展现在Hystrix metrics中, 并且一旦断路器打开,代理请求将不会尝试去链接服务。浅尝辄止——For A Better Idea
在我整理了整套的SpringCloud实现微服务的方案以后,发现了以下的一些问题。
- 非JVM应用的处理
受Netflix Prana的启示,为了更好的兼容一些非JVM应用,SpringCloud提供了一个叫做sidecar的东西。不论是受Prana还是sidecar,其思想都是,都是设计一个JVM程序,和我们非JVM应用跑在同一个容器(主机)里,监测其心跳、健康状态反馈给注册中心。这种思路的出发点很好,但是并没有从根本上解决问题。比如,我要部署一个mycat的服务,我根本没办法为sidecar提供一个健康心跳检测的接口。
- 基于SpringBoot的改造
假设一个乐观的情况,现有的大部分项目都是原生spring,然而总所周知,SpringCloud是基于SpringBoot而来,要使用cloud,必然要进行改造,虽然难度不大,但是这样对程序入侵,真的有必要吗?真的符合我软件开发的原则吗?这还是一个乐观的情况,大部分都还是JVM应用,那如果全是python、php呢?这该如何是好?所以,我开始了新方案的寻找。
- A Better Idea
不能入侵程序,又要达到以上的六个基本要求,这该如何是好?Kubernetes及时闯入了我的视野。
偶然尝试——Kubernetes
Kubernetes(以下简称K8s)不同于SpringCloud,它没有明确的什么客户端服务器的概念,在它的设计理念里:一切皆容器。