微服务之 Dubbo+Zookeeper RPC 尝试

微服务之 Dubbo+Zookeeper RPC 尝试

在这里插入图片描述

一、单体应用和微服务

更好的解释:单体应用与微服务的比较

1. 单体应用架构

也就是所谓的 all in one ,将一个应用中的所有应用服务都封装在一个应用中。

例如一个系统,把数据库访问,web访问,等各个功能放到一个war包内。

若是开发一个不大的应用,单体应用架构总体上优于微服务架构。但是也有一些缺点,例如不够灵活、比微服务更高的耦合,团队开发效率不如微服务。

2. 微服务架构

将单体应用中的服务拆分出来,独立部署,各个模块独立开发,整个系统的耦合度降低,但也更为复杂,一个服务崩了,整个系统还会继续工作。

二、微服务架构解决方案以及分布式

微服务架构的四个问题:

  1. 客户端如何访问服务? api网关
  2. 服务之间如何进行通信? HTTP REST、RPC……
  3. 如何治理这些服务?Eureka、nacos、zookeeper……
  4. 服务挂了,如何解决?熔断机制、负载均衡……

解决这四个问题的方案就称为微服务的解决方案,如SpringCloud。

我们也可以自己组装一套解决方案,例如利用Dubbo进行服务间通信,利用zookeeper治理服务,用Flurry作为api网关,通过自带的服务降级来实现熔断机制,或是使用Hystrix 等组件。

分布式:

分布式服务顾名思义服务是分散部署在不同的机器上的,一个服务可能负责几个功能,是一种面向SOA架构的,服务之间也是通过rpc来交互或者是webservice来交互的。逻辑架构设计完后就该做物理架构设计,系统应用部署在超过一台服务器或虚拟机上,且各分开部署的部分彼此通过各种通讯协议交互信息,就可算作分布式部署,生产环境下的微服务肯定是分布式部署的,分布式部署的应用不一定是微服务架构的,比如集群部署,它是把相同应用复制到不同服务器上,但是逻辑功能上还是单体应用

得出结论: 微服务一定是分布式,分布式不一定是微服务。

接下来就用Dubbo+Zookeeper来体验一下阉割版微服务的hello world(体验一下RPC)。

三、Hello World

1. Dubbo架构

在这里插入图片描述

节点角色说明
节点角色说明
Provider暴露服务的服务提供方
Consumer调用远程服务的服务消费方
Registry服务注册与发现的注册中心
Monitor统计服务的调用次数和调用时间的监控中心
Container服务运行容器
调用关系说明
  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

2. zookeeper安装

直接到官网下载,3.5版本之后的下载带bin的版本。

https://dlcdn.apache.org/zookeeper/

需要修改配置文件/bin/zoo_sample.cfg

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper
clientPort=2181

注意端口就好。

将其重命名为zoo.cfg,双击运行bin目录下的zkServer.cmd。

3. Dubbo-Admin安装

下载:https://github.com/apache/dubbo-admin/tree/master

配置文件:dubbo-admin-server\src\main\resources\application.properties

需要添加一行:

server.port=7001

到dubbo-admin目录下:

打包:mvn clean package -Dmaven.test.skip=true

运行dubbo-admin-distribution/target/dubbo-admin-0.5.0.jar

java -jar ./dubbo-admin-distribution/target/dubbo-admin-0.5.0.jar

运行成功后,访问http://localhost:7001/即可登录监控后台,初始用户名密码皆为root。

在这里插入图片描述

4. SpringBoot + Dubbo + zookeeper

4.1 Provider

我们需要先创建一个服务。

新建项目,导入依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--Dubbo-->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>3.1.1</version>
    </dependency>

    <!--zookeeper客户端-->
    <dependency>
        <groupId>com.github.sgroschupf</groupId>
        <artifactId>zkclient</artifactId>
        <version>0.1</version>
    </dependency>
    <!-- 引入zookeeper -->
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-framework</artifactId>
        <version>5.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-x-discovery</artifactId>
        <version>5.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-recipes</artifactId>
        <version>5.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.8.0</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

写个服务:

接口:

public interface HelloService {
    String sayHello();
}

实现:

@Service
@DubboService
public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(String name) {
        System.out.println("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
        return "Hello " + name;
    }
}

@DubboService表示这个服务由Dubbo管理。

配置:

dubbo:
  registry:
    address: zookeeper://127.0.0.1:2181
  metadata-report:
    address: zookeeper://127.0.0.1:2181
  scan:
    # 服务所在的包
    base-packages: com/example/dubbozookeeper/Service/impl

  application:
    # 应用名称
    name: DubboZookeeper_Provider

  protocol:
    # 注册在Dubbo上的端口
    port: 20881
# 项目端口
server:
  port: 8001

启动。

此时在Dubbo-admin中可以看到该服务;

在这里插入图片描述

4.2 Consumer

写个服务消费者:

新建项目,导入依赖(和之前一样)。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--Dubbo-->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>3.1.1</version>
    </dependency>

    <!--zookeeper客户端-->
    <dependency>
        <groupId>com.github.sgroschupf</groupId>
        <artifactId>zkclient</artifactId>
        <version>0.1</version>
    </dependency>
    <!-- 引入zookeeper -->
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-framework</artifactId>
        <version>5.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-x-discovery</artifactId>
        <version>5.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-recipes</artifactId>
        <version>5.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.8.0</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

配置:

dubbo:
  registry:
    address: zookeeper://127.0.0.1:2181
  application:
    name: DubboZookeeper_Consumer

server:
  port: 8002

调用方式有两种,本地调用或是线上调用。

4.3 本地调用

本地调用简便方法:直接复制需要调用的接口,到该项目目录下。

例如:

我们之前将 DubboZookeeper\src\main\java\com\example\dubbozookeeper\service\HelloService.java 注册到Zookeeper里了,现在只需要复制该文件到:DubboZookeeperConsumer\src\main\java\com\example\dubbozookeeper\service\HelloService.java

com\example\dubbozookeeper\service\HelloService.java部分需要一致。也就是groupId一致。

通过@DubboReference注入

写测试试一试:

@SpringBootTest
class DubboZookeeperConsumerApplicationTests {
    @DubboReference
    HelloService helloService;

    @Test
    void contextLoads() {
        System.out.println(helloService.sayHello("Consumer"));
    }
}

运行:

在这里插入图片描述

并且可以在Provider中看到如下信息:

在这里插入图片描述

4.4 线上调用

直接上管理后台,找到服务的url:

在这里插入图片描述

写个单元测试:

@Test
void text() throws ClassNotFoundException, InvocationTargetException, IllegalAccessException {
    // 接口
    String serviceInterface = "com.example.dubbozookeeper.service.HelloService";
    // 要调用的方法
    String methodName = "sayHello";
    // 替换成自己dubbo服务ip
    String dubboURl = "dubbo://192.168.228.1:20881/com.example.dubbozookeeper.service.HelloService?anyhost=true&application=DubboZookeeper_Provider&background=false&deprecated=false&dubbo=2.0.2&dubbo.endpoints=[{\"port\":20881,\"protocol\":\"dubbo\"}]&dubbo.metadata-service.url-params={\"connections\":\"1\",\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"release\":\"3.1.1\",\"side\":\"provider\",\"port\":\"20881\",\"protocol\":\"dubbo\"}&dubbo.metadata.revision=5263d1a3ac03c713d3de72860c2dd4e0&dubbo.metadata.storage-type=local&dynamic=true&generic=false&interface=com.example.dubbozookeeper.service.HelloService&ispuserver=true&methods=sayHello&release=3.1.1&service-name-mapping=true&side=provider&timestamp=1666951237891";
	// 创建调用配置
    ReferenceConfig reference = new ReferenceConfig();
    Class<?> forName = Class.forName(serviceInterface);
    reference.setInterface(forName);
    reference.setUrl(dubboURl);
    // 获取dubbo服务链接
    Object object = reference.get();;
    // 找到指定方法
    Method[] methods = forName.getMethods();
    Method method = null;
    for (Method m : methods) {
        if (methodName.equals(m.getName())) {
            method =  m;
            break;
        }
    }
    // 指定方法,参数
    Object invokeResult = method.invoke(object, "consumer");
    // 调用结果
    System.out.println(JSON.toJSONString(invokeResult));
}

运行结果:

在这里插入图片描述

在Provider控制台中可以看到:

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值