微服务必然是分布式的。
分布式的特点:
-
多节点
-
不共享主内存
-
节点之间通过网络发送消息合作 (比如通过http rest接口,通过RPC)
注意:微服务可以是异构的,即服务可以是不同的语言,不同的数据库,服务直接通过http或者RPC进行通信。
下面是一个简单的微服务架构:
- 服务注册与发现组件
服务提供方,要将自己的地址等信息注册到注册表里。这样,服务的调用方才能从该组件上成功的找到。
- 服务网关
除了微服务内部相互调用,还需要将服务暴露给外部,比如手机,PC访问。这就需要服务网关。
网关需要对外屏蔽后台服务的一些细节,比如后台的程序升级等,但对用户是无感知的。
路由的功能:可以将外部的请求反向到路由内部的某个微服务去。
还可以做一些限流和容错的功能,因为所有的请求都会经过网关,我们可以控制流量,监控和日志。比如用户的认证授权,反爬虫。
- 后端通用服务(中间层服务)
启动时,会将服务信息注册到服务注册表里。
- 前端服务(边缘服务)
对后端服务做一些【聚合】和【裁剪】后暴露给客户端。
聚合:比如说,客户端向后端请求——获取用户和获取收获人地址两个接口,这时前端服务可以做一个聚合,返回一个聚合接口供前端调用,这样就可以减少请求数。
裁剪:比如说都是商品详情的接口,手机端返回的信息可以少一点,Pc端返回的商品信息多一点。
服务的拆分:
- 每个微服务可以有自己单独的数据存储。
- 依据服务特点选择不同的结构的数据库类型。
比如,如果是个搜索服务,我们可以采用ES,或者Solr等全文索引数据库作为我们的存储引擎。
Spring Cloud
微服务是可以独立部署、水平扩展、独立访问(或者有独立的数据库)的服务单元,springcloud就是这些微服务的大管家。Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如配置管理、服务发现、断路器、智能路由、微代理、控制总线、负载均衡、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。
那么,Dubbo和Spring Cloud有何不同?
首先做一个简单的功能对比:
从上图可以看出其实Dubbo的功能只是Spring Cloud体系的一部分。这样对比是不够公平的,首先 Dubbo 是 SOA 时代的产物,它的关注点主要在于服务的调用,流量分发、流量监控和熔断。而 Spring Cloud 诞生于微服务架构时代,考虑的是微服务治理的方方面面,另外由于依托了 Spring、Spring Boot 的优势之上,两个框架在开始目标就不一致,Dubbo 定位服务治理、Spring Cloud 是一个生态。
下面咱一一介绍几个Spring Cloud的骨干成员。
Config 远程配置服务
在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config配置管理工具包,让你可以把配置放到远程服务器,集中化管理集群配置,目前支持本地存储、Git以及Subversion。
Eureka
- Eureka负责服务注册和服务发现,为了高可用,一般需要多个Eureka server相互注册,组成集群。Eureka Server的同步遵循着一个非常简单的原则:只要有一条边将节点连接,就可以进行信息传播与同步。
- Eureka内部对于注册的service主要通过心跳来监控service是否已经挂掉,默认心跳时间是15s。这就意味着,当一个服务提供方挂掉以后,服务订阅者最长可能30s以后才发现。
- service启动连上Eureka之后,会同步一份服务列表到本地缓存,服务注册有更新时,Eureka会推送到每个service。
- Eureka会有一些策略(熔断器)防止由于某个服务所在网络的不稳定导致的所有服务心跳停止的雪崩现象。
- Eureka自带web页面,在页面上能看到所有的服务注册情况 和 eureka集群状态。
- Eureka支持服务主动从eureka上下掉自己,同时service进程也会自己停掉自己。
Ribbon
客户端负载均衡组件,软负载,即由客户端负载均衡组件决定该请求去调用哪台服务器的资源。当服务发现以后,每个service在本地知道自己要调用的服务有多少台机器,机器的ip是什么,端口号是多少,那这个service在本地需要有一个负载均衡策略,为每一次请求选择一台目标机器进行调用,而ribbon做的就是负载均衡策略的选择。Spring Cloud中RestTemplate, Fegin, Zuul都用到了Ribbon的负载均衡。
Ribbon提供了多种负载均衡策略,包括BestAvailableRule、AvailabilityFilteringRule、WeightedResponseTimeRule、RetryRule、RoundRobinRule、RandomRule、ZoneAvoidanceRule等,默认是ZoneAvoidanceRule轮训。当然,也可以自定义自己的负载均衡策略,比如被调用服务需要灰度发布或者A/B测试的话,就可以在ribbon这一层做自定义。
Fegin
声明式、模板化的HTTP客户端,用作服务之间的通信。
微服务之间的调用本质还是http请求,如果对于每个请求都需要写请求代码,增加请求参数,同时对请求结果做处理,就会存在大量重复工作,而Feign非常优雅的帮助我们解决了这个问题,只需要定义一个interface,fegin就知道http请求的时候参数应该如何设置。同时,Feign也集成了Ribbon,只要在微服务中依赖了Ribbon,Feign默认会使用Ribbon定义的负载均衡策略。
最重要的是,Feign并不是仅仅只能使用在有Eureka或者Ribbon的微服务系统中,任何系统中,只要涉及到http调用第三方服务,都可以使用Feign,帮我们解决http请求的代码重复编写。
Hystrix防雪崩利器
断路器,类似于物理电路图中的断路器。Feign默认集成了Hystrix。
正常情况下,当整个服务环境中,某一个服务提供方由于网络原因、数据库原因或者性能原因等,造成响应很慢的话,调用方就有可能短时间内累计大量的请求线程,最终造成调用方down,甚至整个系统崩溃,即所谓的“雪崩”。而加入Hystrix之后,如果Hystrix发现某个服务的某台机器调用非常缓慢或者多次调用失败,就会短时间内把这条路断掉,所有的请求都不会再发到这台机器上。如果某个服务所有的机器都挂了,Hystrix会迅速失败,马上返回,保证被调用方不会有大量的线程堆积。
上面有提到,使用Eureka时,当一个服务提供方挂掉以后,服务订阅者最长可能30s以后才知道,那这30s就会出现大量的调用失败。如果在系统里面集成了Hystrix,就会马上把挂掉的这台服务提供方断路掉,让请求不再转发到这台机器上,大量减少调用失败。Hystrix执行断路操作以后,并不表示这条路就永远断了,而是会一定时间间隔内缓慢尝试去请求这条路,如果能请求成功,断路就会恢复。
· 有一点需要注意的是Hystrix在做断路时,默认所有的调用请求都会放在一个的线程池中进行,线程池的作用很明显,有隔离性。比如gateway,集成了5个子业务系统,可能其中一个系统的调用量非常大,而另外四个系统的调用很小,如果没有线程池的话,显然第一个系统的大量调用会影响到后面四个系统的调用性能。Hystrix的线程池和java标准线程池一样,可以配置一些参数:coreSize、maximumSize、maxQueueSize、queueSizeRejectionThreshold allowMaximumSizeToDivergeFromCoreSize、keepAliveTimeMinutes等,如果某一个子系统的调用量突然激增,超过了线程池的容量,也会迅速失败,直接返回,起到降级和保护系统本身的作用。当然hystrix也支持非线程池的方式,在本地请求线程中做调用,即semaphore模式,官方不建议,除非系统qps真的很大。
zuul服务网关
是一个网关组件,提供动态路由,监控,弹性,安全等边缘服务的框架。zuul只需要简单配置一下yml文件,不需要写具体的代码就可以实现将请求转发到相应的服务上去,还可以定制化一些filter做验证、隔离、限流、文件处理等切面,对于网关来说,使用zuul能减少大量的代码。
Spring Cloud Bus
事件、消息总线,用于在集群(例如,配置变化事件)中传播状态变化,可与Spring Cloud Config联合实现热部署。