分布式:一个业务分拆多个子业务,部署在不同的服务器上
集群:同一个业务,部署在多个服务器上
一、Zookeeper入门
Zookeeper:是一个为分布式应用提供协调服务的Apache项目。
举例: 服务端将自身的状态信息存储到zookeeper上,然后客户端注册到ZK上,一单状态信息发生改变,通知ZK。
Zookeeper其实采用的是文件系统+监听机制
就是将一个集群作为一个Znode结点(类似linux文件系统的方式),集群中的各个结点就是这个Znode结点下的子结点 ,客户端来监听结点的变化做出相应的处理。
1、Zookeeper特点
1、ZK由一个Leader,多个Follower组成的集群。
2、在集群中只要有超过一半的结点存活,ZK就能正常工作。
3、每个结点上保存的数据副本都是一致的。
4、结点数据更新时具有原子性,同时失败或成功。
5、ZK更新数据很快,保证了实时性。
2、Zookeeper的数据结构
Znode结点类型:
持久型结点:客户端与服务器断开连接后,创建的结点不会删除
短暂型结点:客户端与服务器断开连接后,创建的结点自己删除
3、Zookeeper配置文件详解
tickTime=2000 #心跳时间
initLimit=10 #心跳帧 刚启动时Leader和Follower的通信最大时间=10*2s
syncLimit=5 #同步心跳帧 启动后的通信时间=5*2s
dataDir=/opt/software/apache-zookeeper-3.5.5-bin/zkData #ZK的数据存放地址,新安装时要指定
clientPort=2181 #客户端访问Server的端口号
二、Zookeeper的内部原理
1、ZK的半数机制
由于ZK需要半数以上结点存活,整个集群才能使用,所以ZK适合安装奇数台服务器。
2、ZK的选举机制
假设现在有5台服务器,超过半数选主,也就是大于2票为Leader
1.S1启动,投自己一票
2.S2启动,也投自己,S1发现没法选主,把票投给S2
3.S3启动,投自己一票,同理S1、S2投给S3,S3这时有3票,3>2,所以3为Leader
4.由于Leader已经存在,S4、S5启动时只能给自己投票
3、监听器原理
4、客户端写数据给服务端的流程
三、Dubbo
1、RPC的基本原理
Dubbo是一个Apache的Java RPC远程程序调用框架,说白了就是分布式架构中不同服务器上的应用之间进行程序的调用。**
RPC的核心内容包括两点:SOCKET通信、序列化反序列化操作
所以一个RPC框架牛不牛B。主要看SOCKET的通信速度和序列化反序列化的快慢。
2、Dubbo架构流程图
四、Dubbo案例详解
假设现在是一个Order服务想要去调用User的服务,然而他们分别部署在不同的服务器上,这时Order来远程调用User提供的服务。(Order = 消费者 User=提供者)
大致流程如下:
1、提供者注册到注册中心(ZK),暴露接口
2、消费者从注册中心订阅所需要的服务,并且消费者中要引入提供者的接口
3、消费者中实现
1、环境准备
Provider和Consumer都导入依赖
<!--引入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>
注意!Dubbo版本不同,ZK引入的依赖也有不同
<!--Dubbo 2.6版本后需要引入Zk的版本-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>2.12.0</version>
</dependency>
<!--Dubbo 2.6版本前需要引入Zk的版本-->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.11</version>
</dependency>
2、提供者准备
接口和实现类
//服务提供者
public interface UserService {
public String userInfo();
}
//实现类
public class UserServiceImpl implements UserService {
@Override
public String userInfo() {
return "user信息返回了。。。";
}
}
配置文件:
<?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"
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">
<!--提供者的信息,name要唯一-->
<dubbo:application name="user-provider"/>
<!--指定注册中心的地址-->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!--指定提供服务的协议名,通信的端口号 协议由提供方指定,消费方被动接受-->
<dubbo:protocol name="dubbo" port="20890"/>
<!--要暴露的服务接口-->
<dubbo:service interface="com.zgr.UserService" ref="UserService"/>
<!--注入提供者信息-->
<bean id="UserService" class="com.zgr.UserServiceImpl"/>
</beans>
启动类:
public class Provider {
public static void main(String[] args) throws IOException {
//启动IOC容器
ApplicationContext context = new ClassPathXmlApplicationContext("provider.xml");
context.start();
System.in.read(); // 按任意键退出
}
}
打开Dubbo监控中心发现 提供者注册了:
3、消费者准备
消费者中要引入提供者接口:
//服务消费者
public interface OrderService {
public void getProvider();
}
//实现类
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
UserService userService;
@Override
public void getProvider() {
System.out.println("去调用userService了 ...");
String info = userService.userInfo();
System.out.println(info);
}
}
配置文件:
<?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">
<!--注解扫描-->
<context:component-scan base-package="com.zgr"></context:component-scan>
<!-- 消费方应用名,不要与提供方一样 -->
<dubbo:application name="consumer-order" />
<!-- 注册中心服务地址 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 要调用的提供者接口,提供者那边必须暴露 -->
<dubbo:reference id="UserService" interface="com.zgr.UserService" />
</beans>
启动类:
public class Consumer {
public static void main(String[] args) throws IOException {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("consumer.xml");
OrderService orderService = applicationContext.getBean(OrderService.class);
orderService.getProvider();
System.out.println("调用结束了。。。");
System.in.read();
}
}
调用成功:
监控台也有消费者的信息: