zookeeper管理数据库连接信息
本文将讲解如何利用zookeeper来管理项目中的数据库连接信息,即将数据库的IP、账号密码等信息存储在zookeeper中,这样的好处是可以将多个工程的数据库连接集中管理,而zookeeper本事又是分布式的,所以可靠性又有保障。
一、安装zookeeper
1、下载zookeeper
可以通过官方网站或者国内镜像下载:
官方网站:http://zookeeper.apache.org/
上海大学开源社区镜像:http://mirrors.shuosc.org/apache/zookeeper/
本文使用的版本是 zookeeper-3.4.10,服务器为3台虚拟机,IP分别为192.168.1.191、192.168.1.192、192.168.1.193,先将安装包zookeeper-3.4.10.tar.gz 上传到192.168.1.191上。
2、修改配置文件
配置文件很简单,只需要一个配置文件 conf/zoo.cfg 和dataDir下的myid
先在192.168.1.191 所以zoo.cfg内容配置如下:
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=5
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=2
# the directory where the snapshot is stored.
dataDir=/home/hadoop/zookeeper-3.4.10/data
# the port at which the clients will connect
clientPort=2181
server.1=192.168.1.191:2888:3888
server.2=192.168.1.192:2888:3888
server.3=192.168.1.193:2888:3888
参数说明:
tickTime: zookeeper中使用的基本时间单位, 毫秒值.
dataDir: 数据目录. 可以是任意目录.
dataLogDir: log目录, 同样可以是任意目录. 如果没有设置该参数, 将使用和dataDir相同的设置
clientPort: 监听client连接的端口号.
initLimit:follower和leader之间的最长心跳时间. 此时该参数设置为5, 说明时间限制为5倍tickTime, 即5*2000=10000ms=10s.
syncLimit: 该参数配置leader和follower之间发送消息, 请求和应答的最大时间长度. 此时该参数设置为2, 说明时间限制为2倍tickTime, 即4000ms.
server.I=A:B:C 其中I是一个数字, 表示这是第几号server. A是该server所在的IP地址. B配置该server和集群中的leader交换消息所使用的端口. C配置选举leader时所使用的端口. 如果配置的是伪集群模式, 则各个server的B, C参数必须不同.
/home/hadoop/zookeeper-3.4.10/data/myid内容为1即可,即只有一个数字1。
3、拷贝这个目录到其他两台机器192.168.1.192、192.168.1.193上,然后只需分别修改两台服务器上的/home/hadoop/zookeeper-3.4.10/data/myid文件内容为2和3即可
4、启动zookeeper
bin/zkServer.sh start
[hadoop@hadoop01 zookeeper-3.4.10]$ bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /home/hadoop/zookeeper-3.4.10/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
查看启动状态:
bin/zkServer.sh status
正常已启动状态如下:
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper-3.4.9/bin/../conf/zoo.cfg
Error contacting service. It is probably not running.
如果未启动,信息如下:
期中,Mode: follower表示从节点,Mode: leader表示主节点
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper-3.4.9/bin/../conf/zoo.cfg
Mode: follower
需要分别在三台机器上启动
如果没有启动完全,就会报错
2017-10-06 16:44:36,114 [myid:] - INFO [main-SendThread(192.168.1.191:2181):ClientCnxn$SendThread@1032] - Opening socket connection to server 192.168.1.191/192.168.1.191:2181. Will not attempt to authenticate using SASL (unknown error)
Welcome to ZooKeeper!
2017-10-06 16:44:36,215 [myid:] - INFO [main-SendThread(192.168.1.191:2181):ClientCnxn$SendThread@876] - Socket connection established to 192.168.1.191/192.168.1.191:2181, initiating session
JLine support is enabled
2017-10-06 16:44:36,268 [myid:] - INFO [main-SendThread(192.168.1.191:2181):ClientCnxn$SendThread@1158] - Unable to read additional data from server sessionid 0x0, likely server has closed socket, closing socket connection and attempting reconnect
[zk: 192.168.1.191:2181(CONNECTING) 0] 2017-10-06 16:44:37,509 [myid:] - INFO [main-SendThread(192.168.1.191:2181):ClientCnxn$SendThread@1032] - Opening socket connection to server 192.168.1.191/192.168.1.191:2181. Will not attempt to authenticate using SASL (unknown error)
2017-10-06 16:44:37,513 [myid:] - INFO [main-SendThread(192.168.1.191:2181):ClientCnxn$SendThread@876] - Socket connection established to 192.168.1.191/192.168.1.191:2181, initiating session
或者
2017-10-06 16:44:08,360 [myid:] - INFO [main-SendThread(192.168.1.193:2181):ClientCnxn$SendThread@1032] - Opening socket connection to server 192.168.1.193/192.168.1.193:2181. Will not attempt to authenticate using SASL (unknown error)
2017-10-06 16:44:08,386 [myid:] - WARN [main-SendThread(192.168.1.193:2181):ClientCnxn$SendThread@1162] - Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect
java.net.ConnectException: 拒绝连接
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)
at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:361)
at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1141)
5、连接zookeeper
bin/zkCli.sh -server 192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181
[hadoop@hadoop01 zookeeper-3.4.10]$ bin/zkCli.sh -server 192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181
Connecting to 192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181
2017-10-06 16:47:24,330 [myid:] - INFO [main:Environment@100] - Client environment:zookeeper.version=3.4.10-39d3a4f269333c922ed3db283be479f9deacaa0f, built on 03/23/2017 10:13 GMT
2017-10-06 16:47:24,335 [myid:] - INFO [main:Environment@100] - Client environment:host.name=hadoop01
2017-10-06 16:47:24,336 [myid:] - INFO [main:Environment@100] - Client environment:java.version=1.8.0_131
2017-10-06 16:47:24,338 [myid:] - INFO [main:Environment@100] - Client environment:java.vendor=Oracle Corporation
2017-10-06 16:47:24,339 [myid:] - INFO [main:Environment@100] - Client environment:java.home=/home/hadoop/jdk1.8.0_131/jre
2017-10-06 16:47:24,339 [myid:] - INFO [main:Environment@100] - Client environment:java.class.path=/home/hadoop/zookeeper-3.4.10/bin/../build/classes:/home/hadoop/zookeeper-3.4.10/bin/../build/lib/*.jar:/home/hadoop/zookeeper-3.4.10/bin/../lib/slf4j-log4j12-1.6.1.jar:/home/hadoop/zookeeper-3.4.10/bin/../lib/slf4j-api-1.6.1.jar:/home/hadoop/zookeeper-3.4.10/bin/../lib/netty-3.10.5.Final.jar:/home/hadoop/zookeeper-3.4.10/bin/../lib/log4j-1.2.16.jar:/home/hadoop/zookeeper-3.4.10/bin/../lib/jline-0.9.94.jar:/home/hadoop/zookeeper-3.4.10/bin/../zookeeper-3.4.10.jar:/home/hadoop/zookeeper-3.4.10/bin/../src/java/lib/*.jar:/home/hadoop/zookeeper-3.4.10/bin/../conf:.:/home/hadoop/jdk1.8.0_131/lib/tools.jar:/home/hadoop/jdk1.8.0_131/lib/dt.jar
2017-10-06 16:47:24,339 [myid:] - INFO [main:Environment@100] - Client environment:java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
2017-10-06 16:47:24,340 [myid:] - INFO [main:Environment@100] - Client environment:java.io.tmpdir=/tmp
2017-10-06 16:47:24,340 [myid:] - INFO [main:Environment@100] - Client environment:java.compiler=<NA>
2017-10-06 16:47:24,340 [myid:] - INFO [main:Environment@100] - Client environment:os.name=Linux
2017-10-06 16:47:24,340 [myid:] - INFO [main:Environment@100] - Client environment:os.arch=amd64
2017-10-06 16:47:24,341 [myid:] - INFO [main:Environment@100] - Client environment:os.version=2.6.18-274.el5
2017-10-06 16:47:24,341 [myid:] - INFO [main:Environment@100] - Client environment:user.name=hadoop
2017-10-06 16:47:24,341 [myid:] - INFO [main:Environment@100] - Client environment:user.home=/home/hadoop
2017-10-06 16:47:24,342 [myid:] - INFO [main:Environment@100] - Client environment:user.dir=/home/hadoop/zookeeper-3.4.10
2017-10-06 16:47:24,344 [myid:] - INFO [main:ZooKeeper@438] - Initiating client connection, connectString=192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@22d8cfe0
2017-10-06 16:47:24,402 [myid:] - INFO [main-SendThread(192.168.1.191:2181):ClientCnxn$SendThread@1032] - Opening socket connection to server 192.168.1.191/192.168.1.191:2181. Will not attempt to authenticate using SASL (unknown error)
Welcome to ZooKeeper!
2017-10-06 16:47:24,502 [myid:] - INFO [main-SendThread(192.168.1.191:2181):ClientCnxn$SendThread@876] - Socket connection established to 192.168.1.191/192.168.1.191:2181, initiating session
JLine support is enabled
2017-10-06 16:47:24,556 [myid:] - INFO [main-SendThread(192.168.1.191:2181):ClientCnxn$SendThread@1299] - Session establishment complete on server 192.168.1.191/192.168.1.191:2181, sessionid = 0x15ef0dc89650001, negotiated timeout = 30000
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
[zk: 192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181(CONNECTED) 0]
6、查看当前节点
ls /
WatchedEvent state:SyncConnected type:None path:null
[zk: 192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181(CONNECTED) 0] ls /
[zookeeper]
[zk: 192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181(CONNECTED) 1] ls /zookeeper
[zk2, zk, test, quota]
其他客户端命令可以用h查看
[zk: 192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181(CONNECTED) 2] h
ZooKeeper -server host:port cmd args
stat path [watch]
set path data [version]
ls path [watch]
delquota [-n|-b] path
ls2 path [watch]
setAcl path acl
setquota -n|-b val path
history
redo cmdno
printwatches on|off
delete path [version]
sync path
listquota path
rmr path
get path [watch]
create [-s] [-e] path data acl
addauth scheme auth
quit
getAcl path
close
connect host:port
7、创建新的节点
create [-s] [-e] path data acl
-s:指定该节点是一个序列节点,创建同名的节点时,会给节点自动加上编号
-e:指定该节点是一个临时节点,默认是永久节点。临时节点会在客户端与服务器断开连接时,zk会将其创建的所有临时节点全部删除
path:节点路径
data:存储在节点中的数据
acl:设置子节点访问权限,默认所有人都可以对该节点进行读写操作
如果使用-s参数,系统会自动在的节点名称后面加循环,如0000000007
[zk: 192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181(CONNECTED) 1] create -s /zookeeper/node xxx
Created /zookeeper/node0000000007
[zk: 192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181(CONNECTED) 5] ls /zookeeper
[zk2, zk, test, dblink, node0000000007, quota]
这样并不是很方便,而且zkCli也没有通过修改节点名称的方法。那么,怎么样才能让他就用我们指定的名称呢?那就是create后面直接接节点名称,不加-s也不加-e。
[zk: 192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181(CONNECTED) 3] create /zookeeper/dblink xxxx
Created /zookeeper/dblink
[zk: 192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181(CONNECTED) 4] ls /zookeeper
[zk2, zk, test, dblink, quota]
[zk: 192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181(CONNECTED) 5] get /zookeeper/dblink
xxxx
cZxid = 0x300000006
ctime = Fri Oct 06 16:50:19 CST 2017
mZxid = 0x300000006
mtime = Fri Oct 06 16:50:19 CST 2017
pZxid = 0x300000006
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
二、创建数据库连接信息
现在我们需要将数据库配置信息存放到zookeeper的节点中,但是,如果通过zkCli 会遇到一个问题,那就是zkCli没有转义,即没法写入换行符,比如我们的数据库配置信息:
userName=sa
userPwd=123
dbURL:jdbc:sqlserver://192.18.1.101:1433;DatabaseName=db1
driverNamecom.microsoft.sqlserver.jdbc.SQLServerDriver
所以,
必须通过zookeeper的API 来实现。需要引入的外部包
zookeeper-3.4.10.jar 和slf4j-api-1.6.1.jar在 zookeeper-3.4.10.tar.gz压缩包中都可以找到
ZooKeeper zooKeeper = new ZooKeeper(connectString, sessionTimeout, watcher); //创建一个ZooKeeper对象
zooKeeper.setData("/zookeeper/dblink", "userName=sa\nuserPwd=123".getBytes(),-1); //通过zooKeeper.setData来修改节点数据
三、获取数据库连接信息
创建并配置好数据库连接信息后,即可通过getData方法来获取数据信息,然后通过Properties来解析信息
ZooKeeper zooKeeper = new ZooKeeper(connectString, sessionTimeout, watcher);
byte[] b = zooKeeper.getData(path, true, null) ;
String res= new String(b);
Properties pro = new Properties();
String userName =null;
String userPwd =null;
String dbURL =null;
String driverName =null;
try {
pro.load(new StringBufferInputStream(res));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
完整的java代码如下:
package Package1;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Reader;
import java.io.StringBufferInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.List;
import java.util.Properties;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Op.SetData;
import org.apache.zookeeper.WatchedEvent;
public class ZooKeeperDBlink {
public static void main(String[] args) {
String data="dbURL=jdbc:sqlserver://192.168.1.101:1433;DatabaseName=db1\n"+
"userName=sa\n"+
"userPwd=123\n"+
"driverName=com.microsoft.sqlserver.jdbc.SQLServerDriver";
setData("/zookeeper/dblink",data);
getDB();
}
public static void getDB(){
String connectString = "192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181";
String path="/zookeeper/dblink";
int sessionTimeout = 4000;
Watcher watcher = new Watcher() {
public void process(WatchedEvent event) {
//System.out.println(event.getPath());
}
};
try {
ZooKeeper zooKeeper = new ZooKeeper(connectString, sessionTimeout, watcher);
byte[] b = zooKeeper.getData(path, true, null) ;
String res= new String(b);
Properties pro = new Properties();
String userName =null;
String userPwd =null;
String dbURL =null;
String driverName =null;
try {
pro.load(new StringBufferInputStream(res));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
dbURL=pro.getProperty("dbURL");
userName=pro.getProperty("userName");
userPwd=pro.getProperty("userPwd");
driverName=pro.getProperty("driverName");
System.out.println("userName:"+userName);
System.out.println("userPwd:"+userPwd);
System.out.println("dbURL:"+dbURL);
System.out.println("driverName"+driverName);
} catch (IOException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void setData(String path, String data){
String connectString = "192.168.1.191:2181,192.168.1.192:2181,192.168.1.193:2181";
int sessionTimeout = 4000;
Watcher watcher = new Watcher() {
public void process(WatchedEvent event) {
//System.out.println(event.getPath());
}
};
try {
ZooKeeper zooKeeper = new ZooKeeper(connectString, sessionTimeout, watcher); //创建一个ZooKeeper对象
zooKeeper.setData(path, data.getBytes(),-1); //通过zooKeeper.setData来修改节点数据
} catch (IOException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出结果:
userName:sa
userPwd:123
dbURL:jdbc:sqlserver://192.168.1.101:1433;DatabaseName=db1
driverNamecom.microsoft.sqlserver.jdbc.SQLServerDriver