最早接触Zookeeper,是在学习Hadoop权威指南这本书的时候,印象中是Hadoop项目的一个子工程。
最近,项目中需要用到“分布式锁”。
之前,在开发P2P网贷系统的时候,就用到了“分布式锁”,这个概念听起来挺高端的,实际就是多台机器下,同时运行项目下的“锁”。
之前是用Redis实现“分布式锁”,但是周期性地出现了问题。只能是推测,程序异常退出,或者本地开发和测试环境用的一套Redis,
本地线程定时任务,经常被强制关闭,锁没有成功释放。
听Boss说,Memcache自带的就是分布式的锁,目前还没用过。
据Boss说,2005年之前,实现分布式锁主要是用Memcache和Oracle。后来,出现了NoSQL的Redis,Oracle基本被MySQL取代,
“分布式锁”就成了个问题。至于其他人是怎么解决的,可能还是用了Memcache做缓存,也可能还有其它机智或者解决方案。
探讨技术概念“分布式锁”,真正的实现,必须是要考虑“业务场景”的。
单独的技术,很少有脱离业务场景的。
后来Hadoop出现,有Zookeeper,不知什么时候起,用Zookeeper实现分布式锁的人就变多了。
从哪里可以看出来呢?百度搜索“Zookeeper”,相关的文章多了,搜索Zookeeper+分布式锁的人变多了。
看一个技术火不火,看看有多少人在学习,有多少人在总结相关的文章,就知道了。
Zookeeper基本介绍
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。
它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、名字服务、分布式同步、组服务等。
ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
ZooKeeper包含一个简单的原语集,[1] 提供Java和C的接口。
ZooKeeper代码版本中,提供了分布式独享锁、选举、队列的接口,代码在zookeeper-3.4.3src ecipes。其中分布锁和队列有Java和C两个版本,选举只有Java版本。
ZooKeeper是以Fast Paxos算法为基础的,paxos算法存在活锁的问题,即当有多个proposer交错提交时,有可能互相排斥导致没有一个proposer能提交成功,
而Fast Paxos作了一些优化,通过选举产生一个leader,只有leader才能提交proposer,具体算法可见Fast Paxos。因此,要想弄懂ZooKeeper首先得对Fast Paxos有所了解。[3]
ZooKeeper的基本运转流程:
1、选举Leader。
2、同步数据。
3、选举Leader过程中算法有很多,但要达到的选举标准是一致的。
4、Leader要具有最高的zxid。
5、集群中大多数的机器得到响应并follow选出的Leader。
官方网站
http://zookeeper.apache.org/
Zookeeper启动
实际项目开发中,用的是Linux版本的。
#Zookeeper启动
./zkServer.sh start &
./zkCli.sh -server 127.0.0.1:2181 &
没啥大问题
自己学习,用的是Windows版本的。
#Zookeeper启动
cd /d E:Mongodb-Redis-Nginxzookeeper-3.5.1-alphain
zkServer start &
zkCli -server 127.0.0.1:2181 &
E:Mongodb-Redis-Nginxzookeeper-3.5.1-alphain>zkServer.cmd start
系统找不到指定的路径。
Error: JAVA_HOME is incorrectly set.
E:Mongodb-Redis-Nginxzookeeper-3.5.1-alphain>call "-Dzookeeper.log.dir=E:M
ongodb-Redis-Nginxzookeeper-3.5.1-alphain..logs" "-Dzookeeper.root.logger=I
NFO,CONSOLE" "-Dzookeeper.log.file=zookeeper-Administrator-server-XIAOLEI.log" "
-XX:+HeapDumpOnOutOfMemoryError" "-XX:OnOutOfMemoryError=cmd /c taskkill /pid %%
p /t /f" -cp "E:Mongodb-Redis-Nginxzookeeper-3.5.1-alphain..uildclasses;
E:Mongodb-Redis-Nginxzookeeper-3.5.1-alphain..uildlib*;E:Mongodb-Redis
-Nginxzookeeper-3.5.1-alphain..*;E:Mongodb-Redis-Nginxzookeeper-3.5.1-alp
hain..lib*;E:Mongodb-Redis-Nginxzookeeper-3.5.1-alphain..conf" org.ap
ache.zookeeper.server.quorum.QuorumPeerMain "E:Mongodb-Redis-Nginxzookeeper-3.
5.1-alphain..confzoo.cfg" start
文件名、目录名或卷标语法不正确。
E:Mongodb-Redis-Nginxzookeeper-3.5.1-alphain>endlocal
#打印Java_HOME,明明已经配置好了,所以排除JAVA_HOME的原因
E:Mongodb-Redis-Nginxzookeeper-3.5.1-alphain>echo %JAVA_HOME%
C:Program FilesJavajdk1.7.0_17;
就算是把JAVA_HOME改为"C:Program FilesJavajdk1.7.0_17"还是不行。
网上搜了下,可能是JDK版本的问题,我用的是JDK1.7。
因此,我判断很可能是JDK和Zookeeper的版本匹配问题。
重新下载3.4.6版本的Zookeeper
cd /d E:Mongodb-Redis-Nginxzookeeper-3.4.6in
zkServer start &
E:Mongodb-Redis-Nginxzookeeper-3.4.6in>zkServer.cmd start
E:Mongodb-Redis-Nginxzookeeper-3.4.6in>java "-Dzookeeper.log.dir=E:Mongodb-
Redis-Nginxzookeeper-3.4.6in.." "-Dzookeeper.root.logger=INFO,CONSOLE" -cp "
E:Mongodb-Redis-Nginxzookeeper-3.4.6in..uildclasses;E:Mongodb-Redis-Ngi
nxzookeeper-3.4.6in..uildlib*;E:Mongodb-Redis-Nginxzookeeper-3.4.6in
..*;E:Mongodb-Redis-Nginxzookeeper-3.4.6in..lib*;E:Mongodb-Redis-Nginx
zookeeper-3.4.6in..conf" org.apache.zookeeper.server.quorum.QuorumPeerMain
"E:Mongodb-Redis-Nginxzookeeper-3.4.6in..confzoo.cfg" start
错误: 找不到或无法加载主类 org.apache.zookeeper.server.quorum.QuorumPeerMain
E:Mongodb-Redis-Nginxzookeeper-3.4.6in>endlocal
配置zoo.cfg文件
在conf目录,复制zoo_sample.cfg,重名为zoo.cfg,重新启动
又报错了
E:Mongodb-Redis-Nginxzookeeper-3.4.6in>zkServer.cmd start
E:Mongodb-Redis-Nginxzookeeper-3.4.6in>java "-Dzookeeper.log.dir=E:Mongodb-
Redis-Nginxzookeeper-3.4.6in.." "-Dzookeeper.root.logger=INFO,CONSOLE" -cp "
E:Mongodb-Redis-Nginxzookeeper-3.4.6in..uildclasses;E:Mongodb-Redis-Ngi
nxzookeeper-3.4.6in..uildlib*;E:Mongodb-Redis-Nginxzookeeper-3.4.6in
..*;E:Mongodb-Redis-Nginxzookeeper-3.4.6in..lib*;E:Mongodb-Redis-Nginx
zookeeper-3.4.6in..conf" org.apache.zookeeper.server.quorum.QuorumPeerMain
"E:Mongodb-Redis-Nginxzookeeper-3.4.6in..confzoo.cfg" start
2015-12-01 10:14:27,347 [myid:] - INFO [main:DatadirCleanupManager@78] - autopu
rge.snapRetainCount set to 3
2015-12-01 10:14:27,350 [myid:] - INFO [main:DatadirCleanupManager@79] - autopu
rge.purgeInterval set to 0
2015-12-01 10:14:27,351 [myid:] - INFO [main:DatadirCleanupManager@101] - Purge
task is not scheduled.
2015-12-01 10:14:27,351 [myid:] - WARN [main:QuorumPeerMain@113] - Either no co
nfig or no quorum defined in config, running in standalone mode
2015-12-01 10:14:27,411 [myid:] - ERROR [main:ZooKeeperServerMain@54] - Invalid
arguments, exiting abnormally
java.lang.NumberFormatException: For input string: "E:Mongodb-Redis-Nginxzooke
eper-3.4.6in..confzoo.cfg"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at org.apache.zookeeper.server.ServerConfig.parse(ServerConfig.java:60)
at org.apache.zookeeper.server.ZooKeeperServerMain.initializeAndRun(ZooK
eeperServerMain.java:83)
at org.apache.zookeeper.server.ZooKeeperServerMain.main(ZooKeeperServerM
ain.java:52)
at org.apache.zookeeper.server.quorum.QuorumPeerMain.initializeAndRun(Qu
orumPeerMain.java:116)
at org.apache.zookeeper.server.quorum.QuorumPeerMain.main(QuorumPeerMain
.java:78)
2015-12-01 10:14:27,415 [myid:] - INFO [main:ZooKeeperServerMain@55] - Usage: Z
ooKeeperServerMain configfile | port datadir [ticktime] [maxcnxns]
Usage: ZooKeeperServerMain configfile | port datadir [ticktime] [maxcnxns]
妈蛋啊,网上找了很多资料,没啥可用的。
后来,还是根据错误信息“windows zookeeper启动 java.lang.NumberFormatException”找到了1个答案。
zkServer.cmd 不要后面的“start”就正常启动了。
cd /d E:Mongodb-Redis-Nginxzookeeper-3.4.6in
zkCli.cmd -server 127.0.0.1:2181
通过艰难的几步,就正常启动了。
Zookeeper启动总结
1.实际项目用的是Linux,问题不大,本地开发学习用Windows,问题多多。
2.Zookeeper3.5.1-alpha,和本地JDK1.7,有冲突,无法正常启动。
3.Zookeeper启动,需要配置conf目录下的zoo.cfg。复制-粘贴-重命名一次就可以了。
4.Windows下启动,不需要带“start”参数,直接zkServer.cmd,真是够坑的。
zoo.cfg
# The number of milliseconds of each tick tickTime=2000 # The number of ticks that the initial # synchronization phase can take initLimit=10 # The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit=5 # the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. dataDir=C:/zookeeper # the port at which the clients will connect clientPort=2181 # the maximum number of client connections. # increase this if you need to handle more clients #maxClientCnxns=60 # # Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir #autopurge.snapRetainCount=3 # Purge task interval in hours # Set to "0" to disable auto purge feature #autopurge.purgeInterval=1
dataDir和clientPort应该是必须的。
一点感想:逃避or面对
在Windows下遇到问题的时候,其实我非常想立即转到Linux下,就没有这么多屁事了。
但是,我一直意识到“人”比较喜欢逃避问题,就硬是忍着去正面解决了问题。
另外,是想把遇到的每一个问题都解决了,自己解决问题的能力,肯定是大幅度提高了。
参考资料
Zookeeper百度百科
http://baike.baidu.com/link?url=MsOQSGlqQA1BKF8v9OlB7k_jRi6lZm4fU9JeyP_pwA8yFa8mJopj3B7INfVVLRCIKkkEo2osXfBqnnSvuTq0p_
Zookeeper异常ConnectionLossException解决
http://www.sjsjw.com/kf_cloud/article/022572ABA018042.asp
E:Mongodb-Redis-Nginxzookeeper-3.5.1-alphain
启动Zookeeper时抛出“Invalid arguments, exiting abnormally”错误信息
http://www.bug315.com/article/156.htm