这其中一个显而易见的问题就是权限:如果我的数据被别人动了怎么办?

方案一:采用ZooKeeper支持的ACL digest方式,用户自己定义节点的权限

这种方案将zookeeper的acl和digest授权认证模式相结合。具体操作流程如下:

可以把这个访问授权过程看作是用户注册,系统给你一个密码,每次操作使用这个用户名(appName)和密码. 于是就可以对应有这样权限管理系统,专门是负责进行节点的创建申请:包含“申请私有节点”和“申请公有节点”。这样一来,节点的创建都是由这个权限管理系统来负责了,每次申请完后,系统都会返回给你的一个key,格式通常是“{appName}:{password}”,以后你的任何操作都要在zk session 中携带上这个key,这样就能进行权限控制。当然,用户自己通过zk客户端进行path的创建也是可以的,只是要求他们要使用授权方式来进行zk节点的创建。(注意,如果使用zkclient,请使用
https://github.com/nileader/zkclient )

整个权限控制流程的代码测试,如下图所示,点击查看大图:(测试代码在这里

  1. package org.I0Itec.zkclient;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import org.apache.zookeeper.WatchedEvent;
  5. import org.apache.zookeeper.Watcher;
  6. import org.apache.zookeeper.ZooDefs.Ids;
  7. import org.apache.zookeeper.data.ACL;
  8. /**
  9. * Description: ZooKeepre ACL权限控制 测试
  10. * @author nileader / nileader@gmail.com
  11. * @Date Feb 2, 2012
  12. */
  13. public class DemoAuth implements Watcher {
  14. final static String SERVER_LIST = “127.0.0.1:4711″;
  15. final static String PATH = “/yinshi_auth_test”;
  16. final static String PATH_DEL = “/yinshi_auth_test/will_be_del”;
  17. final static String authentication_type = “digest”;
  18. final static String correctAuthentication = “taokeeper:true”;
  19. final static String badAuthentication = “taokeeper:errorCode”;
  20. static ZkClient zkClient = null;
  21. public static void main( String[] args ) throws Exception {
  22. List< ACL > acls = new ArrayList< ACL >( 1 );
  23. for ( ACL ids_acl : Ids.CREATOR_ALL_ACL ) {
  24. acls.add( ids_acl );
  25. }
  26. try {
  27. zkClient = new ZkClient( SERVER_LIST, 50000);
  28. zkClient.addAuthInfo( authentication_type, correctAuthentication.getBytes() );
  29. } catch ( Exception e ) {
  30. // TODO Auto-generated catch block
  31. e.printStackTrace();
  32. }
  33. try {
  34. zkClient.createPersistent( PATH, acls, “init content” );
  35. System.out.println( “使用授权key:” + correctAuthentication + “创建节点:” + PATH + “, 初始内容是: init content” );
  36. } catch ( Exception e ) {
  37. e.printStackTrace();
  38. }
  39. try {
  40. zkClient.createPersistent( PATH_DEL, acls, “待删节点” );
  41. System.out.println( “使用授权key:” + correctAuthentication + “创建节点:” + PATH_DEL + “, 初始内容是: init content” );
  42. } catch ( Exception e ) {
  43. // TODO Auto-generated catch block
  44. e.printStackTrace();
  45. }
  46. // 获取数据
  47. getDataByNoAuthentication();
  48. getDataByBadAuthentication();
  49. getDataByCorrectAuthentication();
  50. // 更新数据
  51. updateDataByNoAuthentication();
  52. updateDataByBadAuthentication();
  53. updateDataByCorrectAuthentication();
  54. // 获取数据
  55. getDataByNoAuthentication();
  56. getDataByBadAuthentication();
  57. getDataByCorrectAuthentication();
  58. //删除数据
  59. deleteNodeByBadAuthentication();
  60. deleteNodeByNoAuthentication();
  61. deleteNodeByCorrectAuthentication();
  62. deleteParent();
  63. zkClient.close();
  64. }
  65. /** 获取数据:采用错误的密码 */
  66. static void getDataByBadAuthentication() {
  67. String prefix = “[使用错误的授权信息]“;
  68. try {
  69. System.out.println( prefix + “获取数据:” + PATH );
  70. zkClient = new ZkClient( SERVER_LIST, 50000);
  71. zkClient.addAuthInfo( authentication_type, badAuthentication.getBytes() );
  72. System.out.println( prefix + “成功获取数据:” + zkClient.readData( PATH ) );
  73. } catch ( Exception e ) {
  74. System.err.println( prefix + “获取数据失败,原因:” + e.getMessage() );
  75. }
  76. }
  77. /** 获取数据:不采用密码 */
  78. static void getDataByNoAuthentication() {
  79. String prefix = “[不使用任何授权信息]“;
  80. try {
  81. System.out.println( prefix + “获取数据:” + PATH );
  82. zkClient = new ZkClient( SERVER_LIST, 50000);
  83. System.out.println( prefix + “成功获取数据:” + zkClient.readData( PATH ) );
  84. } catch ( Exception e ) {
  85. System.err.println( prefix + “获取数据失败,原因:” + e.getMessage() );
  86. }
  87. }
  88. /** 采用正确的密码 */
  89. static void getDataByCorrectAuthentication() {
  90. String prefix = “[使用正确的授权信息]“;
  91. try {
  92. System.out.println( prefix + “获取数据:” + PATH );
  93. zkClient = new ZkClient( SERVER_LIST, 50000);
  94. zkClient.addAuthInfo( authentication_type, correctAuthentication.getBytes() );
  95. System.out.println( prefix + “成功获取数据:” + zkClient.readData( PATH ) );
  96. } catch ( Exception e ) {
  97. System.out.println( prefix + “获取数据失败,原因:” + e.getMessage() );
  98. }
  99. }
  100. /**
  101. * 更新数据:不采用密码
  102. */
  103. static void updateDataByNoAuthentication() {
  104. String prefix = “[不使用任何授权信息]“;
  105. System.out.println( prefix + “更新数据: ” + PATH );
  106. try {
  107. zkClient = new ZkClient( SERVER_LIST, 50000);
  108. if( zkClient.exists( PATH ) ){
  109. zkClient.writeData( PATH, prefix );
  110. System.out.println( prefix + “更新成功” );
  111. }
  112. } catch ( Exception e ) {
  113. System.err.println( prefix + “更新失败,原因是:” + e.getMessage() );
  114. }
  115. }
  116. /**
  117. * 更新数据:采用错误的密码
  118. */
  119. static void updateDataByBadAuthentication() {
  120. String prefix = “[使用错误的授权信息]“;
  121. System.out.println( prefix + “更新数据:” + PATH );
  122. try {
  123. zkClient = new ZkClient( SERVER_LIST, 50000);
  124. zkClient.addAuthInfo( authentication_type, badAuthentication.getBytes() );
  125. if( zkClient.exists( PATH ) ){
  126. zkClient.writeData( PATH, prefix );
  127. System.out.println( prefix + “更新成功” );
  128. }
  129. } catch ( Exception e ) {
  130. System.err.println( prefix + “更新失败,原因是:” + e.getMessage() );
  131. }
  132. }
  133. /**
  134. * 更新数据:采用正确的密码
  135. */
  136. static void updateDataByCorrectAuthentication() {
  137. String prefix = “[使用正确的授权信息]“;
  138. System.out.println( prefix + “更新数据:” + PATH );
  139. try {
  140. zkClient = new ZkClient( SERVER_LIST, 50000);
  141. zkClient.addAuthInfo( authentication_type, correctAuthentication.getBytes() );
  142. if( zkClient.exists( PATH ) ){
  143. zkClient.writeData( PATH, prefix );
  144. System.out.println( prefix + “更新成功” );
  145. }
  146. } catch ( Exception e ) {
  147. System.err.println( prefix + “更新失败,原因是:” + e.getMessage() );
  148. }
  149. }
  150. /**
  151. * 不使用密码 删除节点
  152. */
  153. static void deleteNodeByNoAuthentication() throws Exception {
  154. String prefix = “[不使用任何授权信息]“;
  155. try {
  156. System.out.println( prefix + “删除节点:” + PATH_DEL );
  157. zkClient = new ZkClient( SERVER_LIST, 50000);
  158. if( zkClient.exists( PATH_DEL ) ){
  159. zkClient.delete( PATH_DEL );
  160. System.out.println( prefix + “删除成功” );
  161. }
  162. } catch ( Exception e ) {
  163. System.err.println( prefix + “删除失败,原因是:” + e.getMessage() );
  164. }
  165. }
  166. /**
  167. * 采用错误的密码删除节点
  168. */
  169. static void deleteNodeByBadAuthentication() throws Exception {
  170. String prefix = “[使用错误的授权信息]“;
  171. try {
  172. System.out.println( prefix + “删除节点:” + PATH_DEL );
  173. zkClient = new ZkClient( SERVER_LIST, 50000);
  174. zkClient.addAuthInfo( authentication_type, badAuthentication.getBytes() );
  175. if( zkClient.exists( PATH_DEL ) ){
  176. zkClient.delete( PATH_DEL );
  177. System.out.println( prefix + “删除成功” );
  178. }
  179. } catch ( Exception e ) {
  180. System.err.println( prefix + “删除失败,原因是:” + e.getMessage() );
  181. }
  182. }
  183. /**
  184. * 使用正确的密码删除节点
  185. */
  186. static void deleteNodeByCorrectAuthentication() throws Exception {
  187. String prefix = “[使用正确的授权信息]“;
  188. try {
  189. System.out.println( prefix + “删除节点:” + PATH_DEL );
  190. zkClient = new ZkClient( SERVER_LIST, 50000);
  191. zkClient.addAuthInfo( authentication_type, correctAuthentication.getBytes() );
  192. if( zkClient.exists( PATH_DEL ) ){
  193. zkClient.delete( PATH_DEL );
  194. System.out.println( prefix + “删除成功” );
  195. }
  196. } catch ( Exception e ) {
  197. System.out.println( prefix + “删除失败,原因是:” + e.getMessage() );
  198. }
  199. }
  200. /**
  201. * 使用正确的密码删除节点
  202. */
  203. static void deleteParent() throws Exception {
  204. try {
  205. zkClient = new ZkClient( SERVER_LIST, 50000);
  206. zkClient.addAuthInfo( authentication_type, correctAuthentication.getBytes() );
  207. if( zkClient.exists( PATH ) ){
  208. zkClient.delete( PATH );
  209. }
  210. } catch ( Exception e ) {
  211. e.printStackTrace();
  212. }
  213. }
  214. @Override
  215. public void process( WatchedEvent event ) {
  216. // TODO Auto-generated method stub
  217. }
  218. }

方案二、对zookeeper的AuthenticationProvider进行扩展,和内部其它系统A打通,从系统A中获取一些信息来判断权限

这个方案大致是这样:

1. A系统上有一份IP和appName对应的数据本地。

2. 将这份数据在ZK服务器上缓存一份,并定时进行缓存更新。

3. 每次客户端对服务器发起请求的时候,获取客户端ip进行查询,判断是否有对应appName的权限。限制指定ip只能操作指定 /appName znode。

4. 其它容灾措施。

个人比较两个方案:

1.方案一较方案二,用户的掌控性大,无论线上,日常,测试都可以由应用开发人员自己决定开启/关闭权限。 (方案一的优势)

2.方案二较方案一,易用性强,用户的使用和无权限基本一致。 (方案二的优势)

3.方案一较方案二更为纯洁。因为我觉得zk本来就应该是一个底层组件,让他来依赖其它上层的另一个系统?权限的控制精度取决于系统A上信息的准确性。 (方案一的优势)

另外附上 方案一 有权限和无权限对比压测TPS情况

测试条件
:三台ZK服务器:8核 JDK 1.6.0-06 四台zk客户端机器:5核 JDK1.6.0-21

测试场景:800个发布者,对应800个path,每个path 3个订阅者,共2400个订阅者。发布者发布数据,通知订阅者。

结论:权限控制对zk的TPS有一定的影响,但是还是保持在较高的水准(1.3w+),如图(点击查看大图):

ZooKeeper 权限管理的更多相关文章

  1. Zookeeper权限管理与Quota管理

    Zookeeper的ACL机制和Quota机制网上资料较少,这里做一个总结,以供大家参考. 1 Zookeeper ACL ZooKeeper的权限管理亦即ACL控制功能通过Server.Client ...

  2. Android权限管理之RxPermission解决Android 6.0 适配问题

    前言: 上篇重点学习了Android 6.0的运行时权限,今天还是围绕着Android 6.0权限适配来总结学习,这里主要介绍一下我们公司解决Android 6.0权限适配的方案:RxJava+RxP ...

  3. Android权限管理之Android 6.0运行时权限及解决办法

    前言: 今天还是围绕着最近面试的一个热门话题Android 6.0权限适配来总结学习,其实Android 6.0权限适配我们公司是在今年5月份才开始做,算是比较晚的吧,不过现在Android 6.0以 ...

  4. Android权限管理之Permission权限机制及使用

    前言: 最近突然喜欢上一句诗:"宠辱不惊,看庭前花开花落:去留无意,望天空云卷云舒." 哈哈~,这个和今天的主题无关,最近只要不学习总觉得生活中少了点什么,所以想着围绕着最近面试过 ...

  5. SpringMVC+Shiro权限管理【转】

    1.权限的简单描述 2.实例表结构及内容及POJO 3.Shiro-pom.xml 4.Shiro-web.xml 5.Shiro-MyShiro-权限认证,登录认证层 6.Shiro-applica ...

  6. Android6.0运行时权限管理

    自从Android6.0发布以来,在权限上做出了很大的变动,不再是之前的只要在manifest设置就可以任意获取权限,而是更加的注重用户的隐私和体验,不会再强迫用户因拒绝不该拥有的权限而导致的无法安装 ...

  7. Oracle 表空间和用户权限管理

    一. 表空间 Oracle数据库包含逻辑结构和物理结构. 数据库的物理结构指的是构成数据库的一组操作系统文件. 数据库的逻辑结构是指描述数据组织方式的一组逻辑概念以及它们之间的关系. 表空间是数据库逻 ...

  8. [Django]用户权限学习系列之权限管理界面实现

    本系列前三章: http://www.cnblogs.com/CQ-LQJ/p/5604331.htmlPermission权限基本操作指令 http://www.cnblogs.com/CQ-LQJ ...

  9. [Django]用户权限学习系列之设计自有权限管理系统设计思路

    若在阅读本片文章遇到权限操作问题,请查看本系列的前两章! http://www.cnblogs.com/CQ-LQJ/p/5609690.html和http://www.cnblogs.com/CQ- ...

随机推荐

  1. 什么时候App委托会收到App进程被结束的消息

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们在Xcode建立的新项目后,在AppDelegate类会发 ...

  2. socket系列之socket服务端与客户端如何通信

    上面已经分别介绍了ServerSocket跟Socket的工作步骤,并且从应用层往系统底层剖析其运作原理,我们清楚了他们各自的一块,现在我们将把他们结合起来,看看他们是如何通信的,并详细讨论一下他们之 ...

  3. JAVA之旅(三十五)——完结篇,终于把JAVA写完了,真感概呐!

    JAVA之旅(三十五)--完结篇,终于把JAVA写完了,真感概呐! 这篇博文只是用来水经验的,写这个系列是因为我自己的java本身也不是特别好,所以重温了一下,但是手比较痒于是就写出了这三十多篇博客了 ...

  4. Ext JS 6开发实例(二) :使用CMD创建应用程序

    由于Ext JS 6将原来的Ext JS和Sencha Touch合并为一个框架,因而在使用CMD来创建应用程序前,需要考虑清楚你是要创建一个通用应用程序,还是仅仅只是针对桌面或移动设备的应用程序. ...

  5. iOS 图片裁剪与修改

    最近做的项目中需要上传头像,发表内容的时候也要涉及到图片上传,我直接用的原图上传,但是由于公司网络差,原图太大,老是加载好久好久,所以需要把原图裁剪或者修改分辨率之后再上传,找了好久,做了很多尝试才解 ...

  6. python上下文管理器ContextLib及with语句

    http://blog.csdn.net/pipisorry/article/details/50444736 with语句 with语句是从 Python 2.5 开始引入的一种与异常处理相关的功能 ...

  7. Hash冲突解决

    hash的冲突不可避免的 1.开放地址法 开放地执法有一个公式:Hi=(H(key)+di) MOD m i=1,2,-,k(k<=m-1) 其中,m为哈希表的表长.di 是产生冲突的时候的增量 ...

  8. 程序员修炼之道中所有tips总结

    1         关心你的技艺 如果你不在乎能否漂亮地开发出软件,你又为何要耗费生命去开发软件呢? 2         思考!你的工作 关掉自动驾驶仪,接管操作.不断地批评和评估你的工作. 3    ...

  9. 青年菜君与小农女送菜商业模式PK

    青年菜君与小农女送菜商业模式PK   对比项 青年菜君 小农女送菜 优势 劣势 开业 2014年3月3日 2013年9月 渠道 地铁捕获用户 写字楼配送 送货 来店面自取 送货到写字楼 菜君 1.减少 ...

  10. Linux IPC实践(13) --System V IPC综合实践

    实践:实现一个先进先出的共享内存shmfifo 使用消息队列即可实现消息的先进先出(FIFO), 但是使用共享内存实现消息的先进先出则更加快速; 我们首先完成C语言版本的shmfifo(基于过程调用) ...