1、分布式基础
1.1 什么是分布式系统
分布式系统是若干独立计算机的集合,对于用户来说就像是一个相关系统。随着时代的发展,网站应用的规模不断扩大,常规的垂直应用架构已经无法应对,分布式服务架构和流动计算架构势在必行,但是将一个系统划分为若干个服务的话,如果服务的数量过多以及服务之间的依赖关系网太复杂的话,会在管理上造成很大的困难,这个时候急需一个治理系统确保架构有条不紊的演进。
1.2 架构演进
-
单一应用架构:当网站流量很小的时候,会选择将所用功能模块放在同一个应用内,而后打包部署到服务器上。
优点:部署节点少,节约成本。
缺点:扩展困难,需要重新打包和部署;不易于协同开发,所有人操作同一个应用,会相互干扰。
-
垂直应用架构:将原来的一个应用拆分为多个相互独立的应用,每个应用都包含各自的界面+业务逻辑+数据库。
优点:相比于单一应用架构来说,扩展容易,不会干扰到其它的应用;有利于协同开发,每个人对自己的负责的应用进行开发,而不会产生对他人的干扰。
缺点:每个应用都包含完整的界面+业务逻辑+数据库,耦合度太高,如果页面需要经常性修改的话,那不是动不动就要重新部署和发布;并且如果网站规模扩大,那么应用之间不可能完全独立。
-
分布式应用架构:分布式应用架构将模块之间、界面和业务逻辑之间分离了开来,节点与节点之间的相互调用称为远程过程调用(RPC),这个时候我们就需要一个良好的RPC服务框架来帮我们处理调用。
-
流动计算架构:随着服务的不断扩大,如何去协调各种各样的服务显得尤为重要。流动计算架构(SOA)用于解决服务的复杂问题,也叫做服务治理。
1.3 什么是RPC
所谓的RPC就是指远程过程调用,是一种技术思想,而不是规范。
基本原理
如上图所示,左边我们当作A服务,右边当作B服务,假设我们A要调用B的方法,那么我们可以通过这个client stub(将它当作一个小助手)和我们要使用的那端建立socket通信,对面那端的小助手会将我们的请求交给server functions处理,而后将响应结果交给我们这端的小助手,小助手再将结果交给我们。简单地说,就是我们需要通过某个中间商进行通信。
大体流程
Client将请求交给Client stub,它会对请求进行序列化,而后发送给server stub,server stub对消息进行反序列化后交由本地服务进行处理,处理后将结果进行序列化交给Client stub,Client stub将消息进行反序列化后交给Client。可以看出,决定这所谓的中间商(RPC框架)的优劣有两个条件:第一个是通信效率,第二个序列化和反序列化的效率。市面上有很多的RPC框架:比如dubbo、gRPC、Thrift、HSF。
2、Dubbo基本使用
2.1 什么是Dubbo
Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
2.2 dubbo的特性
- 面向接口的远程调用:也就是我们只需要对方的接口,然后调用接口方法即可,不需要知道它的实现细节。
- 负载均衡:是指对于同一个服务部署了多个服务器,每个服务器的访问量都被合理的控制在同一水平线上。
- 注册中心:假设我们的服务A需要调用服务B,服务B部署在多个服务器上,那么我们的RPC框架如何知道服务B在哪几台服务器上呢?这个注册中心就是用来将不同的服务以及它们所对应的服务器进行注册,相当于是一个清单,当进行服务调用的时候,dubbo就会去询问注册中心对方的服务在哪几台服务器上。除此之外dubbo还可以实时感知到有哪些服务器下线了,而后就会将它从我们的清单上去掉。
- 灰度发布:比如我们有100台服务器,当我们将服务从v1.0升级到v2.0时,不会将所有服务器上的服务都进行升级,会先选择一部分进行升级,如果运行稳定的话,则再升级一部分,循序渐进。
2.3 dubbo的架构
角色:
- Container:dubbo容器
- Provider:服务的提供者
- Registry:注册中心
- Consumer:服务的消费者
- Monitor:监控中心
分析:
0:dubbo容器启动
1:将提供者提供的服务自动注册到注册中心(比如zookeeper)
2:服务的消费者订阅服务
3:注册中心提醒消费者服务变更
4:消费者调用服务
5:消费者和服务者的状态会被监控中心汇总管理
2.4 搭建注册中心
我们这里选择使用Zookeeper作为注册中心,下载地址:https://zookeeper.apache.org/releases.html
下载完成后进行解压,而后进入bin目录下,在这个目录下打开cmd:敲入=>zkServer.cmd,打开服务端,可能会遇到如下问题:
可以看出:缺失了zoo.cfg
这个文件,我们去conf目录下查看
可以看到,没有这个文件,我们需要拷贝zoo_sample.cfg
文件,重命名为zoo.cfg
,并且打开这个文件,修改dataDir属性
dataDir=../data
这个是用来设置我们的数据的存储目录的,而后我们需要在根目录下新建一个data目录,然后便可以使用cmd打开服务端了。
服务端开启后,我们需要再开启客户端zkCli.cmd
,注意要新开一个cmd窗口:
- ls /:表示查看所有的节点
- create -e /hjj 123456:表示创建节点,
/hjj
是节点的名字,123456
是保存的值 - get /hjj:表示获得该节点的值
2.5 搭建管理控制台
搭建管理控制台,我们需要下载dubbo-admin:https://github.com/apache/dubbo-admin/tree/master,
下载后解压,进入dubbo-admin目录,打开cmd,输入:mvn clean package
(前提是已经装好了maven),进行打包操作。打包后会产生一个target目录,
该目录如下:
我们复制dubbo-admin-0.0.1-SNAPSHOT.jar
的名字,在此处打开cmd,输入:java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
会运行该jar。
注意:需要先将zookeeper的服务端打开! 运行后会看到如下界面:
我们打开浏览器,输入:192.168.197.1:7001
,需要我们输入用户名和密码,都是root,输入之后回车即可进入我们的管理控制台。
2.6 创建存放服务接口的工程
我们这里将服务接口和实体类单独放在一个工程中,而将具体实现放在服务提供者的工程。
具体如下:
1、创建一个maven工程;
2、编写相关实体类User和Order(订单依赖于用户的地址)。注意:实体类必须要序列化,前面说了,远程过程调用会将要发送的东西进行序列化再发送出去
public class User implements Serializable{
private Integer id;
private String name;
private Integer age;
private String address;
public class Order implements Serializable{
private String id;
private String name;//商品名称
private Double price;//商品价格
private Integer num;//商品数量
private String address;//用户地址
3、编写服务接口
public interface UserService {
/**
* 通过id查询用户信息
*/
public User getById(Integer id);
}
public interface OrderService {
//生成订单
void addOrder();
}
2.7 创建服务提供者的工程
步骤如下:
1、创建maven工程,导入下列依赖
<dependencies>
<!--导入服务接口,以做实现-->
<dependency>
<groupId>com.hzp</groupId>
<artifactId>interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--引入dubbo-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.2</version>
</dependency>
<!--引入操作zookeeper的客户端,因为我们要将服务注册到注册中心-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
</dependencies>
2、编写服务接口实现类(用户服务)
public class UserServiceImpl implements UserService {
private static Map<Integer,User> userMap;
//模拟数据库
static {
userMap = new HashMap<Integer, User>();
userMap.put(1, new User(1, "张三", 23, "江西"));
userMap.put(2, new User(2, "李四", 24, "北京"));
userMap.put(3, new User(3, "王舞", 25, "上海"));
}
//通过id查询用户
public User getById(Integer id) {
return userMap.get(id);
}
}
3、编写配置文件(注意,dubbo采用全spring配置方式,所以我们通过spring配置文件来配置)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!--指定服务/应用的名称-->
<dubbo:application name="dubbo_provider"/>
<!--指定注册中心(zookeeper)的位置,dubbo会自动注册我们的服务-->
<!--<dubbo:registry address="zookeeper://127.0.0.1:2181"></dubbo:registry>-->
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"></dubbo:registry>
<!--指定通信协议、端口,别的服务需要通过这个端口来调用本服务-->
<dubbo:protocol name="dubbo" port="20880"></dubbo:protocol>
<!--暴露服务,ref指定具体的实现-->
<dubbo:service interface="com.hzp.service.UserService" ref="userService"></dubbo:service>
<!--服务的具体实现-->
<bean id="userService" class="com.hzp.service.impl.UserServiceImpl"/>
</beans>
4、启动容器,容器会自动将我们的服务注册到注册中心,注意:执行main方法之前,需要打开我们的zookeeper的服务端,这样才能成功注册
public class MainApplication {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:provider.xml");
context.start();
System.in.read();
}
}
5、查看我们注册的服务。使用java -jar xxx
运行我们的管理控制台的那个jar包。
2.8 创建服务消费者的工程
1、创建maven工程,导入依赖
<dependencies>
<!--导入服务接口-->
<dependency>
<groupId>com.hzp</groupId>
<artifactId>interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--dubbo-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.2</version>
</dependency>
<!--操作zookeeper的客户端:订阅服务-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
</dependencies>
2、编写服务接口的实现类
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private UserService userService;
//模拟数据
public void addOrder() {
User user = userService.getById(1);
Order od = new Order("213847", "啤酒", 18.9, 2, user.getAddress());
System.out.println(od);
}
}
3、编写配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置应用的名字-->
<dubbo:application name="dubbo_consumer"></dubbo:application>
<!--配置注册中心的地址,到注册中心订阅服务-->
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"></dubbo:registry>
<!--配置要调用的服务接口-->
<dubbo:reference interface="com.hzp.service.UserService" id="userService"/>
<!--包扫描-->
<context:component-scan base-package="com.hzp.service"/>
</beans>
4、启动容器。注意:必须要先将服务提供者的服务打开
public class MainApplication {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:consumer.xml");
context.start();
OrderService orderService = context.getBean(OrderService.class);
orderService.addOrder();
System.in.read();
}
}
2.9 搭建监控中心
1、之前我们在github上下载了一个压缩包,找到里面的dubbo-monitor-simple
,进入该目录,打开cmd,敲入:mvn package
进行打包
2、打包完成后会有一个target目录,进入该目录,找到:dubbo-monitor-simple-2.0.0-assembly.tar.gz
,将其解压
3、解压后我们将解压后的文件夹放到一个文件路径不包含中文的路径下,要不然会报错
4、进入文件夹,找到assembly.bin下的start.bat,双击它,即可开启我们的监控中心,可能会报jetty端口被占用,我们需要修改配置文件dubbo.properties
,
该文件在conf目录下:
5、打开浏览器,输入:localhost:8899
即可进入我们的监控中心
6、在消费者和提供者的配置文件中配置连接监控中心,可以有两种配置方式:
-
从注册中心发现监控中心地址
<dubbo:monitor protocol="registry"></dubbo:monitor>
-
直连监控中心服务器地址
<dubbo:monitor address="127.0.0.1:8899"></dubbo:monitor>