Dubbo框架知识点

2023-04-14 15:41:20 浏览数 (2)

介绍Dubbo框架知识点

  1. 什么是RPC?

RPC(Remote Procedure Call)是一种远程调用协议,它允许一个应用程序调用另外一个应用程序的服务,而无需手动编写网络通信和协议代码。

  1. 什么是RESTful?

RESTful是一种架构风格,一组架构约束条件和原则。通过RESTful风格,可以建立分布式系统和Web服务,这些系统可以通过Internet进行互操作。

  1. Dubbo官网

Dubbo是一款高性能,轻量级的开源Java RPC框架,是阿里巴巴SOA服务化治理方案的核心框架。官网地址:http://dubbo.apache.org/zh-cn/index.html

  1. 如何学习Dubbo

学习Dubbo应首先了解Java语言和Spring框架,对RPC和SOA也应有一定的了解。可以通过Dubbo官网提供的文档、示例和视频教程进行学习。另外,实践应用也是学习框架的重要方式。

  1. Dubbo学习路线

Dubbo学习路线应该包含以下几个方面:

  • RPC和SOA的基础概念和原理
  • Dubbo的核心概念和特性
  • 配置和使用Dubbo
  • Dubbo整合Spring框架
  • 与其他框架的整合
  • Dubbo的源码分析和深入调优
  1. Dubbo优点
  • 高性能、轻量级
  • 支持集群、容错、负载均衡等特性
  • 提供丰富的扩展点
  • 配置灵活、易于使用
  • 对Spring的支持友好
  1. Dubbo缺点
  • 对高并发的性能调优需要一定的经验和技巧
  • 社区活跃度相比其他框架有些不足
  • 对于初学习者而言,学习门槛有些高
  1. Dubbo应用实例

下面以Dubbo官方提供的示例为例,讲述Dubbo的应用实例:

Dubbo服务提供端代码:

代码语言:java复制
@Service(version = "1.0.0")
public class DemoServiceImpl implements DemoService {

public String sayHello(String name) {
return "Hello "   name;
}
}

Dubbo服务消费端代码:

代码语言:java复制
@RestController
public class DemoAction {

@Reference(version = "1.0.0")
private DemoService demoService;

@RequestMapping("/sayHello")
public String sayHello(String name) {
return demoService.sayHello(name);
}
}
  1. Dubbo集成Springboot

其中Springboot是一款基于Spring的开发框架,可以简化Spring应用的开发和部署等相关工作。Dubbo集成Springboot可以使得服务的管理变得简便,使开发人员更专注于业务逻辑的开发。

Dubbo集成Springboot的示例代码:

代码语言:java复制
@SpringBootApplication
public class DubboApplication {

public static void main(String[] args) {
SpringApplication.run(DubboApplication.class, args);
}

@DubboComponentScan({"com.example.dubboservice"})
public class ConsumerConfiguration {

@Bean
public ApplicationConfig applicationConfig() {
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("dubbo-consumer");
return applicationConfig;
}

@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://localhost:2181");
registryConfig.setClient("curator");
return registryConfig;
}

@Bean
public ConsumerConfig consumerConfig() {
ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setCheck(false);
return consumerConfig;
}

@Bean
public ReferenceConfig referenceConfig() {
ReferenceConfig referenceConfig = new ReferenceConfig();
referenceConfig.setInterface(DemoService.class);
referenceConfig.setVersion("1.0.0");
referenceConfig.setTimeout(3000);
return referenceConfig;
}
}
}

源码

Dubbo源码框架

Dubbo的源码框架大致如下:

其中必须掌握的内容包括:

  • container: Dubbo容器的实现
  • config: 加载和解析Dubbo配置文件
  • exception: Dubbo错误码规范和异常处理
  • filter: Dubbo中的过滤器实现
  • protocol: Dubbo协议的实现
  • registry: Dubbo注册中心的实现
  • rpc: Dubbo中的RPC框架和代理实现
  • serialize: Dubbo中网络传输所用到的序列化/反序列化实现

接下来介绍其中的几个核心模块。

  1. Rpc框架

Rpc框架提供了Dubbo的核心功能,属于Dubbo的基础部分。在Dubbo中,Rpc框架被设计为一个通讯抽象层。Dubbo中支持多种RPC框架,包括Dubbo自带的Netty框架、Hessian框架等。

下面展示一个使用Netty的Rpc框架的样例:

Dubbo中的RPC框架的实现。其中,服务提供方通过实现RpcServer接口,将服务注册到Dubbo容器中;服务消费方通过实现RpcClient接口,调用已注册的服务。该示例使用Netty框架实现了Rpc框架,Netty是一种基于NIO的客户端/服务器框架,以缓冲和异步的方式处理网络通讯,具有高并发和网络吞吐量的优势

代码语言:java复制
public interface RpcServer {

void start() throws Throwable;

void stop();

boolean isRunning();

void register(Object service, Class serviceClass);

int getPort();

String getHost();
}

public interface RpcClient {

Object invoke(String serviceName, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable;

void close();
}

public class NettyServer implements RpcServer {

@Override
public void start() throws Throwable {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast(new RdTxDecode())
.addLast(new RdTxEncoder())
.addLast(new RdTxServerHandler(handlerMap, serverConfig));
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);

ChannelFuture f = bootstrap.bind(serverConfig.getHost(), serverConfig.getPort()).sync();
channel = f.channel();
channel.closeFuture().sync();
}

@Override
public void register(Object service, Class serviceClass) {
handlerMap.put(serviceClass.getName(), service);
LOG.info("register service: {} success!", serviceClass.getSimpleName());
}

@Override
public int getPort() {
return ((InetSocketAddress) channel.localAddress()).getPort();
}

@Override
public void stop() {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}

public class RpcNettyClient implements RpcClient {

private final Bootstrap bootstrap;
private final String host;
private final int port;

@Override
public Object invoke(String serviceName, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable {
FullHttpRequest request = createRequest(serviceName, methodName, parameterTypes, arguments);
ChannelFuture f = bootstrap.connect(host, port).sync();
f.channel().writeAndFlush(request).sync();

DefaultFullHttpResponse response = (DefaultFullHttpResponse) rpcResponseFuture.get(5, TimeUnit.SECONDS);
String responseContent = getResponseContent(response);
if (response.status().code() == STATUS_OK) {
return JSON.parseObject(responseContent, RPCResult.class).getResult();
} else {
throw new RpcException(String.format("response err code: %s, %s", response.status().code(), responseContent));
}
}

@Override
public void close() {
workerGroup.shutdownGracefully();
}

private FullHttpRequest createRequest(String serviceName, String methodName, Class<?>[] parameterTypes, Object[] arguments) {
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, METHOD_POST, "/");
String body = JSON.toJSONString(new RPCInvocation(serializerType, serviceName, methodName, parameterTypes, arguments));
request.headers()
.set(HttpHeaderNames.CONTENT_TYPE, APPLICATION_JSON_VALUE)
.set(HttpHeaderNames.CONTENT_LENGTH, body.length())
.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);

request.content().writeCharSequence(body, CharsetUtil.UTF_8);
return request;
}
}
  1. Registry组件

Registry组件提供了服务注册和订阅功能,是实现Dubbo分布式存储服务的核心代码。

Registry组件通常会将Dubbo服务的注册信息写入到zookeeper或Redis等专门用于存储服务信息的存储引擎中。具体实现过程中,Registry组件可以创建zookeeper或Redis临时节点,以保证当提供服务节点出现故障时,Registry组件能及时的将故障服务下线,同时给客户端推播刷新服务节点的消息,拉取健康的节点列表。

Dubbo注册中心的实现,使用zookeeper作为服务注册和订阅的存储引擎。服务提供方在注册时将自己的服务地址信息存储在zookeeper上;服务消费方通过查询zookeeper获取到可用的服务节点信息,从而实现服务调用。该示例中的ZookeeperRegistry实现了RpcRegistry接口,包括服务注册和订阅两个方法。其中register方法将服务地址信息存储在zookeeper上;discover方法从zookeeper上查询指定服务的节点列表。在实际使用时,需要引入Dubbo的zookeeper依赖才能使用Dubbo的注册中心功能

下面给出一个使用zookeeper进行服务注册和订阅的示例代码:

代码语言:java复制
public interface RpcRegistry {

void register(String serviceName, String serviceAddress);

List<String> discover(String serviceName);
}

public class ZookeeperRegistry implements RpcRegistry, Watcher {

private ZooKeeper zooKeeper;

@Override
public void register(String serviceName, String serviceAddress) {
String servicePath = String.format("/%s/%s", RegistryConstants.ROOT_PATH, serviceName);
try {
if (zooKeeper.exists(servicePath, false) == null) {
zooKeeper.create(servicePath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
String addressPath = zooKeeper.create(String.format("%s/%s", servicePath, RegistryConstants.ADDRESS_PATH), serviceAddress.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
LOG.info("register service address: {} success!", addressPath);
} catch (Exception ex) {
LOG.error("register service address fail: {}", serviceName, ex);
}
}

@Override
public List<String> discover(String serviceName) {
String servicePath = String.format("/%s/%s", RegistryConstants.ROOT_PATH, serviceName);
try {
List<String> addressList = zooKeeper.getChildren(servicePath, true);
if (addressList.isEmpty()) {
LOG.warn("get no service: {}", serviceName);
return null;
}

List<String> resultList = new ArrayList<>();
for (String addressNode : addressList) {
byte[] addressData = zooKeeper.getData(String.format("%s/%s", servicePath, addressNode), true, null);
resultList.add(new String(addressData));
}
LOG.info("get service: {} success, address: {}", serviceName, resultList);
return resultList;
} catch (KeeperException | InterruptedException ex) {
LOG.error("get service fail: {}", serviceName, ex);
}
return null;
}

@Override
public void process(WatchedEvent event) {
LOG.info("Registry changed: {}", event.getState());
}
}

以上就是Dubbo框架的一些知识点的介绍,深入学习这些知识点对于我们理解Dubbo框架的应用和实践会有一定的帮助

0 人点赞