快速上手
分布式协调中间件:
类似于多线程环境中通过并发包来协调线程的访问控制
主要解决分布式环境中各个服务进程的访问控制问题
数据结构
结构化存储
树中的每个节点Znode,维护stat状态信息,包括数据变化的时间和版本等
每个Znode可以设置一个value值,只是管理和协调有关的数据
每个节点的数据都允许读和写
节点的创建必须按照层级创建
/node/node1/node1-1
特性
Znode在被创建的时候,指定节点类型,分类
1.持久化节点:节点的数据会持久化到硬盘
2.临时节点:节点的生命周期和创建该节点的客户端生命周期保持一致
一旦客户端会话结束,则该客户端所创建的临时节点会被自动删除
3.有序节点:在创建的节点后面会增加一个递增序列,该序列的同一级父节点之下时唯一的
注意:持久化和临时节点也可以设置为有序节点:持久化有序节点,临时有序节点
4.容器节点:当容器节点下的最后一个子节点被删除时,容器节点就会自动删除
5.TTL节点:针对持久化和持久化有序节点,设置存活时间
存活时间内该节点没有任何修改并且没有任何子节点,
就会被自动删除
watcher机制
针对Znode订阅通知机制,
Znode节点状态发生变化,或者Zookeeper客户端连接状态发生变化
触发事件通知
在服务注册与发现中,对服务调用者及时感知打服务提供者的变化,提供解决方案
Java Api提供了3种机制来针对Znode进行注册监听
1.getData():获取指定节点value信息,并且可以注册监听
2.getChildren():获取指定节点的所有子节点,并且允许注册监听
3.exists():判断节点是否存在,并且允许注册监听
上述3种方法,当监听的节点进行创建,修改,删除操作时,触发相应的事件通知
存在问题:watcher事件的触发都是一次性的
例如,客户端通过getData(‘/node’,true),注册监听
/node节点数据发生修改,客户端会收到修改事件通知
但是/node再次发生变化时,客户端无法收到watcher事件
解决:客户端在收到事件的回调中,再次注册事件
常见应用场景分析
分布式锁
Synchronized或者Lock解决:多线程环境下,共享资源的数据安全问题,处理级别:线程级别
锁的本质:排他性,避免统一时刻多个进程同时访问某一个共享资源
Zookeeper实现分布式锁:临时节点,以及同级节点的唯一性
1.获得锁过程
所有客户端去zookeeper服务器上/Exclusive_locks节点下创建一个临时节点/lock
基于同节点的唯一性.保证所有客户端中只有一个客户端能创建成功,获得排他锁
没有锁的客户端需要通过watcher机制监听/Exclusive_Lock节点下的子节点变更事件
监听/lock节点的变化情况以作出反应
2.释放锁过程
获得锁的客户端因为异常断开了和服务端的连接,临时节特性,/lock节点会自动被删除
获得锁客户端执行完成业务逻辑之后,主动删除创建/lock节点
当/lock节点被删除之后,zookeeper服务器再次通知所有监听了/Exclusive_Locks子节点变化的客户端,客户端收到通知后,再次发起创建/lock节点的操作来获得排他锁
master选举
2种方式
1.同一级节点不能重复创建一个已经存在的节点(排他锁)
假设集群有3个节点,需要选举出master
3个节点同时去zookeeper服务器上创建一个临时节点:/master-election
只能有1个客户端创建成功,创建成功的客户端所在机器就成了master
没有创建成功的客户端,针对该节点注册watcher事件,监控当前master机器是否存活
master节点挂了(/master-election节点被删除)
其他客户端重新发起选举master
2.临时节点有序性实现
所有参与选举的客户端在zookeeper服务器的/master节点下创建一个临时有序节点
编号最小为master
后续节点监听前一个节点的删除事件
例如:
client02监听client01
client01被删除,client02会收到修改事件通知,在回调事件中注册client02
dubbo集成zookeeper实现服务注册
问题:
1.服务动态上下线感知:
服务调用者要感知到服务提供者上下线的变化
2.负载均衡:
当服务提供者是由多个节点组成的集群环境时,
服务调用者需要通过负载均衡算法,来动态选择一台目标服务器进行远程通信
步骤
服务提供者添加zookeeper相关依赖
org.apache.zookeeper zookeeper 3.5.3-beta org.apache.curator curator-framework 4.0.1 org.apache.curator curator-recipes 4.0.1
修改application.yml文件
修改dubbo.registry.address地址为zookeeper服务器地址
表示当前dubbo服务需要注册到zookeeper上
dubbo: application: name: springboot-dubbo-provider protocol: name: dubbo port: 20880 registry: address: zookeeper://your_ip:2181
注册中心实现原理
当dubbo服务启动时,会去zookeeper服务器上
/dubbo/com.zyl.provider.service.IProviderService/providers(发布服务接口全路径名称)
目录下创建当前服务URL,providers:服务提供者类型
dubbo://ip:port该服务发布的协议,访问地址
URL是临时节点
优点:注册该节点的服务器下线了,这个服务URL地址就会从zookeeper服务器上被移除
dubbo服务消费者启动:
/dubbo/com.zyl.provider.IPoroviderService/providers节点下的子节点注册Watcher监听
可以感知到服务提供方节点的上下线变化
在/dubbo/com.zyl.provider.IProviderService/consumers写入自己URL
可以在监控平台上看到某个dubbo服务正在被哪些服务调用
如果dubbo消费者需要调用IProviderService服务
会去/dubbo/com.zyl.provider.IProviderService/providers路径下获取
所有该服务的提供方URL列表, 通过负载均衡算法计算出一个地址进行远程访问
服务注册/动态感知,用到:临时节点,持久化节点,watcher机制
还可以针对不同情况实现以下功能
1.基于临时节点的特性,当服务提供者宕机,注册中心自动删除该服务提供者提供的信息
2.注册中心重启,dubbo自动恢复注册数据及订阅请求
3.为了保证节点安全性,zookeeper提供ACL权限控制
在dubbo中,可以通过dubbo.registery.username/password设置节点验证信息
4.注册中心默认根节点是/dubbo
如果需要针对不同环境 设置不同的根节点,
使用dubbo.registry.group修改根节点名称
实战dubbo spring cloud
实现服务提供方
创建2个模块:spring-cloud-dubbo-sample-api/spring-cloud-dubbo-smaple-provider
服务提供者,存在api声明,服务调用者需要访问服务提供者声明的接口
推荐: 将服务接口打包发到私服上
父工程pom.xml锁定版本
8 8 UTF-8 Greenwich.SR2 2.1.1.RELEASE 2.1.11.RELEASE org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import org.springframework.boot spring-boot-dependencies ${spring-boot.version} pom import com.alibaba.cloud spring-cloud-alibaba-dependencies ${spring-cloud-alibaba.version} pom import
spring-cloud-dubbo-sample-api声明接口,并发布到私服上
public interface IHelloService { String sayHello(String name); }
服务提供者spring-cloud-dubbo-smaple-provider添加依赖
org.springframework.cloud spring-cloud-starter com.alibaba.cloud spring-cloud-starter-dubbo com.zyl spring-cloud-dubbo-sample-api 1.0-SNAPSHOT org.springframework.cloud spring-cloud-starter-zookeeper-discovery
创建接口实现类
@Service public class IHelloServiceImpl implements IHelloService { @Value("${dubbo.application.name}") private String serverName; @Override public String sayHello(String name) { return "hello," + name + ", serverName:" + serverName; } }
application.yml配置dubbo相关信息
dubbo: cloud: subscribed-services: dubbo-provider spring: application: name: dubbo-consumer cloud: zookeeper: discovery: register: false connect-string: your-server:2181 server: port: 8081
在启动类声明@DubboComponentScan注解,启动服务
扫描注解所在包路径下@org.apache.dubbo.config.annotation.Service注解
,实现服务发布
@DubboComponentScan @SpringBootApplication public class DubboProviderApplication { public static void main(String[] args) { SpringApplication.run(DubboProviderApplication.class,args); } }
dubbo服务提供方
spring-cloud-sample-dubbo-consumer
pom.xml依赖
org.springframework.cloud spring-cloud-starter com.alibaba.cloud spring-cloud-starter-dubbo com.zyl spring-cloud-dubbo-sample-api 1.0-SNAPSHOT org.springframework.cloud spring-cloud-starter-zookeeper-discovery org.springframework.boot spring-boot-starter-web
application.yml添加dubbo配置信息
dubbo: cloud: subscribed-services: dubbo-provider spring: application: name: dubbo-consumer cloud: zookeeper: discovery: register: false connect-string: your-ip:2181 server: port: 8081
spring.cloud.zookeeper.discovery.register=false,服务不需要注册到zookeeper上
dubbo.cloud.subscribed-services:服务调用者订阅服务提供方应用名称
如果有多个应用名称,使用’,‘分开
不推荐使用默认值:’*’
消费dubbo服务提供者IHelloService服务
@RestController @RequestMapping("/consumer") public class IHelloServiceImpl { @Reference private IHelloService helloService; @GetMapping("/say") public String say() { return helloService.sayHello("zyl"); } }
启动springBoot服务
@SpringBootApplication public class DubboConsumerApplication { public static void main(String[] args) { SpringApplication.run(DubboConsumerApplication.class,args); } }
猜你喜欢
网友评论
- 搜索
- 最新文章
- 热门文章