1 微服务的着眼点及解决方案

 

0x0 微服务带来的问题

服务之间的通讯问题?

微服务如何发现彼此?

微服务怎样部署?更新?扩容?

0x1 微服务间如何通讯

通讯:socket、tcp/ip、http...

两个角度考虑通讯:

  1. 通讯模式
  2. 通讯协议

通讯模式角度

通讯协议角度

REST API

特点:

  1. 请求方式描述动作类
  2. REST并不是适合于所有业务场景

RPC

MQ - 消息队列

发布订阅的模式,可以使用MQ的方式实现

RPC专项

选择RPC框架

  1. I/O、线程调度模型
    • 同步?非阻塞的异步?
    • 长连接?短连接?
    • 单线程?多线程?线程调度算法?
  2. 序列化方式(效率影响了RPC通讯效率)
    • 可读的
      • XML
      • JSON
    • 二进制
      • pb
  3. 多语言支持
  4. 服务治理
    • 有木有服务发现?
    • 服务监控?

流行的RPC框架

  1. Dubbo/Dubbox
    • 阿里/当当

      • 蓝色:服务启动的时候做的事
      • 实现:同步调用,虚线:异步调用
    • 特点:
      • 只支持Java
      • 有完善的服务治理
  2. Motan
    • 新浪微博
    • 特点:
      • 支持Java
  3. Thrift
    • facebook/Apache

      • 最下面:定义一个API的文件,然后通过Thrift生成定义各种语言代码
      • 生成之后,服务的提供者和消费者需要引用生成的API
      • 服务端通过引用,做实现功能的实现,消费者通过API的存根直接调用提供者
    • 特点:
      • 跨语言
      • CS模式
        • 通过代码生成工具,讲接口定义的文件生成服务器端和客户端的代码(服务端和客户端的代码可以是不同语言的),进而实现服务端和客户端的跨语言支持
      • 序列化:支持很多种
        • 二进制模式
        • 压缩格式
          • 线上使用,提升性能
        • Json模式
        • Debug模式
          • 开发中使用
      • 通讯模式(多种):
        • 阻塞IO
        • NIO
        • 专门传输文件的传输方式
      • 线程模型(多种):
        • 单线程模式
        • 线程池模式
        • 多线程使用非阻塞IO模式
      • 没有服务治理相关东西(没有服务发现和监控)
        • 消费者只能通过提供者的IP:PORT访问
        • 需要自己实现服务发现
  4. Grpc
    • Google
    • 说明:和Thrift类似,需要先写API的定义文件,文件格式是protoBuffer的,然后去生成各语言接口,然后实现跨语言调用
    • 序列化:pb(高效的序列化方式)
    • 通讯协议:没用socket,基于http/2 - 主要面向移动端
      • 编码和传输效率低于socket模式

RPC框架对比


0x2 服务发现、部署更新扩容

服务发现

所有服务对外的形式都是IP:PORT形式

服务发现的本质:让调用者知道提供者的IP和PORT

传统服务「发现」

虚线:主机,上面部署了两个服务

  1. 客户端通过DNS解析到Nginx
  2. Nginx中配置了两台服务器的IP和PORT
  3. Nginx有一个负载均衡策略,如轮询,会依次访问到右边的两个服务

传统的服务「发现」,其实没有发现什么东西:

  1. 所有服务提供者已经写死了
  2. 配置文件的维护和更新需要运维同学「手动操作」

服务发现

客户端的服务发现

微服务启动之后,会把IP和PORT告诉注册中心

客户端从注册中心查需要访问的服务,然后连这个服务

服务端的服务发现

客户端只固定访问一个服务器,这台服务器来做客户端消息的转发、服务内部的发现、负载均衡选择服务器之类的事情

服务的部署、更新、扩容

传统流程

部署流程

代码写好,内网测试通过准备上线→跟运维交涉找到一台空闲的服务器用来部署服务→运维把应用cp到服务器上(Jekins、脚本、其他自动化方式)-(web服务)→ cp一个Tomcat,给服务分配一个端口号(查询端口列表,找一个没有被占用的端口)→ 给域名做DNS解析,解析到对应的Nginx→ Nginx里配置反向代理,指向刚配置的Tomcat

更新流程

单服务器情况:替换旧代码 & 重启服务

双服务器(高可用)情况:线下一台服务器→ 代码更新重启验证没问题→ 上线→ 重复部署到另一台服务器上

扩容

和部署差不多

微服务流程

特点:服务数量巨多,更新上线非常频繁,传统流程运维同学无法接受

解决方案:服务编排

服务编排

包括服务发现、部署、更新、扩容功能,目的是「简化」

服务编排工具

Mesos、Docker Swarm、Kubernetes

0x3 SpringBoot & SpringCloud

Java世界里和微服务密切相关的东东

参考资料:Spring Framework

SpringBoot

目的:化繁为简

核心功能:

  1. 独立运行
    1. 以前运行Spring服务的方式
      1. 一个web服务器,如Tomcat
      2. 把代码发布到服务器的指定位置
      3. 启动服务
    2. SpringBoot的运行方式
      1. 以一个Java命令的形式运行服务
        1. java -jar xxxxx.jar
  2. 内嵌web服务器
    1. 内嵌了Tomcat
  3. 简化配置
  4. 提供准生产的应用监控

与微服务的关系

SpringBoot是Java开发微服务的润滑剂,让开发微服务的效率变高了。不是开发微服务的必须

SpringBoot的简化思路,贴合了微服务的理念

SpringCloud

目的:简化Java的分布式系统的通用性问题

  1. 多个服务的负载均衡
  2. 服务之间的调用
  3. 事务管理
  4. 统一的注册管理

理解:

  1. 一系列框架的集合
  2. 简化Java的分布式系统开发 - 利用了SpringBoot
  3. 用SpringBoot对一些轮子做的封装

与微服务的关系

专门来做微服务的,是Java的微服务解决方案

核心组件

Eureka:服务发现

发现模式:客户端发现

  1. Eureka Server:是一个注册中心,运行多个实例可以避免「单点」的问题,保证高可用
  2. Application Service:注册到Eureka且保持心跳,心跳停止会认为其不可用
  3. Application Client:通过Eureka Server查询获取服务的注册信息(IP PORT)
  4. Client和Service自己通信

Ribbon:客户端侧的负载均衡


  1. Edge Service:负责把各业务服务提供的数据串联起来,统一提供给客户端的服务(如景点信息、门票信息、景点评论等)
    1. 特点:
      1. 整合后端服务数据
      2. 离客户端最近
    2. 问题:
      1. Edge Service和API Gateway的区别?
        1. 答案见文章下方Zuul部分
  2. 请求通过ELB来到API Service
  3. API Service 通过Eureka的服务发现找到服务列表
  4. 根据RibbonClient提供的负载均衡策略,选择访问指定的服务
    1. 策略:Customer Hash
    2. 策略:Zone Aware RoundRobin
    3. 还提供了完善的配置:连接超时、重试、重试的算法等

Hystrix:断路器

场景:web服务调用了数据库服务,数据库出问题无法响应,导致客户端超时。用户发现没反应,会重复操作,导致请求成倍增长。即使数据库很快恢复,也会由于后面堆积的大量请求而再次压垮,服务很长时间无法恢复。

解决方案:

  1. 服务方不可用的时候,后续请求不会再次访问服务方了
  2. 服务不可用的时候,给用户一个更好的响应
    1. 如:对时效性不高的请求,从缓存中取出数据返回给用户

Zuul:APIGateway

作用:

  1. 对外提供RESTful API
  2. 提供路由服务
  3. 负载均衡
  4. 权限控制

  1. 客户端通过ELB接入云服务
  2. 请求到Zuul,Zuul对外提供统一的接口(服务路由功能)
    1. 对内请求:转发给了不同的Service
      1. Edge Service对外提供RESTful API,Zuul对这些API进行整合
      2. 如何转发请求到Edge Service:
        1. 情况一:整合SpringCloud家族的一个东东,通过服务的id访问到EdgeService,且是负载均衡德
        2. 情况二:不整合,单独使用Zuul,通过url映射的方式,找到对应微服务
          1. 如:某个url开头的请求,转发到对应微服务的地址上,地址就是Edge Service的地址


Spring Cloud Config:解决不同环境的配置问题(测试环境、开发环境、线上环境)

不同环境配置问题的解决方案们:

情景:两个环境 - 测试环境生产环境

原始方案:

  1. 代码从测试环境切到生产环境后,手动修改代码中的环境配置 - 问题:改动了代码可能产生Bug
  2. 排除文件的方式
  3. 代码层面写上,然后通过环境变量指定的方式