如何理解RPC
通俗讲就是远程过程调用
RPC要求在调用方中放置被调用的方法的接口。调用方只要调用了这些接口,就相当于调用了被调用方的实际方法,十分易用。于是,调用方可以像调用内部接口一样调用远程的方法,而不用封装参数名和参数值等操作。
主要包含:
- 动态代理,封装调用细节
- 序列化与反序列化,数据传输与接收
- 通信,可以选择七层的http,四层的tcp/udp
- .异常处理等
- 首先,调用方调用的是接口,必须得为接口构造一个假的实现。显然,要使用动态代理。这样,调用方的调用就被动态代理接收到了。
- 第二,动态代理接收到调用后,应该想办法调用远程的实际实现。这包括下面几步:
- 识别具体要调用的远程方法的IP、端口
- 将调用方法的入参进行序列化
- 通过通信将请求发送到远程的方法中
这样,远程的服务就接收到了调用方的请求。它应该:
- 反序列化各个调用参数
- 定位到实际要调用的方法,然后输入参数,执行方法
- 按照调用的路径返回调用的结果
Dubbo是什么?能做什么?
Dubbo是阿里巴巴开源的基于Java的高性能RPC分布式服务框架,现已成为Apache基金会孵化项目。致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候,才有dubbo这样的分布式服务框架的需求,本质上是个远程服务调用的分布式框架。
核心部分包含
- 远程通讯:提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式,透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。
- .集群容错:提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
- 自动发现:基于注册中心目录服务,服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
简述dubbo的分层设计
- Service,业务层,就是咱们开发的业务逻辑层。
- Config,配置层,主要围绕ServiceConfig和ReferenceConfig,初始化配置信息。
- Proxy,代理层,服务提供者还是消费者都会生成一个代理类,使得服务接口透明化,代理层做远程调用和返回结果。
- Register,注册层,封装了服务注册和发现。
- Cluster,路由和集群容错层,负责选取具体调用的节点,处理特殊的调用要求和负责远程调用失败的容错措施。
- Monitor,监控层,负责监控统计调用时间和次数。
- Portocol,远程调用层,主要是封装RPC调用,主要负责管理Invoker。
- Exchange,信息交换层,用来封装请求响应模型,同步转异步。
- Transport,网络传输层,抽象了网络传输的统一接口,Netty、Mina等。
- Serialize,序列化层,将数据序列化成二进制流,以及反序列化。
图例如下:
能说下Dubbo的工作流程吗
- Start:启动Spring容器时,自动启动Dubbo的Provider
- Register: Dubbo的Provider在启动后会去注册中心注册内容.注册的内容包括:IP、端口、接口列表(接口类、方法)、版本、Provider的协议.
- Subscribe:订阅.当Consumer启动时,自动去Registry获取到所已注册的服务的信息.
- Notify:通知.当Provider的信息发生变化时,自动由Registry向Consumer推送通知.
- Invoke: Consumer调用Provider中方法
- 同步请求.消耗一定性能.但是必须是同步请求,因为需要接收调用方法后的结果
- Count:次数,每隔2分钟,Provoider和Consumer自动向Monitor发送访问次数.Monitor进行统计.
流程图如下:
image.png
Dubbo服务暴露过程
Dubbo采用URL的方式来作为约定的参数类型。
代码语言:javascript复制ubbo 采用 URL 的方式来作为约定的参数类型。
protocol://username:password@host:port/path?key=value&key=value
protocol:指的是 dubbo 中的各种协议,如:dubbo thrift http
username/password:用户名/密码
host/port:主机/端口
path:接口的名称
parameters:参数键值对
ServiceBean实现了ApplicationListener,监听ContextRefreshedEvent时间,在Spring IOC容器刷新完成后调用onApplicationEvent方法,服务暴露的启动点。根据配置得到URL,再利用Dubbo SPI机制根据URL的参数选择对应的实现类,实现扩展。
通过javassist动态封装服务实现类,统一暴露出Invoker使得调用方便、屏蔽底层实现细节,然后封装成exporter存储起来,等待消费者的调用,并且会将URL注册到注册中心,使得消费者可以获取服务提供者的信息。
一个服务如果有多个协议那么就都需要暴露,比如同时支持Dubbo协议和hessian协议,那么需要将这个服务用两种协议分别向多个注册中心(如果有多个的话)暴露注册。
- 检测配置,如果有些配置空的话会默认创建,并且组装成URL。
- 根据URL进行服务暴露、创建代理类invoker、根据URL得知具体的协议,根据Dubbo SPI选取实现类实现exporter。
- 如果只是本地暴露,将exporter存入ServiceConfig的缓存
- 远程暴露,先通过registry协议找到RegistryProtocol进行export,将URL中export=dubbo://...先转换成exporter,然后获取注册中心的相关配置,如果需要注册则向注册中心注册,并且在ProviderConsumerRegTable这个表格中记录服务提供者,其实就是往一个ConcurrentHashMap中将塞入invoker,key就是服务接口全限定名,value是一个set,set里面会存包装过的invoker,根据URL上Dubbo协议暴露出exporter,打开Server调用NettyServer来监听服务。
Dubbo服务引入过程
饿汉式是通过调用ReferenceBean的afterPropertiesSet方法时引入服务。
懒汉式是只有当这个服务被注入到其他类中时启动引入流程,也就是说用到了才会开始服务引入。默认使用懒汉式,如果需要使用饿汉式,可通过配置dubbo:reference的init属性开启。
ReferenceBean实现了FactoryBean接口,当对任意服务Interface进行自动注入或者getBean获取 时,就会触发**getObject()**函数的服务引用过程。
- 本地引入走injvm协议,到服务暴露的缓存中取exporter。
- 直连远程引入服务,测试的情况下用,不需要启动注册中心,由Consumer直接配置写死Provider的地址,然后直连即可。
- 注册中心引入远程服务,Consumer通过注册中心得知Provider的相关信息,然后进行服务的引 入。
获取注册中心实例,向注册中心注册自身,并订阅providers、configurators、routers节点,触发DubboInvoker的生成,cluster将多个服务调用者进行封装,返回一个invoker,
通过配置构建一个map,然后利用map来构建URL,再通过URL上的协议利用自适应扩展机制调用对应的protocol.refer得到相应的invoker。然后再构建代理,封装invoker返回服务引用,之后Comsumer调用这个代理类。
Dubbo支持的注册中心有哪些?
Zookeeper(官方推荐)
- 优点:支持分布式
- 缺点::受限于Zookeeper的特性
Multicast:
组播协议允许将一台主机发送的数据通过网络路由器和交换机复制到多个加入此组播的主机,是一种一对多的通讯方式。每一台服务提供方和服务消费方都可以看作是注册中心的一部分
- 优点:去中心化,不需要单独安装软件.
- 缺点:Provider和Consumer和Registry不能跨机房(路由)
不需要启动任何中心节点,只要广播地址一样,就可以互相发现,组播受网络结构限制,只适合小规模应用或开发阶段使用。
Redis
- 优点:支持集群,性能高
- 缺点:要求服务器时间同步.否则可能出现集群失败问题
Simple
- 优点:标准RPC服务.没有兼容问题
- 缺点:不支持集群