Q&A-12 微服务
参考链接:
CAP 定理
参考链接:http://www.ruanyifeng.com/blog/2018/07/cap.html
image.png1998年,加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标。Eric Brewer 说,这三个指标不可能同时做到。这个结论就叫做 CAP 定理。
- Partition tolerance 分区容错
大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区(partition)。分区容错的意思是,区间通信可能失败。比如,一台服务器放在中国,另一台服务器放在美国,这就是两个区,它们之间可能无法通信。
一般来说,分区容错无法避免,因此可以认为 CAP 的 P 总是成立。CAP 定理告诉我们,剩下的 C 和 A 无法同时做到。
- Consistency 一致性
不同系统的数据保持一致。
- Availability 可用性
只要收到用户的请求,服务器就必须给出回应。
一致性和可用性:不可能同时成立
一致性和可用性,为什么不可能同时成立?答案很简单,因为可能通信失败(即出现分区容错)。
为什么要网关?
微服务下一个系统被拆分为多个服务,但是像 安全认证,流量控制,日志,监控等功能是每个服务都需要的,没有网关的话,我们就需要在每个服务中单独实现,这使得我们做了很多重复的事情并且没有一个全局的视图来统一管理这些功能。
综上:一般情况下,网关一般都会提供请求转发、安全认证(身份/权限认证)、流量控制、负载均衡、容灾、日志、监控这些功能。
上面介绍了这么多功能实际上网关主要做了一件事情:请求过滤 。权限校验、流量控制这些都可以通过过滤器实现,请求转发也是通过过滤器实现的。
你知道有哪些常见的网关系统?
我所了解的目前经常用到的开源 API 网关系统有:
Kong
Netflix zuul
限流的算法有哪些?
简单介绍 4 种非常好理解并且容易实现的限流算法!
- 固定窗口计数器算法
- 滑动窗口计数器算法
- 漏桶算法
- 令牌桶算法
下图的图片不是 Guide 哥自己画的哦!图片来源于 InfoQ 的一篇文章《分布式服务限流实战,已经为你排好坑了》。
固定窗口计数器算法
规定我们单位时间处理的请求数量。比如我们规定我们的一个接口一分钟只能访问10次的话。使用固定窗口计数器算法的话可以这样实现:给定一个变量counter来记录处理的请求数量,当1分钟之内处理一个请求之后counter+1,1分钟之内的如果counter=100的话,后续的请求就会被全部拒绝。等到 1分钟结束后,将counter回归成0,重新开始计数(ps:只要过了一个周期就讲counter回归成0)。
这种限流算法无法保证限流速率,因而无法保证突然激增的流量。比如我们限制一个接口一分钟只能访问10次的话,前半分钟一个请求没有接收,后半分钟接收了10个请求。
固定窗口计数器算法滑动窗口计数器算法
算的上是固定窗口计数器算法的升级版。滑动窗口计数器算法相比于固定窗口计数器算法的优化在于:它把时间以一定比例分片。例如我们的借口限流每分钟处理60个请求,我们可以把 1 分钟分为60个窗口。每隔1秒移动一次,每个窗口一秒只能处理 不大于 60(请求数)/60(窗口数) 的请求, 如果当前窗口的请求计数总和超过了限制的数量的话就不再处理其他请求。
很显然:当滑动窗口的格子划分的越多,滑动窗口的滚动就越平滑,限流的统计就会越精确。
滑动窗口计数器算法漏桶算法
我们可以把发请求的动作比作成注水到桶中,我们处理请求的过程可以比喻为漏桶漏水。我们往桶中以任意速率流入水,以一定速率流出水。当水超过桶流量则丢弃,因为桶容量是不变的,保证了整体的速率。如果想要实现这个算法的话也很简单,准备一个队列用来保存请求,然后我们定期从队列中拿请求来执行就好了。
漏桶算法令牌桶算法
令牌桶算法也比较简单。和漏桶算法算法一样,我们的主角还是桶(这限流算法和桶过不去啊)。不过现在桶里装的是令牌了,请求在被处理之前需要拿到一个令牌,请求处理完毕之后将这个令牌丢弃(删除)。我们根据限流大小,按照一定的速率往桶里添加令牌。
令牌桶算法为什么要分布式 id ?
这部分内容来自:分布式id生成方案总结
ID是数据的唯一标识,传统的做法是利用UUID和数据库的自增ID,在互联网企业中,大部分公司使用的都是Mysql,并且因为需要事务支持,所以通常会使用Innodb存储引擎,UUID太长以及无序,所以并不适合在Innodb中来作为主键,自增ID比较合适,但是随着公司的业务发展,数据量将越来越大,需要对数据进行分表,而分表后,每个表中的数据都会按自己的节奏进行自增,很有可能出现ID冲突。这时就需要一个单独的机制来负责生成唯一ID,生成出来的ID也可以叫做分布式ID,或全局ID。
分布式ID都有哪些生成方式?
-
UUID
优点:简单
缺点:字符串太长,没有规律,无序 -
单独的MySQL实例用来生成自增ID
优点:简单
缺点:单节点可能宕机 -
数据库集群模式
每个数据库实例设置不同的起始值和自增步长
优点:解决DB单点问题
缺点:不利于后续扩容 -
号段模式
号段模式是当下分布式ID生成器的主流实现方式之一,号段模式可以理解为从数据库批量的获取自增ID,每次从数据库取出一个号段范围,例如 (1,1000] 代表1000个ID,具体的业务服务将本号段,生成1~1000的自增ID并加载到内存。
等这批号段ID用完,再次向数据库申请新号段,对max_id字段做一次update操作,update max_id= max_id + step,update成功则说明新号段获取成功,新的号段范围是(max_id ,max_id +step]。
CREATE TABLE id_generator (
id int(10) NOT NULL,
max_id bigint(20) NOT NULL COMMENT '当前最大id',
step int(20) NOT NULL COMMENT '号段的布长',
biz_type int(20) NOT NULL COMMENT '业务类型',
version int(20) NOT NULL COMMENT '版本号',
PRIMARY KEY (`id`)
)
-
Redis
利用redis String的 incr命令实现ID的原子性自增。 -
雪花算法(SnowFlake)
twitter公司内部分布式项目采用的ID生成算法。 -
滴滴出品(TinyID)
-
百度 (Uidgenerator)
-
美团(Leaf)
了解RPC吗?
RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。比如两个不同的服务 A、B 部署在两台不同的机器上,那么服务 A 如果想要调用服务 B 中的某个方法该怎么办呢?使用 HTTP请求 当然可以,但是可能会比较慢而且一些优化做的并不好。 RPC 的出现就是为了解决这个问题。
RPC原理是什么?
我这里这是简单的提一下。详细内容可以查看下面这篇文章:
http://www.importnew.com/22003.html
为了能够帮助小伙伴们理解 RPC 原理,我们可以将整个 RPC的 核心功能看作是下面 5个部分实现的:
- 客户端(服务消费端) :调用远程方法的一端。
- 客户端 Stub(桩) : 这其实就是一代理类。代理类主要做的事情很简单,就是把你调用方法、类、方法参数等信息传递到服务端。
- 网络传输 : 网络传输就是你要把你调用的方法的信息比如说参数啊这些东西传输到服务端,然后服务端执行完之后再把返回结果通过网络传输给你传输回来。网络传输的实现方式有很多种比如最近基本的 Socket或者性能以及封装更加优秀的 Netty(推荐)。
- 服务端 Stub(桩) :这个桩就不是代理类了。我觉得理解为桩实际不太好,大家注意一下就好。这里的服务端 Stub 实际指的就是接收到客户端执行方法的请求后,去指定对应的方法然后返回结果给客户端的类。
- 服务端(服务提供端) :提供远程方法的一端。
- 服务消费方(client)调用以本地调用方式调用服务;
- client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
- client stub找到服务地址,并将消息发送到服务端;
- server stub收到消息后进行解码;
- server stub根据解码结果调用本地的服务;
- 本地服务执行并将结果返回给server stub;
- server stub将返回结果打包成消息并发送至消费方;
- client stub接收到消息,并进行解码;
- 服务消费方得到最终结果。
下面再贴一个网上的时序图:
RPC原理时序图有哪些常见的 RPC 框架?
- RMI(JDK自带): JDK自带的RPC。详细内容可以参考:从懵逼到恍然大悟之Java中RMI的使用
- Dubbo: Dubbo是 阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。详细内容可以参考:高性能优秀的服务框架-dubbo介绍
- gRPC: Google 公布的开源软件,基 HTTP 2.0 协议,并支持常见的众多编程语言。
- Thrift: Apache Thrift是Facebook开源的跨语言的RPC通信框架,目前已经捐献给Apache基金会管理,由于其跨语言特性和出色的性能,在很多互联网公司得到应用,有能力的公司甚至会基于thrift研发一套分布式服务框架,增加诸如服务注册、服务发现等功能。详细内容可以参考: 【Java】分布式RPC通信框架Apache Thrift 使用总结
- Hessian: Hessian是一个轻量级的remotingonhttp工具,使用简单的方法提供了RMI的功能。 相比WebService,Hessian更简单、快捷。采用的是二进制RPC协议,因为采用的是二进制协议,所以它很适合于发送二进制数据。详细内容可以参考: Hessian的使用以及理解
如果让你自己设计 RPC 框架你会如何设计?
一个典型的使用 RPC 的场景如下,一般情况下 RPC 框架不仅要提供服务发现功能,还要提供负载均衡、容错等功能,这个的 RPC 框架才算真正合格。
一个完整的RPC框架使用示意图简单说一下思路:
- 注册中心首先是要有的,推荐使用 Zookeeper。注册中心主要用来保存相关的信息比如远程方法的地址。
- 既然要要互相调用方法就要发请求,推荐nio 的 netty框架。
- 发请求发送什么数据呢?我们就要考虑序列化协议了。
- 另外,动态代理也是需要的。因为 RPC 的主要目的就是让我们调用远程方法像调用本地方法一样简单,使用动态代理屏蔽远程接口调用的细节比如网络传输。推荐一篇我觉得非常不错的动态代理的文章:《10分钟看懂动态代理设计模式》
- 负载均衡也是需要的。为啥?举个例子我们的系统中的某个服务的访问量特别大,我们将这个服务部署在了多台服务器上,当客户端发起请求的时候,多台服务器都可以处理这个请求。那么,如何正确选择处理该请求的服务器就很关键。假如,你就要一台服务器来处理该服务的请求,那该服务部署在多台服务器的意义就不复存在了。负载均衡就是为了避免单个服务器响应同一请求,容易造成服务器宕机、崩溃等问题,我们从负载均衡的这四个字就能明显感受到它的意义。。
了解Dubbo吗 ?
Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC 框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。简单来说 Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
Dubbo 目前已经有接近 31.2k 的 Star ,Dubbo的Github 地址:https://github.com/apache/incubator-dubbo 。
Dubbo 是由阿里开源,后来加入了 Apache 。正式由于 Dubbo 的出现,才使得国内越来越多的公司开始使用以及接受分布式架构。
Dubbo 提供了哪些负载均衡策略?
在集群负载均衡时,Dubbo 提供了多种均衡策略,默认为 random
随机调用。可以自行扩展负载均衡策略,参见:负载均衡扩展。
- Random LoadBalance(默认,基于权重的随机负载均衡机制)
- 随机,按权重设置随机概率。
- 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
- RoundRobin LoadBalance(不推荐,基于权重的轮询负载均衡机制)
- 轮循,按公约后的权重设置轮循比率。
- 存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
- LeastActive LoadBalance(最少活跃调用负载均衡机制)
- 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
- 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
- ConsistentHash LoadBalance(一致性 Hash负载均衡机制)
- 一致性 Hash,相同参数的请求总是发到同一提供者。(如果你需要的不是随机负载均衡,是要一类请求都到一个节点,那就走这个一致性hash策略。)
- 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
谈谈你对微服务领域的了解和认识
现在大公司都在用并且未来的趋势都是 Spring Cloud,而阿里开源的 Spring Cloud Alibaba 也是 Spring Cloud 规范的实现 。
我们通常把 Spring Cloud 理解为一系列开源组件的集合,但是 Spring Cloud并不是等同于 Spring Cloud Netflix 的 Ribbon(负载均衡)、Feign(远程调用)、Eureka(服务注册与发现,已经停止更新)、Hystrix(熔断)、Zuul (网关); 这一套组件,而是抽象了一套通用的开发模式。它的目的是通过抽象出这套通用的模式,让开发者更快更好地开发业务。但是这套开发模式运行时的实际载体,还是依赖于 RPC、网关、服务发现、配置管理、限流熔断、分布式链路跟踪等组件的具体实现。
更多关于 Spring Cloud Netflix 的内容参见: 大白话入门 Spring Cloud
Spring Cloud Alibaba 是官方认证的新一套 Spring Cloud 规范的实现,Spring Cloud Alibaba 是一套国产开源产品集合,后这对于国内的开发者是非常棒的一件事。阿里的这一举动势必会推动国内微服务技术的发展,因为在没有 Spring Cloud Alibaba 之前,我们的第一选择是 Spring Cloud Netflix,但是它们的文档都是英文的,出问题后排查也比较困难, 在国内并不是有特别多的人精通。Spring Cloud Alibaba 由阿里开源组件和阿里云产品组件两部分组成,其致力于提供微服务一站式解决方案,方便开发者通过 Spring Cloud 编程模型轻松开发微服务应用。
Spring Cloud Alibaba也是很值得学习的,其组成包括:
- Sentinel:轻量级的流量控制、熔断降级 Java 库
- 2.dubbo:Apache Dubbo 是一个基于 Java 的高性能开源 RPC 框架。
- nacos:Nacos 致力于帮助您发现、配置和管理微服务。
- seata:Seata 是一种易于使用,高性能,基于 Java 的开源分布式事务解决方案。
- RocketMQ:阿里巴巴开源的一款高性能、高吞吐量的分布式消息中间件。
Spring Cloud 和dubbo区别?
-
服务调用方式:dubbo是RPC;springcloud是Rest Api
-
注册中心:dubbo 是zookeeper;springcloud是eureka,也可以是zookeeper
-
服务网关:dubbo本身没有实现,只能通过其他第三方技术整合;springcloud有Zuul路由网关,作为路由服务器,进行消费者的请求分发,springcloud支持断路器,与git完美集成配置文件支持版本控制,事物总线实现配置文件的更新与服务自动装配等等一系列的微服务架构要素。
Spring Cloud 组成
- 注册中心:Eureka
- 网关:Zuul, Spring Cloud Gateway
- 负载均衡:Ribbon
Nginx是反向代理同时可以实现负载均衡,nginx拦截客户端请求采用负载均衡策略根据upstream配置进行转发,相当于请求通过nginx服务器进行转发。Ribbon是客户端负载均衡,从注册中心读取目标服务器信息,然后客户端采用轮询策略对服务直接访问,全程在客户端操作。 - 断路器:Hystrix
- Feign
SpringCloud调用接口方式:Feign,RestTemplate - Spring Cloud Bus
- 分布式配置中心:Spring Cloud Config