分布式程序开发

手机应用

手机App (前台应用)
java管理程序 (后台应用)

后台应用拆分
用户应用,商品应用,订单应用,物流应用,评论应用 ==> 不同的应用部署在不同的机器上

不同的应用程序之间也需要相互调用

分布式应用程序如何相互调用?

  • http (HttpUrlConnection) 好处:调用简单,80一般不会被防火墙拦截 (短连接 - 用到时建立连接,用完了连接就断开)
  • RPC (remote 远程的 procedure 过程俗称方法 call调用)- tcp 长连接

1. RestTemplate (基于 Http 协议调用)

  • 服务端应用 (spring boot, 已经内嵌了tomcat 所以可以支持 http协议)
    服务器端的开发,就使用 之前的 springmvc的技术就可以完成,但注意数据格式一般采用 json,不需要使用网页了
  • 客户端应用
    使用java原生 api 完成调用
HttpURLConnection conn = (HttpURLConnection)
        new URL("http://localhost:8080/user").openConnection();

// 获取服务器返回的响应(以字节流方式表示)
InputStream in = conn.getInputStream();
InputStreamReader reader = new InputStreamReader(in, "utf-8");
BufferedReader r = new BufferedReader(reader);
// 从字符流读取数据
while(true) {
    String line = r.readLine();
    if(line == null) {
        break;
    }
// System.out.println(line);
    // 把 json 转为 java 对象, 客户端和服务器端的 User 类的定义必须要一样
    User user = om.readValue(line, User.class);
    System.out.println(user);
}

r.close();
conn.disconnect();

使用 spring 的 RestTemplate 工具类对刚才的调用进行简化

// get (查询), post (新增), put (修改), delete (删除)
RestTemplate template = new RestTemplate();
User user = template.getForObject("http://localhost:8080/user", User.class);
System.out.println(user);

Dubbo (RPC 框架)

阿里巴巴 -> apache

provider 服务提供者 用户服务 192.168.9.2
192.168.9.3
192.168.9.4
consumer 服务消费者
registry 注册中心 可以把提供者发生的一些变更,通知给服务消费者

服务提供者 启动后,会向注册中心 注册提供者信息(ip地址、服务名、方法定义)
服务消费者 启动后,会订阅服务信息
一旦服务提供者的信息发生了变更,注册中心负责把这些变更通知给 服务消费者
服务消费者 调用 服务提供者 的功能是直接调用,不经过注册中心

1. 注册中心

zookeeper (分布式的协调框架), 其中会存储 服务提供者 和 服务消费者 的相关信息

  1. 下载压缩包,解压
  2. 进入解压目录下 conf,把zoo_sample.cfg 改为 zoo.cfg
    zookeeper 默认端口号是 2181
  3. 进入解压目录 bin, 执行 zkServer.cmd 脚本

可以通过一个 ZooInspector 查看注册中心中存储了哪些信息

2. dubbo 控制台

可以以图形界面的方式查看 dubbo 提供者,消费者的信息

子项目-用springboot开发

  1. 下载源代码
    git clone https://github.com/apache/incubator-dubbo-ops
  2. 编译源代码(并跳过单元测试)
    命令行方式
    mvn -Dmaven.test.skip=true clean package

idea 打开项目 用右侧的maven 工具也可以实现打包

  1. 获得一个jar包,并运行
    java -jar dubbo-admin-server-0.1.jar --server.port=7070

3. 开发dubbo项目

  1. 开发公共api 项目
    公共类与接口的定义 UserService , User
    mvn install

  2. 开发 provider (提供者)
    pom.xml 中添加必要的依赖 spring-boot, dubbo, zookeeper, curator, 公共 api

// 把这个实现类 交给 dubbo 进行管理, dubbo 会把它的信息发布至注册中心 (服务导出)
@Service
public class UserServiceImpl implements UserService {
    @Override
    public void insert(User user) {
        System.out.println("dubbo insert, " + user);
    }

    @Override
    public void update(User user) {
        System.out.println("dubbo update, " + user);
    }

    @Override
    public User find(String name) {
        System.out.println("dubbo find, " + name);
        User user = new User();
        user.setAge(19);
        user.setSex("男");
        user.setName(name);
        return user;
    }
}

配置

# 配置端口
server.port=8080

# 应用程序的名字, 需要唯一, 不能和注册中心中其他程序冲突
spring.application.name=provider

# 注册中心
dubbo.registry.address=zookeeper://localhost:2181
# 设置连接注册中心的超时时间  3 分钟
dubbo.registry.timeout=180000

# 把元数据信息 发布至注册中心
dubbo.metadata-report.address=zookeeper://localhost:2181

# 指定 导出服务 的包名
dubbo.scan.base-packages=com.westos.provider
  1. 开发 服务消费者 consumer
@RestController
public class MyController {

    // 使用 公共的 api 接口把两者联系起来
    @Reference
    private UserService userService;

    @RequestMapping("/user")
    public User find() {
        return userService.find("李四");
    }
}

spring boot 配置

# 端口
server.port=9090

# 给消费者应用起一个唯一的名字
spring.application.name=xxx-consumer

# 注册中心地址
dubbo.registry.address=zookeeper://192.168.9.2:2181
dubbo.registry.timeout=180000

调用流程

  1. 浏览器中访问消费者 http://localhost:9090/user
  2. 根据此地址找到控制器方法,接下来要调用 userService
  3. 但userService 是一个接口,实现不在消费者这边
  4. dubbo 针对这个UserService接口生成了一个代理对象
  5. 代理对象
    • 代理对象会访问注册中心 把UserService服务的信息下载至本地
    • 这些服务信息会缓存在本地,后续的调用不会再依赖注册中心
    • 底层 netty nio 非阻塞io 跟服务提供者之间进行通信, tcp
      bio 阻塞io

dubbo 两个使用java语言的程序之间进行调用, 性能上, 字节, 服务应用程序之间,更适合长连接(规模小)
支持服务治理 (管理)
rest 任意语言,任意平台之间进行调用, 字符, 更适合短连接(规模大)

–server.port=xxx --dubbo.protocol.port=20881

4. dubbo 服务治理功能

入门 -> 示例

4.1 负载均衡

采用的默认算法是 1)

  1. random : 随机访问多个 provider中的一个
  2. roundrobin: 轮询算法 1, 2, 1, 2
    2ms 5ms
    dubbo 在轮询的基础上添加权重
  3. leastactive 根据访问的响应时间
  4. consistenthash 一致性 hash算法 – 让提供者的变动,尽量少的影响到消费者
    消费者 192.168.9.11 --> 11 % 3 = 2 ===> 2 提供者
    192.168.9.12 --> 12 % 3 = 0 ===> 0 提供者
    2 提供者