RPC高级功能剖析
本质上是服务治理,以技术方案解决管理成本
服务熔断
当某服务出现不可用或响应超时情况时,为了防止整个系统出现雪崩,cosumer暂时停止对该服务的调用。服务不在继续向下调用。
服务降级
对业务进行降级,跳过异常调用,返回关键数据,确保服务可用。一种有损补偿行为。服务继续向下调用。
熔断和降级是两个不同的概念,由于在微服务中的场景下经常一起出现,导致部分人会以为熔断和降级是同一个事情。 熔断会触发服务降级,超时、异常等。
动态权重
对新的节点分配低权重,逐步提高权重
限流
通过限制调用方流量,达到对provider的保护的目的。
限流算法
- 计数器算法 按固定时间设置上限值 例如 1000次/10s,每10秒为单位间隔固定限流。
- 滑动窗口算法
按最近时间设置上限值,同样10s 为间隔 计数是固定的10秒(1-10,11-20),滑动是最近的10秒(2-12,5-15) - 漏斗算法 经过漏斗器将流量均匀达到服务提供方。将请求缓存在队列中,出队时取出固定请求交给线程池进行处理。每次出队后睡眠一个短暂时间。
- 令牌桶算法 生产线程每秒生成n个token放入(固定长度的)桶中,consumer每次调用都从桶中取出一个token以调用provider,当桶满时不在生成以限制调用速度。
主流RPC对比分析
如何对RPC框架进行选型,需要考虑什么注意点?
RPC选型考虑
- 计数团队语言
- RPC框架特性
- 框架成熟度
- 技术支持
- 社区活跃度
主流产品及其设计目标
- gRPC
- 由google开发,语言、平台中立,高性能开源框架
- 传输协议 HTTP/2
- 接口定义和序列化(ProtoBuf)
- 客户端寻址。本地配置,需要开发注册中心
- 支持 java、C++、Python、Go、Ruby、Nodejs、C#
- Dubbo
- 阿里巴巴开源高性能、透明化RPC调用方案,与spring无缝衔接。
- 传输协议&序列化,多种通讯协议面向不同的应用场景
- 支持java语言
- 扩展性 Dubbo SPI 机制
- 配套设施 自带注册中心、监控
- brpc
- 百度工业级RPC框架,上百万个实例(不包含client),目前开源C++版。
- 传输&序列化,多种通讯协议面向不同的应用场景
- 支持语言 java、C++
- 性能优于其他RPC产品
- Thrift
- 2007年由facebook开发的序列化方法和rpc框架,包含独特序列化格式和IDL,支持多语言.
- 传输&序列化,多协议支持
- 支持多语言,跨语言
面试题
Http1.0 Http1.1 Http2.0的区别? http 1.0 短连接,一次请求一次响应。css、js等静态资源都需要多次连接获取。 http 1.1 为了解决多次连接获取静态资源问题,增加了keep-alive支持,对连接进行复用继续请求。 http 2.0 将http 1.1的通信方式 半双工通信优化为了全双工通信。
Dubbo原理剖析
dubbo 是市面上广泛使用的开源产品,具备面向接口代理的高性能RPC调用、服务注册与发现、运行期流量管理、智能负载均衡和高度可扩展性。
Dubbo整体架构
Dubbo总体分为业务层、RPC层、Remote层。其中Service 和 Config 可以划分为 API层,其他的可以划分为SPI层
dubbo采用的分层设计,每一层的核心实现为上一层提供服务,分层设计实际上是一种插件化思维,这样每一层的实现都可以被替换。
Dubbo扩展点机制
Dubbo的扩展点加载机制使框架的接口和具体实现完全解耦,是框架可扩展行的基础。
- Dubbo扩展点
- Dubbo的SPI层所有接口都可以基于Dubbo框架做定制化的二次开发,对功能进行拓展。如负载均衡、序列化协议、注册中心等。
- Dubbo SPI扩展点加载机制
- Java SPI:Service Provider Interface 一个接口多种实现,通过配置确定使用哪个实现
- 制定接口规范,供外部扩展人员实现
- Dubbo SPI:Java SPI增强版,增加了对扩展点 IOC 和 AOP的支持。
- SPI注解可扩展
- 通过键值对配置
- 根据key指定扩展类
- Java SPI:Service Provider Interface 一个接口多种实现,通过配置确定使用哪个实现
负载均衡实现案例
@SPI 注解声明可扩展, RandomLoadBalance.NAME 作为key指定配置文件中的属性值扩,获取配置扩展类
@SPI(RandomLoadBalance.NAME)
public interface LoadBalance {
@Adaptive(loadbalance)
<T> Invoker<T> select(List<Invoke<T>> invokers, URL url, Invocation invocation) throw RpcException;
}
public class RandomLoadBalance extends AbstractLoadBalance {
public static final String NAME = "random";
}
SPI配置文件 META-INF/dubbo/org.apache.dubbo.rpc.cluster.LoadBalance
### 随机
random=com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance
### 轮询
roundrobin=com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
### 最少活跃度
leastactive=com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance
### 一致性hash
consistenthash=com.alibaba.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance
Dubbo扩展点特性
-
扩展点自动包装
Wrapper(包装)类,不是扩展点真正的实现,但是它持有真正的扩展点实现类。在扩展点上添加逻辑//实现Protocol public class ProtocolFilterWrapper implements Protocol { //声明实现的目标类作为成员变量 private final Protocol protocol; //通过构造方法注入目标类 public ProtocolFilterWrapper (Protocol protocol) {...} @Override public <T> Expoter<T> export(Invoker<T> invoker) throws RpcException { //AOP切面增强 if(REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) { return protocol.export(invoker); } return protocol.export(buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonContants.PROVIDER)); } @Override public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { if (REGISTRY_PROTOCOL.equals(url.getProtocol())) { return protocol.refer(type, url); } return buildInvokerChain(protocol.refer(type,url), REFERENCE_FILTER_KEY,CommonConstants.CONSUMER); } }@SPI("dubbo") public interface Protocol { int getDefaultPort(); @Adaptive <T> Exporter<T> export(Invoker<T> invoker) throws RpcException; @Adaptive <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException; void destory(); }META-INF
fliter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper mock=org.apache.dubbo.rpc.support.MockProtocol dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol多个包装类并不只生效一个,包装类内部使用最内层实现,不加载包装类AOP也不会失效。
-
扩展点自动装配
扩展点实现类的成员如果为其他扩展点类型,自动注入依赖.
这里有两个扩展点接口 分别为 CarMaker和WheelMaker
public interface CarMaker {
Car makeCar();
}
public interface WheelMaker {
Wheel makeWheel();
}
扩展点实现类
public class RaceCarMaker implements CarMaker {
//WheelMaker扩展点作为 CarMaker扩展点的成员变量,自动注入依赖
WheelMaker wheelMaker;
public setWheelMaker(WheelMaker wheelMaker) {
this.wheelMaker = wheelMaker;
}
public Car makeCar() {
Wheel wheel = wheelMaker.makeWheel();
return new RaceCar(wheel,...);
}
}
- 扩展点自适应 有些扩展并不想初始化时被加载,希望作用在扩展方法被调用时根据参数进行加载。
- 静态指定扩展点实现 @SPI
- SPI注解
- 配置
- 动态指定扩展点实现 @Adaptive
- 运行时决定
@SPI(RandomLoadBalance.NAME) // 静态默认指定random随机算法
public interface LoadBalance {
@Adaptive(loadbalance) //运行时可以根据@Adaptive的值或者url的参数修改为ruby轮询算法
<T> Invoker<T> select(List<Invoke<T>> invokers, URL url, Invocation invocation) throw RpcException;
}
- 扩展点自动激活 对于集合类扩展点,例如Filter,每个Filter实现不同的功能,需要多个同时激活,可以用自动激活来简化配置。
@Activate(group = Constants.PROVIDER, value = Constants.ACCESS_LOG_KEY)
public class AccessLogFilter implements Filter {
@Activate(group = {Constants.CONSUMER,Constants.PROVIDER}, value = Constants.CACHE_KEY)
public class CacheFilter implements Filter {
@Activate(group = Constants.PROVIDER, order = -30000)
public class ClassLoaderFilter implements Filter {
通过group分组,将相同实现放入链表结构中,通过order保证排序,实现自动激活