目录
1.在官网下载apache-zookeeper-3.6.3-bin.tar
13.zookeeper的集群 leader follower observer
1.在官网下载apache-zookeeper-3.6.3-bin.tar
2.解压在linux中的data/zookeeper 下
3.cp zoo_sample.cfg zoo.cfg
4. vim zoo.cfg
4.set get的使用
5.关于ttl节点 我们需要去启动系统参数
- vim zkServer.sh
6.启动zookeeper 服务端
./bin/zkServer,sh start conf/zoo.cfg
7.启动zookeeper客户端
./bin/zkCli.sh
8.创建ttl节点(5秒后消失)
create -t 5000 /ttl-node
9.事件监听机制(只会生效一次)
节点监听get 【-s】 【-w】 path
这个 -w 就会对节点开启监听 当客户端这个节点发送变化,服务端会主动通给给我
目录监听 ls -w /xxx
对多个子节点进行监听 ls -R -w /test
10.removeWatches /xxx 移除监听
11.ACL
(1)digest密文授权
在create 的最后一个参数是ACL
下面这里生成的就是秘钥
注意:user1 和 pass1
create /zknode ddd digest : user1 : 秘钥 : rw(这里填的是权限信息)
此时再zget /znode 会报错 因为它不知道你是谁 只有user1才能对他访问
我们需要在访问前添加授权信息
addauth digest user1:pass1
(2)auth明文授权
addauth digest user1 : pass1
create /zknode2 xxx auth : user1 : pass1 : rw
(3) IP权限模式
create /zknode3 node3 ip : 192.168.109.130 : rw
设置只有ip为192.168.109.130的客户端连接才能进行ad
zookeeper数据结构
12.zookeeper在idea的使用
(1)导入包
(2)注意countdownlatch zookeeper 每次在get的时候,都会重新设置监听w
byte[] data = zooKeeper.getData("/myconfig", this, null);
这个this 指的就是watcher 因为watcher 只能用一次,所以每次改完后都需要重加入
package zookeeper.client;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.*;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@Slf4j
public class ConfigCenter {
private final static String CONNECT_STR="10.0.12.11:22";
//操作时间
private final static Integer SESSION_TIMEOUT=30*1000;
private static ZooKeeper zooKeeper=null;
private static CountDownLatch countDownLatch=new CountDownLatch(1);
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
//zookeeper的创建时线程异步的一件事情 需要contdownLatch
//为什么不能直接new zookeeper
//因为 sentThread 和 eventThead是守护线程
zooKeeper=new ZooKeeper(CONNECT_STR, SESSION_TIMEOUT, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getType()== Event.EventType.None
&& event.getState() == Event.KeeperState.SyncConnected){
log.info("连接已建立");
countDownLatch.countDown();
}
}
});
countDownLatch.await();
MyConfig myConfig = new MyConfig();
myConfig.setKey("anykey");
myConfig.setName("anyName");
//序列化工具
ObjectMapper objectMapper=new ObjectMapper();
//转换成字节
byte[] bytes = objectMapper.writeValueAsBytes(myConfig);
String s = zooKeeper.create("/myconfig", bytes, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
Watcher watcher = new Watcher() {
@SneakyThrows
@Override
public void process(WatchedEvent event) {
if (event.getType()== Event.EventType.NodeDataChanged
&& event.getPath()!=null && event.getPath().equals("/myconfig")){
log.info(" PATH:{} 发生了数据变化" ,event.getPath());
byte[] data = zooKeeper.getData("/myconfig", this, null);
MyConfig newConfig = objectMapper.readValue(new String(data), MyConfig.class);
log.info("数据发生变化: {}",newConfig);
}
}
};
byte[] data = zooKeeper.getData("/myconfig", watcher, null);
MyConfig originalMyConfig = objectMapper.readValue(new String(data), MyConfig.class);
log.info("原始数据: {}", originalMyConfig);
TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
}
}
13.zookeeper的集群 leader follower observer
1.首先创建4个文件夹 zk1 zk2 zk3 zk4
2.给他们加上唯一的表示 echo 1 > zk1/myid echo 2 > zk2/myid ……
3.修改配置文件 端口号 data 位置都要改
前一个2001 是我们自己定义的需要通信的端口
后一个3001 是我们自己定义的需要集群选举的端口
4.启动三个服务
14.zookeeper的分布式锁
我们如果使用nginx开启十个请求 通过jmeter来模拟,然后商品只有五个库存,十个请求每次拿一个。最终商品就会变成 -5; 此时我们就需要分布式锁
非公平锁
公平锁
- lockpath:路径
- InterProcessMutex 互斥锁
具体操作
1.创建curator 客户端
@Configuration
public class CuratorCfg {
@Bean(initMethod = "start")
public CuratorFramework curatorFramework(){
//两个参数的意思是 在失败后 等待1000ms 继续重试 最多重试三次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
//创建 curator客户端
CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.109.200:2181", retryPolicy);
return client;
}
}
2.进行加锁操作
@RestController
public class TestController {
@Autowired
private OrderService orderService;
@Value("${server.port}")
private String port;
//curator 客户端
@Autowired
CuratorFramework curatorFramework;
@PostMapping("/stock/deduct")
public Object reduceStock(Integer id) throws Exception {
InterProcessMutex interProcessMutex = new InterProcessMutex(curatorFramework, "/product_" + id);
try {
// ... 不加参数意味着 如果失败就会一直加锁
interProcessMutex.acquire();
orderService.reduceStock(id);
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw e;
}
}finally {
interProcessMutex.release();
}
return "ok:" + port;
}
}
ourPath = (String)((ACLBackgroundPathAndBytesable)client.create().creatingParentContainersIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL)).forPath(path, lockNodeBytes);
锁为什么要用容器节点?creatingParentContainersIfNeeded
因为容器的节点全都没了后,就会被自动删除,如果使用持久化节点,还需要自己去维护
CreateMode.EPHEMERAL_SEQUENTIAL 临时顺序节点
为什么用临时节点 和顺序节点
临时节点是为了解决羊群效应;顺序节点是为了公平锁的实现
共享锁
集群选举