分布式程序开发
手机应用
手机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 (分布式的协调框架), 其中会存储 服务提供者 和 服务消费者 的相关信息
- 下载压缩包,解压
- 进入解压目录下 conf,把zoo_sample.cfg 改为 zoo.cfg
zookeeper 默认端口号是 2181 - 进入解压目录 bin, 执行 zkServer.cmd 脚本
可以通过一个 ZooInspector 查看注册中心中存储了哪些信息
2. dubbo 控制台
可以以图形界面的方式查看 dubbo 提供者,消费者的信息
子项目-用springboot开发
- 下载源代码 (先不做)
git clone https://github.com/apache/incubator-dubbo-ops - 编译源代码(并跳过单元测试) (先不做)
命令行方式
mvn -Dmaven.test.skip=true clean package
idea 打开项目 用右侧的maven 工具也可以实现打包
- 获得一个jar包,并运行
java -jar dubbo-admin-server-0.1.jar --server.port=7070
3. 开发dubbo项目
-
开发公共api 项目
公共类与接口的定义 UserService , User
mvn install -
开发 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
- 开发 服务消费者 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
调用流程
- 浏览器中访问消费者 http://localhost:9090/user
- 根据此地址找到控制器方法,接下来要调用 userService
- 但userService 是一个接口,实现不在消费者这边
- dubbo 针对这个UserService接口生成了一个代理对象
- 代理对象
- 代理对象会访问注册中心 把UserService服务的信息下载至本地
- 这些服务信息会缓存在本地,后续的调用不会再依赖注册中心
- 底层 netty nio 非阻塞io 跟服务提供者之间进行通信, tcp
bio 阻塞io
dubbo 两个使用java语言的程序之间进行调用, 性能上, 字节, 服务应用程序之间,更适合长连接(规模小)
支持服务治理 (管理)
rest 任意语言,任意平台之间进行调用, 字符, 更适合短连接(规模大)
4. dubbo 服务治理功能
入门 -> 示例
4.1 负载均衡
采用的默认算法是 1)
- random : 随机访问多个 provider中的一个
- roundrobin: 轮询算法 1, 2, 1, 2
2ms 5ms
dubbo 在轮询的基础上添加权重 - leastactive 根据访问的响应时间
- consistenthash 一致性 hash算法 – 让提供者的变动,尽量少的影响到消费者
消费者 192.168.9.11 --> 11 % 3 = 2 ===> 2 提供者
192.168.9.12 --> 12 % 3 = 0 ===> 0 提供者
2 提供者