天天看点

ZooKeeper权限控制

目前在公司内部使用zookeeper的地方越来越多,应用大多喜欢自己部署一套zk集群来使用。考虑到zk的高可用,并且一套zk集群至少3台机器, 那么每个应用,尤其是一些非核心应用都自己去部署一套的话,对资源利用率很低。另外,随着zk容灾的提出,单套zk集群使用的机器量会更大,运维人员开始 对这个情况担忧,强烈希望能够合并zk集群。

zk集群合并使用本身并没有太大的难度,问题在于应用方是否愿意大家共用一套zk集群,这其中一个显而易见的问题就是权限:如果我的数据被别人动了怎么办?

在公司不少牛人的帮助下,暂时得到两个权限方案,同时也希望大家提出自己的看法,共同进步。个人建议采用zookeeper acl的权限控制方式。

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

整个权限控制流程的代码测试:

<code>package org.i0itec.zkclient;</code> import java.util.arraylist; import java.util.list; import org.apache.zookeeper.watchedevent; import org.apache.zookeeper.watcher; import org.apache.zookeeper.zoodefs.ids; import org.apache.zookeeper.data.acl; /** description: zookeepre acl权限控制 测试 @author nileader / [email protected] @date feb 2, 2012 */ public class demoauth implements watcher { final static string server_list = “127.0.0.1:4711”; final static string path = “/yinshi_auth_test”; final static string path_del = “/yinshi_auth_test/will_be_del”; final static string authentication_type = “digest”; final static string correctauthentication = “taokeeper:true”; final static string badauthentication = “taokeeper:errorcode”; static zkclient zkclient = null; public static void main( string[] args ) throws exception { list&lt; acl &gt; acls = new arraylist&lt; acl &gt;( 1 ); for ( acl ids_acl : ids.creator_all_acl ) { acls.add( ids_acl ); } try { zkclient = new zkclient( server_list, 50000); zkclient.addauthinfo( authentication_type, correctauthentication.getbytes() ); } catch ( exception e ) { // todo auto-generated catch block e.printstacktrace(); zkclient.createpersistent( path, acls, “init content” ); system.out.println( “使用授权key:” + correctauthentication + “创建节点:” + path + “, 初始内容是: init content” ); zkclient.createpersistent( path_del, acls, “待删节点” ); system.out.println( “使用授权key:” + correctauthentication + “创建节点:” + path_del + “, 初始内容是: init content” ); // 获取数据 getdatabynoauthentication(); getdatabybadauthentication(); getdatabycorrectauthentication(); // 更新数据 updatedatabynoauthentication(); updatedatabybadauthentication(); updatedatabycorrectauthentication(); //删除数据 deletenodebybadauthentication(); deletenodebynoauthentication(); deletenodebycorrectauthentication(); deleteparent(); zkclient.close(); /* 获取数据:采用错误的密码 / static void getdatabybadauthentication() { string prefix = “[使用错误的授权信息]”; system.out.println( prefix + “获取数据:” + path ); zkclient.addauthinfo( authentication_type, badauthentication.getbytes() ); system.out.println( prefix + “成功获取数据:” + zkclient.readdata( path ) ); system.err.println( prefix + “获取数据失败,原因:” + e.getmessage() ); /* 获取数据:不采用密码 / static void getdatabynoauthentication() { string prefix = “[不使用任何授权信息]”; /* 采用正确的密码 / static void getdatabycorrectauthentication() { string prefix = “[使用正确的授权信息]”; system.out.println( prefix + “获取数据失败,原因:” + e.getmessage() ); 更新数据:不采用密码 static void updatedatabynoauthentication() { system.out.println( prefix + “更新数据: “ + path ); if( zkclient.exists( path ) ){ zkclient.writedata( path, prefix ); system.out.println( prefix + “更新成功” ); system.err.println( prefix + “更新失败,原因是:” + e.getmessage() ); 更新数据:采用错误的密码 static void updatedatabybadauthentication() { system.out.println( prefix + “更新数据:” + path ); 更新数据:采用正确的密码 static void updatedatabycorrectauthentication() { 不使用密码 删除节点 static void deletenodebynoauthentication() throws exception { system.out.println( prefix + “删除节点:” + path_del ); if( zkclient.exists( path_del ) ){ zkclient.delete( path_del ); system.out.println( prefix + “删除成功” ); system.err.println( prefix + “删除失败,原因是:” + e.getmessage() ); 采用错误的密码删除节点 static void deletenodebybadauthentication() throws exception { 使用正确的密码删除节点 static void deletenodebycorrectauthentication() throws exception { system.out.println( prefix + “删除失败,原因是:” + e.getmessage() ); static void deleteparent() throws exception { zkclient.delete( path ); @override public void process( watchedevent event ) { // todo auto-generated method stub `

这个方案大致是这样:

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+),如图(点击查看大图):

继续阅读