从0开始学微服务(一) --- 2018年12月

1、微服务的发展

  单体应用(进程内部调用)--- RPC接口(远程方法调用)。将臃肿的单体应用拆分为细粒化的服务(项目)。随着敏捷开发、持续交付、DevOps 理论的发展和实践,以及基于Docker容器化技术的成熟,微服务的应用越来越广。

  举个例子,之前我们的项目是打包为war包部署,所有的代码在一个项目,如果有改动,则需要重新打包部署。 现在我们把一个项目拆分为了好几个子项目目,打包为jar包,各自部署,某一个子项目改动并不会影响其他项目的部署。

  这样提高了开发、测试、上线、运维的效率。

2、服务拆分的考虑

  1)、功能维度---将公共功能聚合为一个服务,这是横向拆分;

  2)、业务维度---业务和数据关系密切的放一起,纵向拆分;

  3)、人员聚类---某几个业务某几个人熟悉,就一起开发部署;

  4)、性能聚类---性能要求高的并发大和性能要求低的并发小,分为不同的服务。

3、微服务架构(很多是分布式、集群系统才会很明显的使用)

  1)、服务描述: 一般用的RESTful API 暴露接口。提供接口路径,入参,出参;

  2)、注册中心:常规的eureka和consul;

  3)、服务框架:接口调用之前还有几个问题---服务通信采用什么通信(HTTPS)、数据传输采用什么方式(同步或异步、单连接传输还是多路复用)、数据压缩采用什么格式(Json序列化或Java对象序列化);

  4)、服务监控:前后端或者后端与后端调用是否正常,指标收集---数据处理---数据展示。这个在小型项目中一般直接看后台日志,大型项目才有专门的监控。

  5)、服务追踪:主要用于服务追踪和故障定位,每一次调用接口记录一个requestId,向下调用再记录一个requestId...这样定位故障(没用过);

  6)、服务治理:单机故障(小型项目常遇到,这时候就要查看Log日志再解决)、单数据中心故障(人为挖断缆线等)、依赖服务不可用(被依赖的项目异常,可以做熔断机制)。

  这些组件,在分布式SOA架构中有类似相同功能的组件。

4、服务发现 - 注册中心

  注册中心是服务提供者和服务消费者之间的纽带。 服务提供者提供心跳给注册中间,表明服务提供者是否在运行。 当服务提供者增加/减少节点时,也通知注册中心,注册中心修改注册表,再提供给服务消费者。

  注册中心一般采用集群部署,保证高可用。但是又要保证数据的一致性,这就涉及到分布式事务等一系列的操作。

5、服务调用 - RPC调用

  1)、客户端(我理解的前端)和服务端(我理解的后端)如何建立连接:

    HTTP通信,"三次握手"来建立连接,"四次挥手"断开连接;

    Socket通信,前端和后端要对接,发送请求和响应请求。当连接发生异常时,通过链路存活检测到链接是否断开,断开就断链重试;

  2)、服务端的处理方式:BIO同步阻塞方式(客户端请求一次创建一个线程去处理...最后线程太多达到系统最大数直接挂掉)、NIO同步非阻塞方式(客户端请求,通过IO多路复用处理,可以为系统节省开销)、AIO异步非阻塞方式(客户端发送IO请求立即返回,等待服务端通知);

  3)、协议与数据序列化:协议契约通常包括消息头和消息体。为什么数据要序列化,因为数据的传输速度取决于网络带宽与数据大小,数据序列化后,数据变小,传输速度变快。 常见的序列化:Hsesian2.0支持Map、List数据类型,二进制PB序列化压缩比和速度都比Json快,适用于对性能和存储要求高的场景,Json性能比PB稍微差些,但是可读性好,适合提供给外接服务。

  序列化最主要的作用是数据编解码,适用于前后端的数据传输。

  推荐使用成熟的通信框架,例如netty。

6、服务监控

  监控可以从三个方面着手:
    1)、监控对象:用户端监控、接口监控(后端开发常用到)、资源监控、基础监控(CPU利用率、内存使用量、IO读写、带宽等);

    2)、监控指标:每秒请求数量QPS(一段时间请求数量,如果在高峰期,每秒请求数量的指标更具有代表性PV)、响应时间(主要是慢请求500ms的数量,越少越好)、错误率(顾名思义);

    3)、监控维度:全局监控、单机房监控、单机监控、时间监控、核心业务监控。

  监控系统的原理:

    1)、数据采集:服务主动上报(在代码里写逻辑,每次调用完接口将数据上报)、代理采集(在日志中采集需求的数据)。 采样率涉及到监控的准度和系统的性能,当系统空闲的时间加大采样率,系统并发高的时候减小采样率(提高系统性能);

    2)、数据传输:UDP传输(数据采集完和服务器建立连接,上传数据到数据处理单元)、kafka传输(数据采集完上传到Topic,数据处理单元去订阅)。 在传输的时候可以使用PB(protocol buffers)/Json个数传输;

    3)、数据处理:需要将数据聚合---接口维度聚合、机器维度聚合。可以用es数据库保存数据;

    4)、数据展示:可以用曲线图、饼状图、格子图展示数据。

7、服务追踪

  服务追踪的作用
    1)、快速定位bug或者错误,例如五层调用,请求到第三层的时候莫名挂了,就可以定位是第三层请求的时候出了问题;

    2)、优化系统瓶颈:服务追踪数据展示,可以用全局角度去定位是哪一块出现了系统的性能的瓶颈。然后做出对应的优化;

    3)、优化链路调用:服务追踪,可以很直观的从全局角度去看一个链路调用的各种依赖,有些依赖是否是有必要的,然后优化;

    4)、生成网络拓扑:根据链路调用,可以生成一个网络拓扑图像,可以直观的的反应了一个接口的调用路线,依赖,耗时等等。 也起到一个监控的作用。

  服务追踪原理:

    1)、每个请求有一个唯一标识traceId,在整个系统中也是唯一标识。所以一次请求生成的traceId可以在整个系统中看到调用了哪些接口服务;

    2)、每一层或同层调用的不同服务,都有一个spanId来区别。 向下一层就是在spanId值后面再添加值(修改值),同层就是spanId的值的尾数不一样。例如A调用B和C,B调用D。traceId=123,A服务的spanId=0,B的spanId=0.1,D的spanId=0.1.1,C的spanId=0.2,这样就可以迅速追踪到当前请求一共调了几层服务,一共调了多少次服务等数据。

  服务追踪实现:

  1)、数据埋点上报:通过CS.SR创建上下文、CR.SS归档上下文,将每个服务的埋点上报;

  2)、数据计算处理:实时数据处理、离线数据处理。不同的方式都有各自的插件、数据库;

  3)、数据展示:链路图(可以看到一个接口的总体情况,响应时间、模块、调用多少个系统,主要用来定位故障)、拓扑图(一个调用包含了哪些应用,它们之间的关系、以及QPS、耗时等)。

  服务追踪和数据监控的区别:

    服务追踪:从系统全局去看,是一个链路,一个traceId全局追踪,上下游依赖关系;

    数据监控:某节点的具体数据的采集、处理、展示、分析;

    排查bug和调优性能等,都是先从链路去定位bug等的位置。 定位后,再根据该节点的数据监控,查看该节点的日志、性能、资源、异常等。

8、微服务的治理手段

  微服务如果调用失败,原因可能是服务提供者宕机或线程退出,还可能是服务提供者、注册中心、服务消费者三者之间的某块网络问题。 

  针对于上述问题,有2种节点管理方法:

    1)、注册中心主动摘除服务提供者:服务提供者主动向注册中心汇报心跳(存活),把这次汇报心跳的世界与上一次汇报心跳的时间做对比,超过一定时间,就认为服务提供者失效,然后注册中心主动摘除该节点(服务提供者可能部署了集群,所以摘除了有问题的节点);

    2)、服务消费者摘除机制:第一个解决方法情况下,假如服务提供者与注册中心的网络出了问题,会导致所有的服务提供者全部被摘除。 所以可以在服务消费者调用服务提供者的时候,如果哪一个节点出现了问题,就摘除哪一个提供者的节点。

  一个服务提供者多是以集群存在,这就涉及到了负载均衡,涉及到了负载均衡的几种算法:

    1)、随机算法:顾名思义就是随机的去访问节点,最终访问数量大到一定程度的时候,发现请求到各个节点的数量占比差不多;

    2)、轮询算法:根据节点的权重,对服务节点轮询发送请求。性能好的服务器,将权重设置大一点,分发的请求多一点,性能达到最优;

    3)、最少活跃调用算法:在服务消费者端维护一个数字,调用某服务节点,改节点数字+1,返回了就数字-1。 性能好的服务器节点,处理快,活跃数低,所以请求很多分发到性能好的节点,性能达到最优;

    4)、一致性Hash算法:相同参数的请求总是发某一个服务器节点。当某个服务器节点宕机后,基于虚拟节点机制,平摊到其他节点,不会整体宕机。

  选择节点不止由负载均衡确定,还由路由规则确定,制定路由规则原因有2个

    1)、业务存在灰度发布的需求:更新了版本,要内测,允许部分人使用,则符合条件的部分人就可以访问新的节点;

    2)、多机房就近访问的需求:如果在全国部署了几个大机房,那么请求的话就最好就近访问。

  路由配置方式有2种

    1)、静态配置:在服务消费者本地存放路由规则,只有在修改服务消费者本地配置的路由规则后才能上线后生效。

    2)、动态配置:路由规则存放在注册中心,服务消费者定期去注册中心同步规则。 注册中心的路由规则改变,服务消费者去更新的时候也相应改变,从而实现动态更新。

  服务容错手段有以下几种

    1)、FailOver:失败自动切换。访问一个节点失败后访问下一个节点;

    2)、FailBack:失败通知。如果是读操作,失败了可以再一次发送请求,如果是非幂等性操作(插入等),则如果调用生效就不可以重新请求;

    3)、FailCache:失败缓存。请求失败后,隔一段时间重新对该节点发送请求;

    4)、FailFast:快速失败。请求失败后不再请求,直接打印错误日志。

  在幂等性(读)的情况下可以选择FailOver或者FailCache,在非幂等性操作下选择FailBack或者FailFast操作。

该文章只是笔记,记录的是我自己大概的总结。

如果想看完整的知识点,可以去 极客时间app 上找 从0开始学微服务 --- 阿忠伯 老师的课程。

链接:https://time.geekbang.org/column/115

原文地址:https://www.cnblogs.com/AlmostWasteTime/p/10167101.html