Zookeeper编程笔记



初识ZooKeeper,做一些记录。

ZooKeeper提供一个集中式服务,包括配置维护、服务命名、分布式同步、组管理。子服务常用于分布式应用。

 

ZooKeeper体系结构

ZooKeeper是开源的用于分布式应用的分布式协调服务。它公开了一组接口,分布式应用可在其基础上实现配置维护、数据同步、服务命名、组管理等上层服务。它采用了类似文件系统的目录树型结构的数据模型。协调服务难于处理,特别容易出错,比如条件竞争和死锁。ZooKeeper的动机是为了减轻分布式应用实现协调服务的负担。

zookeeper允许分布式应用通过共享的层次化名字空间进行相互协调。zookeeper在内存中维护数据,访问上具备高吞吐、低延迟的特点。zookeeper重视高性能、高可用、严格有序存取,因此,性能方面能够胜任大型分布式系统,可靠方面可屏蔽单点故障,严格有序存取确保客户端能够实现复杂的同步原语。

 

数据模型、层次化名字空间、节点

zookeeper名字空间由节点znode构成,其组织方式类似文件系统,其中各个节点相当于目录和文件,通过路径作为唯一标识。与文件系统不同的是,每个节点具有与之对应的数据内容,同时也可以具有子节点。zookeeper用于存储协调数据,如状态、配置、位置等信息,每个节点存储的数据量很小,KB级别(我理解是0~1024KB)。节点维护一个stat结构(包括数据变化的版本号、ACL变化、时间戳),以允许缓存验证与协调更新。每当节点数据内容改变,版本号会增长。客户端获取数据的同时也会获取数据版本号。节点的数据内容以原子方式读写,读操作读取全部内容,写操作替换全部内容。节点具有一个访问控制列表(Access Control List - ACL)来约束哪些人能执行哪些操作。zookeeper有一种节点叫做临时节点,临时节点仅在创建该节点的会话的存存活期间存在,会话结束,临时节点自动删除。

 

ZooKeeper组件

如下图所示,同一个zookeeper服务下的server有两种,一种是leader server,另一种是follower server。leader特殊之处在于它有决定权,具有Request Processor,在zookeeper整个服务下的每台server将复制各个组件。Replicated Database是包含了所有数据的内存数据库。读请求利用本地副本数据库进行处理。改变zookeeper服务状态的请求和写请求将按照一个协同协议执行。所有写请求(from client)将传递到leader,然后leader向所有follower发起提案,follower接收提案并表态,提案通过后执行。消息传输层负责在提案失败时更换leader和followers与leader之间的同步。

 

关于ZooKeeper Watches

zookeeper所有读操作(getData(),getChildren(),exists())具有设置watch的选项。
zookeeper watch的定义如下:watch事件是一次性触发器,当watch监视的数据发生变化时,通知设置了该watch的client,即watcher。

需要注意三点:

1.一次性触发器
client在一个节点上设置watch,随后节点内容改变,client将获取事件。当节点内容再次改变,client不会获取这个事件,除非它又执行了一次读操作并设置watch

2.发送至client,watch事件延迟
watch事件异步发送至观察者。比如说client执行一次写操作,节点数据内容发生变化,操作返回后,而watch事件可能还在发往client的路上。这种情况下,zookeeper提供有序保证:client不会得知数据变化,直到它获取watch事件。网络延迟或其他因素可能导致不同client在不同时刻获取watch事件和操作返回值。

3.设置watch的数据内容
涉及到节点改变的不同方式。比方说zookeeper维护两个watch列表:节点的数据watch和子节点watch。getData()和exists()设置了内容watch,getChildren()设置了子节点watch,操作返回的数据类型不同,前者是节点的内容,后者是节点的子节点列表。setData()触发内容watch,create()触发当前节点的"内容watch"和其父节点的"子节点watch",delete()同时触发"内容watch"和"子节点watch"(其子节点被全部删除),以及其父节点的"子节点watch"。说白了,对当前节点的操作,要考虑到对其父节点与子节点的影响。

watch在客户端所连接的服务端本地维护。watch的设置、维护、分发操作都很轻量级。当客户端连接到新的服务端,watch将被任一会话事件触发。与服务端断开连接时,不能获取watch事件。客户端重连后,之前注册的watch将被重新注册并在需要时触发。通常这一切透明地发生,用户不会察觉到。有一种情况watch可能丢失:之前对一个尚未建立的节点的设置了exists watch,如果断开期间该节点被建立或删除,那么此watch将丢失。

对于watch,zookeeper提供以下保证:
1.watch对于其他事件、watch、异步响应是有序的。zookeeper client library保证有序分发
2.客户端监视一个节点,总是先获取watch事件,再发现节点的数据变化。
3.watch事件的顺序对应于zookeeper服务所见的数据更新的顺序。

关于watch要记住的是:
1.watch是一次性触发的,如果获取一个watch事件并希望得到新变化的通知,需要重新设置watch
2.watch是一次性触发的并且在获取watch事件和设置新watch事件之间有延迟,所以不能可靠的观察到节点的每一次变化。要认识到这一点。
3.watch object只触发一次,比如,一个watch object被注册到同一个节点的getData()和exists(),节点被删除,仅对应于exists()的watch ojbect被调用
4.若与服务端断开连接,直到重连后才能获取watch事件。

 

ZooKeeper访问控制

zookeeper使用ACL(Access Control List)控制对节点的访问。ACL与Unix文件访问权限类似,采用权限位的形式控制节点的可操作类型,zookeeper没有拥有者和用户组的概念,使用ACL指定每个用户的访问权限。一个ACL只用于一个节点,注意不能用于该节点的子节点,即每个节点的访问权限由其自身的ACL决定。

每一个客户端连接在zookeeper内部有唯一的id,zookeeper将连接和id关联起来,客户端试图访问节点时,用id与节点ACL进行比对,以确定客户端的访问权限。

ACL由键值对构成,格式是(scheme:expression, perms)。expression内容格式特定于scheme。

ACL权限

 

ZooKeeper客户端开发

关于C开发,zookeeper提供了两个库:zookeeper_st(单线程库)与zookeeper_mt(多线程库)。zookeeper_st放弃了事件循环,可在事件驱动的应用程序中使用。而zookeeper_mt更加易用,与Java API类似,创建一个网络IO线程和一个事件分发线程,用来维护连接和执行回调。

在具体使用上,zookeeper_st仅提供了异步API与回调,用以集成至应用程序的事件循环。它只是为了支持pthread库不可用或不稳定的平台而存在,例如FreeBSD 4.x。除此以外的其他情况,应使用提供同步与异步两种API的zookeeper_mt。

采用zookeeper_mt库的zookeeper客户端使用了3个线程:
线程1是业务逻辑层,负责与用户直接交互,主要是zookeeper库提供的API
线程2是网络IO层,负责与zookeeper服务端的网络通信,包括发送业务逻辑层的API调用生成的请求数据、服务端的响应数据、服务端的watch事件数据
线程3是事件处理层,负责执行watch回调

 

 

 

 

 

 

Watch事件类型:

ZOO_CREATED_EVENT:节点创建事件,需要watch一个不存在的节点,当节点被创建时触发,此watch通过zoo_exists()设置
ZOO_DELETED_EVENT:节点删除事件,此watch通过zoo_exists()或zoo_get()设置
ZOO_CHANGED_EVENT:节点数据改变事件,此watch通过zoo_exists()或zoo_get()设置
ZOO_CHILD_EVENT:子节点列表改变事件,此watch通过zoo_get_children()或zoo_get_children2()设置
ZOO_SESSION_EVENT:会话失效事件,客户端与服务端断开或重连时触发
ZOO_NOTWATCHING_EVENT:watch移除事件,服务端出于某些原因不再为客户端watch节点时触发

watch事件与zookeeper读操作的对应关系图:

 

 

API:

 

复制代码
typedef void (*watcher_fn)(zhandle_t *zh, int type, int state, const char *path,void *watcherCtx);
watch回调函数,两种watch事件通知方式:
1.legacy:预先实现watch回调函数并将函数指针传入zookeeper_init,然后使用其他api设置watch
2.watcher object:一个函数指针和一个watcher上下文指针。watch触发时,两者结合调用。使用此类型,需使用'w'前缀api,如zoo_awexists、zoo_wget等

zhandle_t *zookeeper_init(const char *host, watcher_fn fn, int recv_timeout, const clientid_t *clientid, void *context, int flags);
创建与ZooKeeper服务端通信的句柄和对应于此句柄的会话。会话的创建过程是异步的,收到ZOO_CONNECTED_STATE状态事件后,确认会话成功建立。 

int zookeeper_close(zhandle_t *zh);
关闭句柄,释放资源。调用函数后,会话将不可用,函数返回前会将未发送完毕的请求发送完,所以可能会引起阻塞。
对一个句柄来说,这个方法只许调用一次,调用多次将产生不确定的结果。对于调用过此方法的句柄,其他句柄操作也将产生不确定的结果。

const clientid_t *zoo_client_id(zhandle_t *zh);
返回客户端会话id,仅在与服务端连接正常时有效

int zoo_recv_timeout(zhandle_t *zh);
返回会话超时时间,仅在于服务端连接正常时有效,该值在与服务器重连后可能改变

const void *zoo_get_context(zhandle_t *zh);
返回句柄上下文

void zoo_set_context(zhandle_t *zh, void *context);
设置句柄上下文

watcher_fn zoo_set_watcher(zhandle_t *zh,watcher_fn newFn);
设置watch回调,返回之前的watch回调

struct sockaddr* zookeeper_get_connected_host(zhandle_t *zh, struct sockaddr *addr, socklen_t *addr_len);
返回服务端的网络地址(sockaddr结构),仅在与服务端连接正常是有效

int zookeeper_interest(zhandle_t *zh, int *fd, int *interest, struct timeval *tv);
暂时不太理解,可能是返回zookeeper在监听某个fd的读或者写

int zookeeper_process(zhandle_t *zh, int events);
暂时不太理解,通知zookeeper监听的事件发生了

typedef void (*void_completion_t)(int rc, const void *data);
函数类型定义,异步调用或连接断开或连接超时执行的回调类型

typedef void (*stat_completion_t)(int rc, const struct Stat *stat, const void *data);
同上,有返回值

typedef void (*data_completion_t)(int rc, const char *value, int value_len, const struct Stat *stat, const void *data);
同上,返回详细数据

typedef void (*strings_completion_t)(int rc, const struct String_vector *strings, const void *data);
同上

typedef void (*strings_stat_completion_t)(int rc, const struct String_vector *strings, const struct Stat *stat, const void *data);
同上

typedef void (*string_completion_t)(int rc, const char *value, const void *data);
同上

typedef void (*acl_completion_t)(int rc, struct ACL_vector *acl, struct Stat *stat, const void *data);
同上

int zoo_state(zhandle_t *zh);
返回句柄状态

int zoo_acreate(zhandle_t *zh, const char *path, const char *value, int valuelen, const struct ACL_vector *acl, int flags, string_completion_t completion, const void *data); 
创建一个之前不存在的节点。如果设置ZOO_EPHEMERAL,客户端会话失效,节点将自动删除;如果设置ZOO_SEQUENCE,一个唯一的自动增加的序列号附加到路径名,序列号宽度是10个数字的宽度,不足用0填充

int zoo_adelete(zhandle_t *zh, const char *path, int version, void_completion_t completion, const void *data);
删除一个节点

int zoo_aexists(zhandle_t *zh, const char *path, int watch, stat_completion_t completion, const void *data);
检查一个节点是否存在

int zoo_awexists(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, stat_completion_t completion, const void *data);
检查一个节点是否存在,它允许指定一个watcher对象(一个函数指针watcher和对应的上下文watcherCtx),在watch解除时,此函数会调用,watcherCtx作为watcher的传入参数

int zoo_aget(zhandle_t *zh, const char *path, int watch, data_completion_t completion, const void *data);
获取节点数据(legacy方式)。completion是回调函数,其rc参数可能是以下参数:ZOK-完成,ZNONODE-节点不存在,ZNOAUTH-客户端无权限

int zoo_awget(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, data_completion_t completion, const void *data);
获取节点数据(watcher object方式)。

int zoo_aset(zhandle_t *zh, const char *path, const char *buffer, int buflen, int version, stat_completion_t completion, const void *data);
设置节点数据

int zoo_aget_children(zhandle_t *zh, const char *path, int watch, strings_completion_t completion, const void *data);
获取子节点列表(legacy)

int zoo_awget_children(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, strings_completion_t completion, const void *data);
获取子节点列表(watcher object)

int zoo_aget_children2(zhandle_t *zh, const char *path, int watch, strings_stat_completion_t completion, const void *data);
获取子节点列表,3.3.0版本加入(legacy)

int zoo_awget_children2(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, strings_stat_completion_t completion, const void *data);
获取子节点列表,3.3.0版本加入(watcher object)

int zoo_async(zhandle_t *zh, const char *path, string_completion_t completion, const void *data);
Flush leader channel. 暂时不明确

int zoo_aget_acl(zhandle_t *zh, const char *path, acl_completion_t completion, const void *data);
获取节点的ACL。ACL描述了操作该节点所需具备的条件,即哪些人(id)具备哪些权限后才允许对节点执行哪些操作。

int zoo_aset_acl(zhandle_t *zh, const char *path, int version, struct ACL_vector *acl, void_completion_t, const void *data);
设置节点的ACL

int zoo_amulti(zhandle_t *zh, int count, const zoo_op_t *ops, zoo_op_result_t *results, void_completion_t, const void *data);
以原子方式执行一系列操作

const char* zerror(int c);
返回错误信息

int zoo_add_auth(zhandle_t *zh, const char* scheme, const char* cert, int certLen, void_completion_t completion, const void *data);
为应用程序指定证书。调用此函数用于认证的证书。服务端用scheme指定的安全服务对客户端连接进行认证。
如果认证失败,将与服务端断开连接,watcher触发,状态码是ZOO_AUTH_FAILED_STATE

int is_unrecoverable(zhandle_t *zh);
检查zookeeper连接是否可恢复

void zoo_set_debug_level(ZooLogLevel logLevel);
设置调试级别

void zoo_set_log_stream(FILE* logStream);
设置用于记录日志的文件流。默认使用stderr。若logStream为NULL,则使用默认值stderr。

void zoo_deterministic_conn_order(int yesOrNo);
用于启用或停用quarum端点的随机化排序,通常仅在测试时使用。
如果非0,使得client连接到quarum端按照被初始化的顺序。
如果是0,zookeeper_init将变更端点顺序,使得client连接分布在更优的端点上。

int zoo_create(zhandle_t *zh, const char *path, const char *value, int valuelen, const struct ACL_vector *acl, int flags, char *path_buffer, int path_buffer_len);
同步建立节点

int zoo_delete(zhandle_t *zh, const char *path, int version);
同步删除节点

int zoo_exists(zhandle_t *zh, const char *path, int watch, struct Stat *stat);
同步检查节点是否存在

int zoo_wexists(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, struct Stat *stat);
同步检查节点是否存在(watcher object)

int zoo_get(zhandle_t *zh, const char *path, int watch, char *buffer, int* buffer_len, struct Stat *stat);
同步获取节点数据(legacy)

int zoo_wget(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, char *buffer, int* buffer_len, struct Stat *stat);
同步获取节点数据(watcher object)

int zoo_set(zhandle_t *zh, const char *path, const char *buffer, int buflen, int version);
同步设置节点数据

int zoo_set2(zhandle_t *zh, const char *path, const char *buffer, int buflen, int version, struct Stat *stat);
同步设置节点数据并返回当前节点的stat信息

int zoo_get_children(zhandle_t *zh, const char *path, int watch, struct String_vector *strings);
同步获取子节点列表(legacy)

int zoo_wget_children(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, struct String_vector *strings);
同步获取子节点列表(watcher object)

int zoo_get_children2(zhandle_t *zh, const char *path, int watch, struct String_vector *strings, struct Stat *stat);
同步获取子节点列表并返回当前节点的stat信息(legacy),3.3.0版本加入

int zoo_wget_children2(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, struct String_vector *strings, struct Stat *stat);
同步获取子节点列表并返回当前节点的stat信息(watcher object),3.3.0版本加入

int zoo_get_acl(zhandle_t *zh, const char *path, struct ACL_vector *acl, struct Stat *stat);
同步获取节点ACL

int zoo_set_acl(zhandle_t *zh, const char *path, int version, const struct ACL_vector *acl);
同步设置节点ACL

int zoo_multi(zhandle_t *zh, int count, const zoo_op_t *ops, zoo_op_result_t *results);
同步以原子方式执行一系列操作
复制代码


From http://www.cnblogs.com/caosiyang/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第一部分 Spark学习 6 第1章 Spark介绍 7 1.1 Spark简介与发展 7 1.2 Spark特点 7 1.3 Spark与Hadoop集成 7 1.4 Spark组件 8 第2章 Spark弹性分布数据集 9 2.1 弹性分布式数据集 9 2.2 MapReduce数据分享效率低 9 2.3 MapReduce进行迭代操作 9 2.4 MapReduce进行交互操作 10 2.5 Spark RDD数据分享 10 2.6 Spark RDD 迭代操作 10 2.7 Spark RDD交互操作 10 第3章 Spark安装 11 第4章 Spark CORE编程 13 4.1 Spark Shell 13 4.2 RDD Transformations 13 4.3 Actions 16 4.4 用RDD编程 17 4.5 UN-Persist存储 18 第5章 Spark调度与高级编程 20 5.1 Spark应用程序例子 20 5.2 Spark-submit语法 22 5.3 Spark变量 23 5.4 数字类型 RDD操作 23 第二部分 ZOOKEEPER学习 24 第6章 zookeeper介绍 25 6.1 zookeeper简介 25 6.2 分布式应用程序 25 6.3 Apache Zookeeper意味着什么? 26 第7章 zookeeper基本组成与工作流程 27 第8章 zookeeper的leader节点选择 31 第9章 zookeeper安装 33 第10章 zookeeper 命令行接口 35 第11章 zookeeper应用程序接口 39 第12章 zookeeper应用 40 第三部分 KAFKA学习 48 第12章 KAFKA介绍 49 12.1 KAFKA简介 49 12.2信息系统 49 12.3 KAFKA是什么? 50 第13章 KAFKA基本组成与集群架构 51 13.1 KAFKA的基本组成 51 13.2 KAFKA集群架构 52 第14章 KAFKA工作流程 53 14.1 PUB-SUB信息工作流 53 14.2 队列信息工作流/消费者组 53 14.3 Zookeeper在KAFKA中扮演的角色 54 第15章 KAFKA安装 55 第16章 KAFKA基本操作 56 16.1 启动zookeeper服务 56 16.2 单个单节点中间件配置 56 16.3 Topics列表 56 16.4 启动生产者发送信息 57 16.5 启动消费者接收信息 57 16.6 单个多节点中间件配置 57 16.7 创建一个topic 58 16.8 启动生产者发送信息 59 16.9 启动消费者接收信息 59 16.10 基本Topic操作 59 16.11 删除Topic 59 第17章 KAFKA 生产者与消费者群实例 60 17.1 生产者实例 60 17.2 简单消费者实例 63 17.3 消费者群例子 65 第18章 KAFKA与SPARK集成 67 18.1 Kafka与spark集成 67 18.2 SparkConf API 67 18.3 StreamingContext API 67 18.4 KafkaUtils API 67 18.5 建立脚本 69 18.6 编译/打包 69 18.7 提交到Spark 69 第四部分HIVE学习 70 第19章 HIVE介绍 71 19.1 HIVE是什么? 71 19.2 HIVE特点 71 19.3 HIVE架构 71 19.5 HIVE工作流 72 第20章 HIVE 安装 74 20.1 Hadoop安装 74 20.2 HIVE安装 77 20.3 Derby安装与设置 78 第21章 HIVE 数据类型 80 21.1列类型(Column Type) 80 21.2文本类型(Literals) 81 21.3 Null 值 81 21.4 复杂类型 81 第22章 数据库操作 82 22.1 创建数据库 82 22.2 删除数据库 82 第23章 数据表操作 83 23.1 创建数据表 83 23.2 load数据(插入数据) 85 23.3 修改数据表(Alter table) 86 23.4 删除表(Drop table) 90 第24章 分区 92 24.1 添加分区(Adding a Partition) 93 24.2 重命名分区(Renaming a Partition) 93 24.3 删除分区(Droping a Partition) 93 第25章 内置运算符 94 25.1 关系运算符 94 25.2 算术运算符 96 25.3 逻辑运算符 97 25.4 复杂运算符(Complex Operators) 97 第26章 内置函数 98 26.1 内置函数 98 26.2 聚合函数(Aggregate Functions) 99 第27章 视图与索引 100 27.1 创建视图(Creating a View) 100 27.2 删除视图(Dropping a View) 100 27.3 创建索引(Creating an Index) 101 27.4 删除索引(Dropping an Index) 101 第28章 HIVEQL 102 28.1 查询语句(SELECT ...WHERE) 102 28.1.1 查询语句实例 102 28.1.2 JDBC查询语句实例 102 28.2 查询语句(SELECT...ORDER BY) 103 28.2.1 ORDER BY查询语句实例 103 28.2.2 JDBC ORDER BY 查询语句实例 104 28.3 查询语句(GROUP BY) 104 28.3.1 GROUP BY查询语句实例 104 28.3.2 JDBC GROUP BY查询语句实例 105 28.4 查询语句(JOIN) 106 28.4.1 JOIN查询语句实例 106
抱歉,根据提供的引用内容,没有提到具体的ZooKeeper编程题。但是,我可以为您介绍一下ZooKeeper编程概念和用法。 ZooKeeper是一个分布式协调服务,它提供了一个可靠的、有序的、高性能的分布式系统基础设施。它主要用于解决分布式系统中的一致性问题,例如分布式锁、选举、配置管理等。 在ZooKeeper编程中,您可以使用ZooKeeper提供的API来创建、读取、更新和删除ZooKeeper节点。以下是一些常见的ZooKeeper编程任务: 1. 连接到ZooKeeper集群: ```java ZooKeeper zooKeeper = new ZooKeeper("localhost:2181", 5000, null); ``` 2. 创建一个ZooKeeper节点: ```java String path = "/myNode"; byte[] data = "Hello, ZooKeeper!".getBytes(); CreateMode mode = CreateMode.PERSISTENT; zooKeeper.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, mode); ``` 3. 读取一个ZooKeeper节点的数据: ```java String path = "/myNode";byte[] data = zooKeeper.getData(path, false, null); String dataStr = new String(data); System.out.println("Node data: " + dataStr); ``` 4. 更新一个ZooKeeper节点的数据: ```java String path = "/myNode"; byte[] newData = "New data".getBytes(); int version = zooKeeper.exists(path, false).getVersion(); Stat stat = zooKeeper.setData(path, newData, version); System.out.println("Node updated, new version: " + stat.getVersion()); ``` 5. 删除一个ZooKeeper节点: ```java String path = "/myNode"; int version = zooKeeper.exists(path, false).getVersion(); zooKeeper.delete(path, version); ``` 请注意,这只是ZooKeeper编程的一些基本示例。在实际应用中,您可能还需要使用ZooKeeper的监听器来监视节点的变化,并使用ZooKeeper提供的其他功能来实现更复杂的分布式系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值