微服务是相对于单体服务来说的,即将单体服务按照一定的规则进行拆分,如按照业务类型,如:
单体服务:如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-webspring-cloud-starter-eureka:有互联网的能力spring-boot-starter-data-redisspring-boot-starter-aop:切面配置,如加日志,异常处理spring-boot-starter-activemqspring-boot-starter-rocketmqspring-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资源对象,并得到ClusterIpCoreDNS 监听 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服务发现
Configuration | Prometheus
K8S(kubernetes_sd_configs):http://prometheus-api.qiyi.domain/prometheus/prometheus/
Promethus服务发现角色总结:
服务注册:无
注册中心:第三方注册中心,如eureka,k8s的Service
服务发现:针对第三方注册中心开发发现逻辑
5、SpringCloud服务注册与发现:eureka介绍
eureka服务注册与发现组件,是spring cloud推荐的注册中心实现,是分布式开发的核心组件之一
http://10.49.4.119:9500/
架构
高可用(ap)(对比zookeeper(cp))
eureka:集群部署,数据备份,当某个节点挂掉之后,客户端请求会自动切换 到新的Eureka节点;当宕机的服务器重新恢复后,Eureka会再次将其纳入到服务器集群管理之中;
zookeeper:虽然也是集群部署,数据备份,但是zookeeper当集群中只有master提供服务,当master节点挂了之后,会进行重新选举,选举需要花费秒级的时间;
自我保护机制
当Eureka Server节点在短时间内丢失过多的客户端时(可能发送了网络故障),那么这个节点将进入自我保护模式,不再注销任何微服务,当网络故障回复后,该节点会自动退出自我保护模式。
五、Spring cloud其它微服务组件 1、feign对服务进行声明式调用,封装了接口调用,让接口调用变的简单,代码层面类似于调用方法
普通web调用:
| String url = PropKit.get("lingxu-new"); Map params.put("token", getSysVal("lingxu-api-token")); params.put("uuid", uuid); String result = WebUtil.doGet(url, params, 60000, 60000); |
缺点:
无错误检查:如某个参数名称输错了无熔断,需要配置超时,当调用量大容易影响对方服务手动输入参数名称代码复杂,代码可读性差;逻辑混乱,调用对象不明确
feign调用:
声明:@FeignClient(name = "hubble-biz-aiops")
List list = aiopsAlarmLevelesServiceRemote.getLevelListByEventid(eventid);
Feign优势:
可插拔的注解支持:@FeignClient(name = "hubble-biz-aiops")支持Hystrix和异常的时候进行Fallback;整合Ribbon的负载均衡;支持HTTP请求和响应的压缩。
响应压缩配置:
| server.compression.enabled=true server.compression.mime-types=application/json #默认是2048,即2K server.compression.min-response-size=2048000 |
ribbon 是一个客户端负载均衡器,可类比于nginx的负载均衡模块功能。
服务提供者往往是通过集群部署,ribbon的职责是将请求均匀的转发服务集群中的所有服务器/POD
和nginx区别
nginx:独立的负载均衡服务,消费者与服务提供者的中间组件
ribbon:进程内负载均衡,类库
| ribbon负载均衡配置 #开启重试功能 spring.cloud.loadbalancer.retry.enabled=true #请求连接的超时时间,单位毫秒 ribbon.ConnectTimeout=30000 #请求处理的超时时间, 单位毫秒 ribbon.ReadTimeout=30000 #对所有操作请求都进行重试 ribbon.OkToRetryonAllOperations=true #对当前实例的重试次数 ribbon.MaxAutoRetries=0 #最多重试多少台服务器 ribbon.MaxAutoRetriesNextServer=2 |
熔断器。
作用:当发现服务提供者有问题时,及时停止调用,避免影响自己和服务提供者。
保护自身:避免本功能占用进程太多线程资源,影响自身稳定性保护对方:避免发送太多请求,给服务提供者提供太多压力,甚至造成服务提供者卡死的情况保护调用本服务的客户端:自身出问题可能还会影响调用者
详情见六单独描述
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相当于是降级操作。对于重要的查询操作可以将缓存数据返回,让业务无感知。
资源隔离技术
通过线程池实现。每个应用名称对应一个线程池。
| #并发执行的最大线程数,默认10 hystrix.threadpool.default.coreSize=50 #BlockingQueue的最大队列数,默认值-1 hystrix.threadpool.default.maxQueueSize=1000 #即使maxQueueSize没有达到,达到queueSizeRejectionThreshold该值后,请求也会被拒绝,默认值5 hystrix.threadpool.default.queueSizeRejectionThreshold=800 #hubble-biz-host hystrix.threadpool.hubble-biz-host.coreSize=80 hystrix.threadpool.hubble-biz-host.maxQueueSize=1000 hystrix.threadpool.hubble-biz-host.queueSizeRejectionThreshold=800 #hubble-biz-cm hystrix.threadpool.hubble-biz-cm.coreSize=150 hystrix.threadpool.hubble-biz-cm.maxQueueSize=1000 hystrix.threadpool.hubble-biz-cm.queueSizeRejectionThreshold=800 |
Hystrix遵循的设计原则总结:
防止任何单独的依赖耗尽资源(线程)过载立即切断并快速失败,防止排队尽可能提供回退以保护用户免受故障使用隔离技术来避免服务间相互影响通过近实时的指标,监控和告警,确保故障被及时发现防止整个依赖客户端执行失败,而不仅仅是网络通信
超时网络故障服务端500等
七、Hubble-manager微服务架构实践


