一、Java 应用架构趋势
现状:各种架构风格中,微服务架构仅占 32%,单体架构占比 22%,模块化单体架构占比 13%,SOA 架构占比 12%。
二、微服务架构趋势
既然微服务架构占比高一些,我们就来看一下微服务架构的应用趋势。
微服务架构的应用状态
从结果来看,有 44%的人团队已经是完全微服务架构了,还有 44%的团队在向微服务架构迁移。可见,在 Java 行业中,微服务架构是得到大家普遍认可的。
- 但是这个结果与上面的架构风格占比结果有出入,可能是问卷题目设计问题,或者问题回答者的主观原因,不能够苛求结果准确性。
三、每个应用中微服务的数量
既然是微服务架构,每个应用中服务数量必然超过 1 个。从结果可以看出来,有 54%的应用中少于 10 个服务,还有 22%的应用服务数量超过 20 个。
按照公司规模统计:
按照公司规模维度,越是大公司,每个应用中服务数量越多,结果符合康威定律的。
从大家普遍实践结果看,当团队规模较小时,要尽量减少微服务数量。市面上很多老师会告诉我们,微服务架构要按照业务域拆分,但是你要知道,如果团队规模不大,即使拆分了业务域,可能最终开发调试维护也只有你一个。
四、微服务实现技术
从结果看,SpringBoot 几乎霸占了整个微服务市场。所以,大家在日常工作学习过程中,还是主要看看 SpringBoot 栈吧。
在国内,SpringBoot 技术栈还会细分为 SpringNetflixCloud 栈、SpringAlibabaCloud 栈、SpringBoot+Dubbo 栈等。
不同的技术栈中组件有些差异,所以我们需要掌握的不是简单的应用,还要了解其中的原理。原理掌握了,不同的组价只是在应用层面的差异。
五、启动需要多长时间
可以看到,只有 9%的服务在 1 分钟内启动成功,有 26%的服务启动时间需要 10 分钟以上。
按照公司规模看:
从上图可以看出来,人员规模大于 100 人的公司中,服务启动时间普遍长于少于 100 人的公司。产生这种情况的原因有这么几个:
-
公司规模大一些,可能业务复杂一些,服务中的代码、类库更多一些;
-
公司规模大一些,依赖的组件更多一些,在服务启动时,需要与各种中间件建立链接,然后彼此交换成功心跳,自然需要时间更多。
采用微服务其中一个好处是服务足够小,启动时间比较少。但是,从上面两个问卷结果来看,普遍情况是启动时间比较长,而且在变得更长。
一、什么是微服务?
微服务是相对于单体服务来说的,即将单体服务按照一定的规则进行拆分,如按照业务类型,如:
单体服务:如hubble-api,hubble-job
微服务:如hubble-biz-cm(配置服务),hubble-biz-host(资产服务)、告警查询服务、告警投递服务、数据统计服务等
进化过程:单体服务 → 部分拆分 → 服务间交互? –> 架构标准化,术语标准化
主要角色:
注册中心,服务提供者,服务消费者
二、微服务 VS 单体服务
1、微服务
优点:
- 升级部署影响小。升级时,只需要重启本服务即可,如hubble-biz-cm。
- 服务启动快,开发效率高,故障时间短。
- 代码量少
- 由于往往伴随着数据库拆分,因此需要连接的数据库也会变少
- 低耦合,高内聚
- 云原生时代(K8S),单体服务注定淘汰
- 开发简单。针对某块功能开发相对容易,只需要熟悉某个服务代码即可
缺点:
- 技术组件多,学习成本大
- 部署进程多,部署复杂,服务之间的调用变的复杂
- 维护较为困难。需要引入调用链进行监控观测
- 性能会有所降低。原来方法间调用,变成了进程间调用,需要有一定的网络开销,代码封装的开销
2、单体服务
优点:
- 升级简单。
- 技术组件简单,坑比较少,遇到问题排查快,相对可控
- 服务关系简单,仅有一个进程。
缺点:
- 随着代码逐渐增加,启动越来越慢,影响开发的心情
- 越来越多的数据库连接,中间件连接等
- 越来越多的代码需要编译等
- 影响巨大。
- 小小的改动升级就会重启整个业务,业务很容易感知到。
- 比如VPS服务,随便改个功能,启动过程如果有业务申请虚机就歇菜了
- 服务故障重启时间长,故障恢复慢,甚至轻易不敢去重启
- 比如VPS服务,启动要接近2分钟,每次升级服务都心惊胆战
- 小小的改动升级就会重启整个业务,业务很容易感知到。
- 扩展性差
- 增加功能只能在单体项目中加,耦合严重,很容易出问题
三、微服务框架
1、主流Java微服务开发框架
- Spring Cloud(一直很火)
- 全家桶。SpringCloud是一系列框架的集合。它基于SpringBoot的便利性融合了一整套实现微服务的框架并提供了服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等组件。
- Dubbo(阿里开源,以前比较火)
2、Spring boot
基于spring boot可快速开发单个微服务。框架的框架,简化配置文件,降低开发难度。
类比:
Spring cloud:互联网
Spring boot:服务器
理念:约定优于配置。目的在于减少软件开发人员所需要做出的决定的数量。
- 大量使用注解。代替众多的XML配置。(老的Spring使用了大量的XML配置)
- 默认的加载方式。如数据库连接,配置的方式通过前缀定义即可。
- 默认内嵌了Tomcat服务器,不用安装tomcat,也不用在启动的时候配置tomcat启动
优点:
- 提供众多starter,我们只需要在配置文件中配置数据源信息即可。
- spring-boot-starter-web
- spring-cloud-starter-eureka:有互联网的能力
- spring-boot-starter-data-redis
- spring-boot-starter-aop:切面配置,如加日志,异常处理
- spring-boot-starter-activemq
- spring-boot-starter-rocketmq
- spring-boot-starter-freemarker:自动引入配套的freemarker包
- mybatis-spring-boot-starter:持久层框架,数据库管理组件
- druid-spring-boot-starter:数据库连接池
- spring-boot-starter-actuator:监控组件,自动监控进程相关指标
- IOC(控制反转):系统自动创建并维护对象,多实例,单实例
- 内嵌了Web容器(Tomcat、Jetty和Undertow),降低了对环境的要求
- 搭建快速:直接下载官方包启动即可
- 配置简化:减少了很多spring的配置文件
3、微服务配套运行环境
K8S
Docker
4、微服务治理Istio
服务网格。它是一组和应用服务部署在一起的轻量级的网络代理。使微服务治理与服务本身解耦。
1、多样化的灰度发布(金丝雀发布);
- 基于流量:20%流量访问V2,80%流量访问V1
- 基于用户:zhangsan访问V2,其它访问V1
2、故障注入(类似小鹿乱撞,但场景较少)。支持随机向服务通信中注入故障(如模拟延时/网络中断),检测服务的可靠性;
- Isito 支持注入两种类型的故障:网络延迟和中断。
- 中断是模拟上游服务崩溃的情况,表现为 HTTP 的错误码和 TCP 连接失败。
3、提供非侵入的熔断,超时,重试机制;
4、安全认证。无侵入式地为服务增加认证、鉴权和加密通信的能力。
相关配置
#按照流量比例灰度
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-hubble-biz-host
namespace: hubble-manager-istio-host
spec:
gateways:
- hubble-gateway
- mesh
hosts:
- istio.hubble.qiyi.domain
- m-biz-host.hubble-manager-istio-host.svc.cluster.local
http:
- match:
- uri:
prefix: /api/biz/host
route:
- destination:
host: m-biz-host.hubble-manager-istio-host.svc.cluster.local
subset: hubble-biz-host-2-2-7-005
weight: 10
- destination:
host: m-biz-host.hubble-manager-istio-host.svc.cluster.local
subset: hubble-biz-host-2-2-7-006
weight: 90
#按照用户灰度(比如hubble-query,访问量比较多的组token,可以按照用户升级,好处是方便和业务沟通效果)
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
end-user:
exact: jason
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v1
四、服务注册与发现
1、开源系统
很多系统都会涉及服务注册与发现,如K8S,Promethus,Spring Cloud(eureka),zookeeper、Dubbo,consul
2、角色
服务注册:针对服务提供者。服务提供方将自己调用地址注册到服务注册中心,让服务调用方能够方便地找到自己。
注册中心:中间代理,价值就是管理服务,管理一个健康的服务列表。
服务发现:针对服务消费者。服务调用方从服务注册中心找到自己需要调用的服务的地址。
3、K8S服务注册与发现
3.1、介绍
针对Service资源对象而言。
发现的含义:pod怎么找到另一个pod,并发送请求
3.2、注册与发现流程
注册过程:
- 通过API创建Service资源对象,并得到ClusterIp
- CoreDNS 监听 API Server,发现有新建的 Service 对象,则创建一个从 Service 名称与 ClusterIP 的域名映射记录。
发现流程:
- 服务消费者(POD)向集群 DNS 发出查询,把 Service 名称解析为 ClusterIP(一般也会本地缓存一份配置)
- 然后服务消费者(POD)将流量发送给ClusterIP 上(最终流量被转发给 Pod 所在节点的网卡)
- 物理节点Node将ClusterIp的数据转向健康的 Pod。
3.3、使用案例
比如prometheus server将告警消息打到alertmanager:http://prometheus-api.qiyi.domain/prometheus/prometheus/
比如prometheus operator ServiceMonitor配置:QKE
3.4、K8S服务注册与发现总结
服务注册:Service
注册中心:DNS
服务发现:服务使用者,如Pod,从注册中心(DNS)拉取服务列表
4、Promethus服务注册与发现
原理:借助第三方服务发现代理,如k8s服务发现,eureka服务发现,consul服务发现
K8S(kubernetes_sd_configs):http://prometheus-api.qiyi.domain/prometheus/prometheus/
Promethus服务发现角色总结:
服务注册:无
注册中心:第三方注册中心,如eureka,k8s的Service
服务发现:针对第三方注册中心开发发现逻辑
5、SpringCloud服务注册与发现:eureka
介绍
eureka服务注册与发现组件,是spring cloud推荐的注册中心实现,是分布式开发的核心组件之一
架构
高可用(ap)(对比zookeeper(cp))
eureka:集群部署,数据备份,当某个节点挂掉之后,客户端请求会自动切换 到新的Eureka节点;当宕机的服务器重新恢复后,Eureka会再次将其纳入到服务器集群管理之中;
zookeeper:虽然也是集群部署,数据备份,但是zookeeper当集群中只有master提供服务,当master节点挂了之后,会进行重新选举,选举需要花费秒级的时间;
自我保护机制
当Eureka Server节点在短时间内丢失过多的客户端时(可能发送了网络故障),那么这个节点将进入自我保护模式,不再注销任何微服务,当网络故障回复后,该节点会自动退出自我保护模式。
五、Spring cloud其它微服务组件
1、feign
对服务进行声明式调用,封装了接口调用,让接口调用变的简单,代码层面类似于调用方法
普通web调用:
|
缺点:
- 无错误检查:如某个参数名称输错了
- 无熔断,需要配置超时,当调用量大容易影响对方服务
- 手动输入参数名称
- 代码复杂,代码可读性差;
- 逻辑混乱,调用对象不明确
feign调用:
声明:@FeignClient(name = "hubble-biz-aiops")
List<AlarmLevelesVO> list = aiopsAlarmLevelesServiceRemote.getLevelListByEventid(eventid);
Feign优势:
- 可插拔的注解支持:@FeignClient(name = "hubble-biz-aiops")
- 支持Hystrix和异常的时候进行Fallback;
- 整合Ribbon的负载均衡;
- 支持HTTP请求和响应的压缩。
响应压缩配置:
|
2、ribbon
ribbon 是一个客户端负载均衡器,可类比于nginx的负载均衡模块功能。
服务提供者往往是通过集群部署,ribbon的职责是将请求均匀的转发服务集群中的所有服务器/POD
和nginx区别
nginx:独立的负载均衡服务,消费者与服务提供者的中间组件
ribbon:进程内负载均衡,类库
|
3、hystrix
熔断器。
作用:当发现服务提供者有问题时,及时停止调用,避免影响自己和服务提供者。
- 保护自身:避免本功能占用进程太多线程资源,影响自身稳定性
- 保护对方:避免发送太多请求,给服务提供者提供太多压力,甚至造成服务提供者卡死的情况
- 保护调用本服务的客户端:自身出问题可能还会影响调用者
详情见六单独描述
4、fegin - hytrix - ribbon协作流程
5、zuul
作用:网关,参考nginx
- 现负载均衡、反向代理
对比nginx无优势,性能差不多
6、config
配置中心。
作用:动态更新配置。
当前hubble微服务未使用
7、bus
消息总线。
作用:用于在集群(例如,配置变化事件)中传播状态变化,可与Config联合实现热部署,达到自动化动态更新配置。
8、Spring Cloud Consul
服务注册与发现。
作用:类似Eureka,Eureka2.x已经闭源。
原理:基于Consul,封装了Consul操作
9、Security
安全认证。
如登录系统时的用户名,密码
我们统一使用公司单点登录
六、熔断器 - hystrix
熔断的目的:是为了保证服务高可用。不能因为系统中的一个小服务不可用,从而导致整个系统崩溃。
目标:1、快速失败。2、自愈。
熔断策略:
状态:
- Closed: 关闭状态(断路器关闭),所有请求都正常访问。
- Open:打开状态(断路器打开),所有请求都会被降级。Hystix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全关闭。默认失败比例的阈值是50%,请求次数最少不低于20次。
- Half Open:半开状态,Closed状态不是永久的,关闭后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放部分请求通过,若这些请求都是健康的,则会完全打开断路器,否则继续保持关闭,再次进行休眠计时。
状态切换:
1、当请求后端服务失败数量超过一定比例(默认50%), 断路器会切换到开路状态(Open)。这时所有请求会直接失败而不会发送到后端服务。
2、断路器保持在开路状态一段时间后(默认5秒),自动切换到半开路状态(HALF-OPEN)。这时会判断下一次请求的返回情况,如果请求成功,断路器切回闭路状态(CLOSED),否则重新切换到开路状态(OPEN)。
Fallback
Fallback相当于是降级操作。对于重要的查询操作可以将缓存数据返回,让业务无感知。
资源隔离技术
通过线程池实现。每个应用名称对应一个线程池。
|
Hystrix遵循的设计原则总结:
- 防止任何单独的依赖耗尽资源(线程)
- 过载立即切断并快速失败,防止排队
- 尽可能提供回退以保护用户免受故障
- 使用隔离技术来避免服务间相互影响
- 通过近实时的指标,监控和告警,确保故障被及时发现
- 防止整个依赖客户端执行失败,而不仅仅是网络通信
- 超时
- 网络故障
- 服务端500等