• Kafka与.net core(二)zookeeper


    1.zookeeper简单介绍

    1.1作用

    zookeeper的作用是存储kafka的服务器信息,topic信息,和cunsumer信息。如下图:

    而zookeeper是个什么东西呢?简单来说就是一个具有通知机制的文件系统,引用网路上的一张图

    可以看出来zookeeper是一个树形的文件结构,我们可以自定义node与node的值,并对node进行监视,当node的结构或者值变化时,我们可以收到通知。

    1.2node类型

    1)PERSISTENT-持久化目录节点
    客户端与zookeeper断开连接后,该节点依旧存在
    2)PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点
    客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号
    3)EPHEMERAL-临时目录节点
    客户端与zookeeper断开连接后,该节点被删除
    4)EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点
    客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号

    2.zookeeper命令操作

    连接zookeeper

    [root@iz2zei2y693gtrgwlibzlwz ~]# zkCli.sh -server ip:2181

    查看zookeeper的所有节点

    ls /

    查看某个节点的子节点

    ls /brokers

    创建节点

     create /testaa dataaaa

    获取节点的值

    get /testaa

    设置节点值

     set /testaa aaabbb

    删除节点

     delete /testaa

    这么看来实际上zookeeper跟数据库类似也是CURD操作,我们再来看看zookeeper的安全控制ACL

    3.zookeeper的ACL

    3.1ZK的节点有5种操作权限:

    CREATE、READ、WRITE、DELETE、ADMIN 也就是 增、删、改、查、管理权限,这5种权限简写为crwda(即:每个单词的首字符缩写)

    3.2身份的认证有4种方式:

    world:默认方式,相当于全世界都能访问
    auth:代表已经认证通过的用户(cli中可以通过addauth digest user:pwd 来添加当前上下文中的授权用户)
    digest:即用户名:密码这种方式认证,这也是业务系统中最常用的
    ip:使用Ip地址认证

    3.3ACL实例

    默认创建的时world方式,任何人都能访问,我们新建一个测试node节点
    [zk: 3:2181(CONNECTED) 11] create /cys cys

    访问一一下

    [zk: 3:2181(CONNECTED) 13] get /cys

    查看一下Acl

    [zk: 3:2181(CONNECTED) 15] getAcl /cys

    下面我们设置一下他的用户

     命令为:

    1)增加一个认证用户
    addauth digest 用户名:密码明文
    eg. addauth digest user1:password1
    2)设置权限
    setAcl /path auth:用户名:密码明文:权限
    eg. setAcl /test auth:user1:password1:cdrwa
    3)查看Acl设置
    getAcl /path

     具体操作如下:

    addauth digest cys:123456
    setAcl /cys auth:cys:123456:crwda

    我们ctrl+c退出zkCli,重新连接一下,然后查询

    get /cys

    结果如下:

    提示我们认证失败,我们登陆一下

    addauth digest cys:123456

    结果如下:

    我们在查看一下/cys节点的Acl

     

    可以看出来用户cys对应的密码(加密后的)和权限cdrwa

    4..net core 操作

    4.1新建server项目,引入ZookeeperNetEx这个nuget包

    Server端代码

    using org.apache.zookeeper;
    using org.apache.zookeeper.data;
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApp3
    {
        class Program
        {
            static void Main(string[] args)
            {
                while (true)
                {
                    Console.WriteLine("输入path");
                    var path = Console.ReadLine();
                    string address = "39.**.**.**:2181";
                    ZooKeeper _zooKeeper = new ZooKeeper(address, 1000 * 1000, null);
                    ZooKeeper.States states = _zooKeeper.getState();
                    //是否存在
                    Task<org.apache.zookeeper.data.Stat> stat = _zooKeeper.existsAsync(path);
                    stat.Wait();
                    if (stat.Result != null && stat.Status.ToString().ToLower() == "RanToCompletion".ToLower())
                    {
                        //已存在
                        Console.WriteLine($"{path}已存在");
                    }
                    else
                    {
                        Console.WriteLine("输入data");
                        var data = Console.ReadLine();
                        //创建
                        Task<string> task = _zooKeeper.createAsync(path, System.Text.Encoding.UTF8.GetBytes(data), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
                        task.Wait();
                        if (!string.IsNullOrEmpty(task.Result) && task.Status.ToString().ToLower() == "RanToCompletion".ToLower())
                        {
                            Console.WriteLine($"{path}创建成功");
                        }
                    }
                    Console.WriteLine("输入set data");
                    var dataA = Console.ReadLine();
                    //set值
                    Task<org.apache.zookeeper.data.Stat> statA = _zooKeeper.setDataAsync(path, System.Text.Encoding.UTF8.GetBytes(dataA));
                    statA.Wait();
                    if (statA.Result != null && statA.Status.ToString().ToLower() == "RanToCompletion".ToLower())
                    {
                        Console.WriteLine("set 成功");
                    }
    
                    Console.WriteLine("输入子path");
                    var childpath = Console.ReadLine();
         
                    Console.WriteLine("输入子data");
                    var childdata = Console.ReadLine();
                    Task<string> childtask = _zooKeeper.createAsync(childpath, System.Text.Encoding.UTF8.GetBytes(childdata), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
                    childtask.Wait();
                    if (!string.IsNullOrEmpty(childtask.Result) && childtask.Status.ToString().ToLower() == "RanToCompletion".ToLower())
                    {
                        Console.WriteLine($"{childpath}创建成功");
                    }
    
                    Console.ReadLine();
                    _zooKeeper.closeAsync().Wait();
                }
                ////删除
                //Console.WriteLine("输入delete path");
                //var pathB = Console.ReadLine();
                //Task taskA = _zooKeeper.deleteAsync(pathB);
                //taskA.Wait();
                //if (taskA.Status.ToString().ToLower() == "RanToCompletion".ToLower())
                //{
                //    Console.WriteLine("delete 成功");
                //}
    
                ////获取数据
                //Task<DataResult> dataResult = _zooKeeper.getDataAsync(path, new NodeWatcher());
                //dataResult.Wait();
                //if (dataResult.Result != null && dataResult.Status.ToString().ToLower() == "RanToCompletion".ToLower())
                //{
                //    Console.WriteLine(Encoding.UTF8.GetString(dataResult.Result.Data));
                //}
            }
        }
    
    }

    4.2新建client项目,引入ZookeeperNetEx这个nuget包

    客户端代码

    using org.apache.zookeeper;
    using org.apache.zookeeper.data;
    using System;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace Client
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("输入path");
                var path = Console.ReadLine();
                string address = "39.**.**.**:2181";
                ZooKeeper _zooKeeper = new ZooKeeper(address, 10 * 1000, new DefaultWatcher());
           //用户登陆 _zooKeeper.addAuthInfo(
    "digest", System.Text.Encoding.Default.GetBytes("cys:123456")); //获取child var getresult = _zooKeeper.getChildrenAsync(path, true); getresult.Wait(); //获取数据 Task<DataResult> dataResult = _zooKeeper.getDataAsync(path,true); dataResult.Wait(); Thread.Sleep(100000); } } public class DefaultWatcher : Watcher { internal static readonly Task CompletedTask = Task.FromResult(1);         /// <summary>         /// 接收通知         /// </summary>         /// <param name="event"></param>         /// <returns></returns>         public override Task process(WatchedEvent @event) { Console.WriteLine(string.Format("接收到ZooKeeper服务端的通知,State是:{0},EventType是:{1},Path是:{2}", @event.getState(), @event.get_Type(), @event.getPath() ?? string.Empty)); return CompletedTask; } } }

    这样当server端操作的时候,client端会通过watcher收到通知

  • 相关阅读:
    Linux
    Linux
    JavaScript
    JavaScript
    Linux
    不可不说的Java“锁”事
    RabbitMQ公共配置
    求一个数字的补码
    项目中Controller的全局异常处理类
    如何较方便给上百张数据库表添加表字段
  • 原文地址:https://www.cnblogs.com/chenyishi/p/10249731.html
Copyright © 2020-2023  润新知