基于centos8搭建zookeeper集群
【README】 本文基于centos8 搭建
1,其他linux版本,命令可能不同;
2,集群包括3个节点,如下(因为采用NAT模型进行网络连接,需要让windows和linux机器在同一个网段):
centos01: 192.168.163.201
centos02: 192.168.163.202
centos02: 192.168.163.203
【1】 软件准备
1、远程文件传输软件
window 与 centos 文件传输, sz, rz
yum -y install lrzsz
yum -y install vim
yum -y install scp
yum -y install rsync 远程同步文件
2、安装java
vim /etc/profile
# JVM ENV
JAVA_HOME=/usr/local/java/jdk1.8
JRE_HOME=$JAVA_HOME/jre
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin
export JAVA_HOME CLASSPATH PATH JRE_HOME
source /etc/profile 更新
java -version
【2】搭建单机模式的zk
步骤1: 下载 zookeeper 框架包, 本文使用 zookeeper-3.4.10 , https://archive.apache.org/dist/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz
[root@localhost module]# ls
zookeeper-3.4.10.tar.gz
步骤2:解压,位置在 /opt/module
tar -zxvf zookeeper-3.4.10.tar.gz
[root@localhost module]# ls
zookeeper-3.4.10 zookeeper-3.4.10.tar.gz
[root@localhost module]# pwd
/opt/module
[root@localhost module]# cd zookeeper-3.4.10
[root@localhost zookeeper-3.4.10]# pwd
/opt/module/zookeeper-3.4.10
步骤3: 修改 zookeeper 配置文件
[root@localhost zookeeper-3.4.10]# cd conf
[root@localhost conf]# ls
configuration.xsl log4j.properties zoo_sample.cfg
[root@localhost conf]# cp zoo_sample.cfg zoo.cfg
[root@localhost conf]# vim zoo.cfg
设置zoo.cfg 如下,修改 dataDir=/opt/module/zookeeper-3.4.10/zkdata zkdata为自定义文件夹
-- zoo.cfg[root@localhost conf]# cat 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=/opt/module/zookeeper-3.4.10/zkdata
# 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
步骤4: 新建 /opt/module/zookeeper-3.4.10/zkdata 文件夹
[root@localhost zookeeper-3.4.10]# pwd
/opt/module/zookeeper-3.4.10
[root@localhost zookeeper-3.4.10]# mkdir zkdata
步骤5: 启动zk,并查看zk状态
[root@localhost zookeeper-3.4.10]# bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
[root@localhost zookeeper-3.4.10]#
[root@localhost zookeeper-3.4.10]# bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: standalone
standalone 为单机模式 ;
提醒:这里可能报错 Error contacting service. It is probably not running.
解决方法1: 关闭防火墙
查看防火墙状态:firewall-cmd --state
关闭防火墙:systemctl stop firewalld.service解决方法2: https://blog.csdn.net/PacosonSWJTU/article/details/111260961
懂的查看 zk 目录下的 zookeeper.out 日志文件;
步骤6: 启动zk客户端, 并退出(quit)
[root@localhost zookeeper-3.4.10]# bin/zkCli.sh
Connecting to localhost:2181
Welcome to ZooKeeper!
......
WATCHER::WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0]
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper][zk: localhost:2181(CONNECTED) 1] quit
Quitting...
2020-12-20 03:42:33,745 [myid:] - INFO [main:ZooKeeper@684] - Session: 0x1767c83c15e0000 closed
2020-12-20 03:42:33,747 [myid:] - INFO [main-EventThread:ClientCnxn$EventThread@519] - EventThread shut down for session: 0x1767c83c15e0000
[root@localhost zookeeper-3.4.10]#
步骤7:停止zk线程(或有)
[root@localhost zookeeper-3.4.10]# bin/zkServer.sh stop
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Stopping zookeeper ... STOPPED
补充:zoo.cfg 配置解析
序号 | 属性 | 描述 |
1 | tickTime=2000 | 心跳,2000毫秒一个心跳;(2秒) |
2 | initLimit=10 | 10个2秒, 20秒是Leader和Follower 刚开始(初始化)通信的最大延时时间; 如果超过这个时间, 则zk服务器认为 两者连接失败; |
3 | syncLimit=5 | 5个2秒, 10秒是 Leader 和 Follower的在集群正常启动后的通信的最大延时时间; 如果超过这个时间, 则zk服务器认为 两者连接失败; |
4 | dataDir=/opt/module/zookeeper-3.4.10/zkdata | 设置zk数据文件存储路径; |
5 | clientPort=2181 | 客户端访问 zk 服务的所在主机的端口号; |
【3】搭建集群模式的zk
步骤1:201机器,在zoo.cfg下增加集群配置;
server.A=B.C.D , 如 server.1=192.168.163.201:2888:3888
其中A 等于myid文件的值1;
B表示本服务器地址 192.168.163.201;
C表示本服务器与集群中 Leader服务器交换信息的端口 ; 两者同步的数据是 数据副本; 2888;
D表示 在选举Leader服务器时,服务器间相互通信的端口; 3888;
小结:添加如下配置:
server.1=192.168.163.201:2888:3888
server.2=192.168.163.202:2888:3888
server.3=192.168.163.203:2888:3888
[root@localhost module]# cat zookeeper-3.4.10/conf/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=/opt/module/zookeeper-3.4.10/zkdata
# 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
server.1=192.168.163.201:2888:3888
server.2=192.168.163.202:2888:3888
server.3=192.168.163.203:2888:3888
步骤2:201机器,设置服务器编号,在zkdata文件夹下新建myid,内容为1;
[root@localhost zkdata]# pwd
/opt/module/zookeeper-3.4.10/zkdata
[root@localhost zkdata]# echo "1" > myid
步骤3:把201机器下的 zookeeper 文件夹同步到202,203机器 ;
[root@localhost module]# rsync -azv zookeeper-3.4.10/ root@192.168.163.202:/opt/module/zookeeper-3.4.10/
[root@localhost module]# rsync -azv zookeeper-3.4.10/ root@192.168.163.203:/opt/module/zookeeper-3.4.10/
步骤4:修改 202机器的myid为2, 203机器的myid为3 ;
-- 202机器
[root@localhost zookeeper-3.4.10]# cat zkdata/myid
2
-- 203 机器
[root@localhost zookeeper-3.4.10]# cat zkdata/myid
3
步骤5: 启动zk集群
-- 201机器-启动失败
[root@localhost zookeeper-3.4.10]# bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
[root@localhost zookeeper-3.4.10]# bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Error contacting service. It is probably not running.
[root@localhost zookeeper-3.4.10]#
-- 202机器-启动成功-并且成为leader
[root@localhost zookeeper-3.4.10]# bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
[root@localhost zookeeper-3.4.10]# bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: leader
[root@localhost zookeeper-3.4.10]#
注: zk的选举机制,自行google, 这里不再赘述;
-- 203机器-启动成功-follower
[root@localhost zookeeper-3.4.10]# bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
[root@localhost zookeeper-3.4.10]#
[root@localhost zookeeper-3.4.10]# bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: follower
我们再回头查看201机器的zk状态 ; 当202,203启动zk线程后, 我们再次查看201的zk状态为 成功且是 follower;
-- 201
[root@localhost zookeeper-3.4.10]# bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
[root@localhost zookeeper-3.4.10]# bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Error contacting service. It is probably not running.
[root@localhost zookeeper-3.4.10]# -- ### 我是分割线, 202,203开启zk线程后,[root@localhost zookeeper-3.4.10]# bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: follower
[root@localhost zookeeper-3.4.10]#
至此,zk集群启动成功;
【4】其他
【4.1】zookeeper 选举机制
1)半数机制: 当有半数以上机器存活,则集群可用;否则不可用; (不包括半数);建议zookeeper 集群的机器数量为奇数 ;
2)虽然配置文件没有指定 master 和 slave,但在工作时, zookeeper临时选择一条机器作为 master或 leader, 其他机器为 slave或follower;
【4.2】zk客户端命令行
-- zk客户端常用命令
ls create get delete rmr set
登录zk客户端
[root@localhost zookeeper-3.4.10]# bin/zkCli.sh
1) ls 查看节点
ls2 查看节点详情
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 1] ls2 /
[zookeeper]
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1
[zk: localhost:2181(CONNECTED) 2]
stat结构体
序号 |
key |
描述 |
1 |
cZxid |
创建事务编号 |
2 |
ctime |
创建时间 |
3 |
mZxid |
修改事务编号 |
4 |
mtime |
修改时间 |
5 |
pZxid |
最后更新的子节点 |
6 |
cversion |
子节点变化编号 |
7 |
dataVersion |
数据变化编号 |
8 |
aclVersion |
访问控制列表的变化号 |
9 |
ephemeralOwner |
若是临时节点,表示的是znode拥有者的session id,如果不是,则是0 |
10 |
dataLength |
znode的数据长度 |
11 |
numChildren |
znode的子节点个数 |
2)create 创建节点
[zk: localhost:2181(CONNECTED) 2] create /sichuan "sichuan"
Created /sichuan
[zk: localhost:2181(CONNECTED) 3] ls /
[sichuan, zookeeper]
3)get 获取节点
[zk: localhost:2181(CONNECTED) 4] get /sichuan
sichuan
cZxid = 0x100000002
ctime = Sun Dec 20 04:22:16 CST 2020
mZxid = 0x100000002
mtime = Sun Dec 20 04:22:16 CST 2020
pZxid = 0x100000002
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 0
[zk: localhost:2181(CONNECTED) 5]
4)delete 删除节点
[zk: localhost:2181(CONNECTED) 5] create /sichuan/cd "chengdu"
Created /sichuan/cd
[zk: localhost:2181(CONNECTED) 7] create /sichuan/leshan "leshan4"
Created /sichuan/leshan
[zk: localhost:2181(CONNECTED) 8] ls /sichuan
[cd, leshan]
[zk: localhost:2181(CONNECTED) 9] delete /sichuan/leshan
[zk: localhost:2181(CONNECTED) 10]
[zk: localhost:2181(CONNECTED) 10] ls /sichuan
[cd]
[zk: localhost:2181(CONNECTED) 11]
5)rmr 递归删除当前目录及其下的所有子目录
[zk: localhost:2181(CONNECTED) 10] ls /sichuan
[cd]
[zk: localhost:2181(CONNECTED) 11] create /sichuan/my "mianyang"
Created /sichuan/my
[zk: localhost:2181(CONNECTED) 12] ls /sichuan
[cd, my]
[zk: localhost:2181(CONNECTED) 13] rmr /sichuan
[zk: localhost:2181(CONNECTED) 14]
[zk: localhost:2181(CONNECTED) 14] ls /sichuan
Node does not exist: /sichuan
6)set 设置节点存储的值
[zk: localhost:2181(CONNECTED) 18] create /china "china"
Created /china
[zk: localhost:2181(CONNECTED) 19] [zk: localhost:2181(CONNECTED) 19] get /china
china
cZxid = 0x10000000b
ctime = Sun Dec 20 04:28:10 CST 2020
mZxid = 0x10000000b
mtime = Sun Dec 20 04:28:10 CST 2020
pZxid = 0x10000000b
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0[zk: localhost:2181(CONNECTED) 20] set /china "china xiongqi"
cZxid = 0x10000000b
ctime = Sun Dec 20 04:28:10 CST 2020
mZxid = 0x10000000c
mtime = Sun Dec 20 04:28:35 CST 2020
pZxid = 0x10000000b
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 13
numChildren = 0[zk: localhost:2181(CONNECTED) 21] get /china
china xiongqi
cZxid = 0x10000000b
ctime = Sun Dec 20 04:28:10 CST 2020
mZxid = 0x10000000c
mtime = Sun Dec 20 04:28:35 CST 2020
pZxid = 0x10000000b
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 13
numChildren = 0
[zk: localhost:2181(CONNECTED) 22]
7)zk有4种节点类型:
1、类型1-持久目录节点: 客户端与服务器断开后,创建的节点不删除;
2、类型2-持久化顺序编号目录节点:客户端与服务器断开连接后, 该节点依旧存在,只是zookeeper 给该节点名称进行顺序编号;
应用场景:在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序; (哪台服务器先上,哪台服务器后上)
3、类型3-临时目录节点:两者断开后, 创建的节点被删除;
应用场景: zk 服务器监听某台客户端机器的状态; 若客户端机器下线,则zk服务器节点也删除; 集群从而间接知晓 客户端机器下线;(服务器节点动态上下线)
4、类型4-临时顺序编号目录节点:客户端与服务器断开后,该节点被删除; 只是 zk 对该服务器节点名称进行了顺序编号;
8)荔枝: 创建有序节点 (-s) 创建临时节点 -e
有序节点
-- 创建有序节点
[zk: localhost:2181(CONNECTED) 24] ls /china
[]
[zk: localhost:2181(CONNECTED) 25] create -s /china/beijing "beijing"
Created /china/beijing0000000000
[zk: localhost:2181(CONNECTED) 26] create -s /china/beijing "beijing"
Created /china/beijing0000000001
[zk: localhost:2181(CONNECTED) 27] create -s /china/beijing "beijing"
Created /china/beijing0000000002
[zk: localhost:2181(CONNECTED) 28] create -s /china/beijing "beijing"
Created /china/beijing0000000003
[zk: localhost:2181(CONNECTED) 29] ls /china
[beijing0000000001, beijing0000000000, beijing0000000003, beijing0000000002]
创建临时+有序节点 (chongqing)
[zk: localhost:2181(CONNECTED) 31] create -e -s /china/chongqing "chongqing4"
Created /china/chongqing0000000004
[zk: localhost:2181(CONNECTED) 32]
[zk: localhost:2181(CONNECTED) 32] ls /china
[beijing0000000001, beijing0000000000, chongqing0000000004, beijing0000000003, beijing0000000002]
退出 当前客户端 quit 并再次登录客户端 , 发现chognqing节点被删除了;
[zk: localhost:2181(CONNECTED) 33] quit
Quitting...
2020-12-20 04:38:48,888 [myid:] - INFO [main:ZooKeeper@684] - Session: 0x1767ca215950000 closed
2020-12-20 04:38:48,890 [myid:] - INFO [main-EventThread:ClientCnxn$EventThread@519] - EventThread shut down for session: 0x1767ca215950000
[root@localhost zookeeper-3.4.10]#
[root@localhost zookeeper-3.4.10]# bin/zkCli.sh[zk: localhost:2181(CONNECTED) 0] ls /china
[beijing0000000001, beijing0000000000, beijing0000000003, beijing0000000002]
[zk: localhost:2181(CONNECTED) 1]
还有话说: 为啥 -s是有序,-e是临时。看下zk的java api 的节点类型常量命名就知道了,如下:
/**** CreateMode value determines how the znode is created on ZooKeeper.*/
public enum CreateMode {/*** The znode will not be automatically deleted upon client's disconnect.*/PERSISTENT (0, false, false),/*** The znode will not be automatically deleted upon client's disconnect,* and its name will be appended with a monotonically increasing number.*/PERSISTENT_SEQUENTIAL (2, false, true),/*** The znode will be deleted upon the client's disconnect.*/EPHEMERAL (1, true, false),/*** The znode will be deleted upon the client's disconnect, and its name* will be appended with a monotonically increasing number.*/EPHEMERAL_SEQUENTIAL (3, true, true);
最后, 可以通过 zk提供的javaapi 连接 zk集群, refer 2 https://blog.csdn.net/PacosonSWJTU/article/details/111404364
基于centos8搭建zookeeper集群相关推荐
- 基于docker搭建zookeeper集群、kafka集群(多台真机之间的集群)
基于docker搭建zookeeper集群.kafka集群---二(多台真机之间的集群) https://blog.csdn.net/diebiao6526/article/details/10143 ...
- 基于docker搭建zookeeper集群、kafka集群
zookeeper集群搭建 https://www.cnblogs.com/znicy/p/7717426.html #Docker中搭建zookeeper集群,昵称:zni.feng htt ...
- Linux搭建eureka集群,基于dns搭建eureka集群
eureka集群方案: 1.通常我们部署的eureka节点多于两个,根据实际需求,只需要将相邻节点进行相互注册(eureka节点形成环状),就达到了高可用性集群,任何一个eureka节点挂掉不会受到影 ...
- 使用Cloudera Manager搭建zookeeper集群及HDFS HA实战篇
使用Cloudera Manager搭建zookeeper集群及HDFS HA实战篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.使用Cloudera Manager搭建zo ...
- linux 使用 nginx 搭建 zookeeper 集群
搭建 zookeeper 集群,笔者这里使用3台 centos7 服务器,它们 ip 分别是 192.168.0.125:192.168.0.123:192.168.0.117,后面简称 125,12 ...
- 1主2从基于GKE搭建k8s集群-无需科学上网
1主2从基于GKE搭建k8s集群-无需科学上网 1.安装docker: 2.搭建k8s集群: 2.1.组件版本 2.1.修改hosts文件 2.3.部署前基础前提配置 2.4.部署kubeadm, k ...
- dockerer-compose搭建zookeeper集群,工作中最新亲测能用,超详细
作为一名菜鸟Java工程师,公司这几天让我搭建zookeeper集群,对于搭建过的人来说十分简单,对zookeeper不太熟悉的人来说还是有一定难度的,这一周我在公司的角色更像是运维人员搭建各种集群, ...
- linux下搭建zookeeper集群
linux下搭建zookeeper集群 1.准备 1.下载zookeeper压缩包 (注:下载3.4.14版本,3.5以上运行时会少jar包) 2.系统:centOS7 安装好java环境 3.将压缩 ...
- 基于Docker搭建Redis集群(主从集群)
最近陆陆续续有不少园友加我好友咨询 redis 集群搭建的问题,我觉得之前写的这篇 <基于Docker的Redis集群搭建> 文章一定是有问题了,所以我花了几分钟浏览之前的文章总结了下面几 ...
最新文章
- JavaScript从内容中筛选出手机号码集合
- 减少C++编译时间的方法
- day63-webservice 01.cxf介绍
- AUTOSAR从入门到精通100讲(十四)-一文详解CAN总线错误帧
- 巴菲特发布2022年致股东公开信:盛赞苹果CEO
- 大萧条来临前的几大征兆
- search engine
- ubunut 安装 pyqt5
- python安装包方式汇总
- python下载音乐代码_使用python3下载网易云音乐歌单歌曲,附源代码
- svchost.exe网速占用解决办法
- Sublime Text 2 - 性感无比的代码编辑器!程序员必备神器!跨平台支持Win/Mac/Linux,支持32与64位,支持各种流行编程语言的语法高亮、代码补全等...
- linux中如何查看mac地址
- 解决虚拟机键盘不能使用,或能使用但会模糊错乱的问题
- 嵌入式菜单LCD简单版
- 电脑显示nt服务器发生错误,Windows NT常见问题(一)
- 开启Fluter基础之旅三-------Material Design风格组件、Cupertino风格组件、Flutter页面布局篇...
- 【实用】一套专业的人员定位系统应该如何选择硬件设备?
- LA@分块矩阵@初等变换@初等矩阵#逆矩阵计算@初等变换法
- XCP协议系列介绍01-看了就会的XCP协议
热门文章
- Codeforces Round #628 (Div. 2) F. Ehab‘s Last Theorem dfs树
- 【杭电多校2020】Fibonacci Sum【斐波拉契通项】【推式子】
- 牛客练习赛74 E CCA的期望(算概率的技巧+floyd处理)
- GCD HDU - 1695
- P4159 [SCOI2009] 迷路
- acwing 327. 玉米田
- AT2070-[ARC061D]3人でカードゲーム/Card Game for Three【计数,组合数学】
- jzoj5353-村通网【最小生成树】
- jzoj1265-Round Numbers【数位统计】
- 读上瘾-让用户养成习惯