这篇文章将为大家详细讲解有关ZooKeeper怎么启动,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。ZooKeeper 是 Apache 软件基金会的一个软件项目,它为大型分布式计算提供开源的分布式配置服
这篇文章将为大家详细讲解有关ZooKeeper怎么启动,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
ZooKeeper 是 Apache 软件基金会的一个软件项目,它为大型分布式计算提供开源的分布式配置服务、同步服务和命名注册ZooKeeper 的架构通过冗余服务实现高可用性。Zookeeper 的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。
ZooKeeper服务的启动方式分为三种,即单机模式、伪分布式模式、分布式模式,这里针对三种模式均做逐一讲解。
Tips
调试过程建议尽量使用分布式模式,单机模式不推荐在生产环境下使用,伪分布式模式实质上是在一个进程内派生多个线程模拟分布式形态,由于操作系统的内部结构设计,容易造成一些问题,建议与其解决问题不如切换到分布式模式。生产环境下建议一定采用分布式模式,如果机器不够,推荐采用虚拟机方式。
采用单机模式,意味着只有一台机器或者一个节点,因此流程较为简单。首先,在conf目录下面可以通过自己创建zoo.cfg文件的方式完成ZooKeeper的配置,如清单1-7所示,ZooKeeper服务会读取该配置文件,具体的读取代码会在第四章介绍。
注意,ZooKeeper自带了zoo_sample.cfg文件,这个是配置文件的模板文件,可以打开看看具体的内容,也可以作为zoo.cfg的创建内容范例。
清单1-7 ZooKeeper配置文件
[root@localhost zookeeper-3.4.7]# cd conf[root@localhost conf]# ls -rlttotal 12-rw-rw-r--. 1 1000 1000 922 Nov 1022:32 zoo_sample.cfg-rw-rw-r--. 1 1000 1000 2161 Nov 10 22:32 log4j.properties-rw-rw-r--. 1 1000 1000 535 Nov 1022:32 configuration.xsl[root@localhost conf]# cat zoo_sample.cfg# The number of milliseconds of each ticktickTime=2000# The number of ticks that the initial# synchronization phase can takeinitLimit=10# The number of ticks that can pass between# sending a request and getting an acknowledgementsyncLimit=5# the directory where the snapshot is stored.# do not use /tmp for storage, /tmp here is just# example sakes.dataDir=/tmp/zookeeper# the port at which the clients will connectclientPort=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
上面是自带的示例配置,与我们相关的三个配置项是tickTime、dataDir和clientPort。
tickTime:这个参数主要是用来针对ZooKeeper服务端和客户端的会话控制,包括心跳控制,一般来说,会话超时时间是该值的两倍,它的单位是毫秒,我们设置为2000毫秒。
dataDir:这个目录用来存放数据库的镜像和操作数据库的日志。注意,如果这个文件夹不存在,需要手动创建一个并赋予读写权限,我们设置为/tmp/zookeeper,不用手动创建这个文件夹,系统运行后会自动创建或覆盖。
clientPort:ZooKeeper服务端监听客户端的端口,默认是2181,这里沿用默认设置。
接下来通过bin目录下面的zkServer.sh脚本启动ZooKeeper服务,如果不清楚具体参数,可以直接调用脚本查看输出,如清单1-8所示。
Tips
ZooKeeper采用的是Bourne shell。Shell基本上是一个命令解释器,类似于DOS下的command。它接收用户命令(如ls等),然后调用相应的应用程序。较为通用的shell有标准的Bourne shell、C shell和Korn shell。
清单1-8 调用zkServer.sh脚本
[root@localhost bin]# ./zkServer.shZooKeeper JMX enabled by defaultUsing config: /home/zhoumingyao/zookeeper/zookeeper-3.4.7/bin/../conf/zoo.cfgUsage: ./zkServer.sh{start|start-foreground|stop|restart|status|upgrade|print-cmd}
输出中可以看到有start等选项,具体每个选项的意义我们放在第四章解释,这里先启动ZooKeeper服务,如清单1-9所示。
清单1-9 启动ZooKeeper
[root@localhost bin]# ./zkServer.sh startZooKeeper JMX enabled by defaultUsing config:/home/zhoumingyao/zookeeper/zookeeper-3.4.7/bin/../conf/zoo.cfgStarting zookeeper ... STARTED
ZooKeeper服务是否启动成功,可以通过ps或者jps命令查看,如清单1-10所示。
清单1-10 查看ZooKeeper服务
[root@localhost bin]# jps2737 QuorumPeerMain2751 Jps[root@localhost bin]# ps -ef | grep zookeeper | grep -v grep | awk '{print$2}'2608
这里我们看到的进程号为2737的进程QuorumPeerMain代表了ZooKeeper服务。我们也可以通过ZooKeeper启动脚本自带的参数“Status”来查看ZooKeeper进程状态,如清单1-11所示。
清单1-11 查看ZooKeeper进程状态
[root@localhost bin]# ./zkServer.sh statusZooKeeper JMX enabled by defaultUsing config:/home/zhoumingyao/zookeeper/zookeeper-3.4.7/bin/../conf/zoo.cfgMode: standalone
ZooKeeper服务运行以后我们可以通过命令行工具去访问它,默认是Java命令行脚本。我们可以通过以下命令方式启动ZooKeeper命令行Shell,运行输出如清单1-12所示。
清单1-12 ZKCli运行输出
[root@localhost bin]# ./zkCli.sh -server localhost:2181Connecting to localhost:21812015-12-20 23:22:10,620 [myid:] - INFO [main:Environment@100] - Clientenvironment:zookeeper.version=3.4.7-1713338, built on 11/09/2015 04:32 GMT2015-12-20 23:22:10,645 [myid:] - INFO [main:Environment@100] - Client environment:host.name=localhost2015-12-20 23:22:10,645 [myid:] - INFO [main:Environment@100] - Client environment:java.version=1.8.0_512015-12-20 23:22:10,657 [myid:] - INFO [main:Environment@100] - Client environment:java.vendor=oracleCorporation2015-12-20 23:22:10,658 [myid:] - INFO [main:Environment@100] - Clientenvironment:java.home=/usr/lib/jdk1.8.0_51/jre2015-12-20 23:22:10,658 [myid:] - INFO [main:Environment@100] - Client environment:java.class.path=/home/zhoumingyao/zookeeper/zookeeper-3.4.7/bin/../build/classes:/home/zhoumingyao/zookeeper/zookeeper-3.4.7/bin/../build/lib/*.jar:/home/zhoumingyao/zookeeper/zookeeper-3.4.7/bin/../lib/slf4j-log4j12-1.6.1.jar:/home/zhoumingyao/zookeeper/zookeeper-3.4.7/bin/../lib/slf4j-api-1.6.1.jar:/home/zhoumingyao/zookeeper/zookeeper-3.4.7/bin/../lib/Netty-3.7.0.Final.jar:/home/zhoumingyao/zookeeper/zookeeper-3.4.7/bin/../lib/log4j-1.2.16.jar:/home/zhoumingyao/zookeeper/zookeeper-3.4.7/bin/../lib/jline-0.9.94.jar:/home/zhoumingyao/zookeeper/zookeeper-3.4.7/bin/../zookeeper-3.4.7.jar:/home/zhoumingyao/zookeeper/zookeeper-3.4.7/bin/../src/java/lib/*.jar:/home/zhoumingyao/zookeeper/zookeeper-3.4.7/bin/../conf:2015-12-20 23:22:10,660 [myid:] - INFO [main:Environment@100] - Clientenvironment:java.library.path=/usr/java/packages/lib/i386:/lib:/usr/lib2015-12-20 23:22:10,665 [myid:] - INFO [main:Environment@100] - Client environment:java.io.tmpdir=/tmp2015-12-20 23:22:10,665 [myid:] - INFO [main:Environment@100] - Client environment:java.compiler=2015-12-20 23:22:10,666 [myid:] - INFO [main:Environment@100] - Client environment:os.name=linux2015-12-20 23:22:10,666 [myid:] - INFO [main:Environment@100] - Client environment:os.arch=i3862015-12-20 23:22:10,667 [myid:] - INFO [main:Environment@100] - Clientenvironment:os.version=2.6.32-504.el6.i6862015-12-20 23:22:10,668 [myid:] - INFO [main:Environment@100] - Client environment:user.name=root2015-12-20 23:22:10,668 [myid:] - INFO [main:Environment@100] - Client environment:user.home=/root2015-12-20 23:22:10,668 [myid:] - INFO [main:Environment@100] - Clientenvironment:user.dir=/home/zhoumingyao/zookeeper/zookeeper-3.4.7/bin2015-12-20 23:22:10,693 [myid:] - INFO [main:ZooKeeper@438] - Initiating client connection,connectString=localhost:2181 sessionTimeout=30000watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@b07fd3Welcome to ZooKeeper!2015-12-20 23:22:10,953 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1032] - OpeningSocket connection to server localhost/0:0:0:0:0:0:0:1:2181. Will not attempt toauthenticate using SASL (unknown error)JLine support is enabled2015-12-20 23:22:11,342 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@876] - Socketconnection established to localhost/0:0:0:0:0:0:0:1:2181, initiating session2015-12-20 23:22:11,672 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1299] - Sessionestablishment complete on server localhost/0:0:0:0:0:0:0:1:2181, sessionid =0x151c241c15b0000, neGotiated timeout = 30000WATCHER::WatchedEvent state:SyncConnected type:None path:null[zk: localhost:2181(CONNECTED) 0]
光标停留在[zk: localhost:2181(CONNECTED) 0]这一行,我们可以通过help请求来查看所有的支持命令,如清单1-13所示。
清单1-13 ZKCli help命令
[zk: localhost:2181(CONNECTED) 0] helpZooKeeper -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 dataacl addauth scheme auth quit getAcl path close connect host:port
关于ZKCli命令我们会在后续章节详细解释,这里只做一个简单的演示,我们可以使用类似于Linux的ls命令打印ZooKeeper内部Znode列表,如清单1-14所示。 清单1-14 打印ZNode列表
[zk: localhost:2181(CONNECTED) 1] ls /[zookeeper]
上面示例返回一个字符串zookeeper,这是一个ZooKeeper的ZNode(ZooKeeper术语),我们可以通过脚本创建一个ZNode,如清单1-15所示。
清单1-15 创建一个ZNode
[zk: localhost:2181(CONNECTED) 3] create /HelloWorld ""Created /HelloWorld[zk: localhost:2181(CONNECTED) 4] ls /[zookeeper, HelloWorld]
上面演示了如何启动单机模式,现在我们来演示设置伪分布式模式。
我们可以在一台机器上创建模拟的ZooKeeper集群服务,假如我们需要3个节点,需要创建3个cfg文件,分别命名为zoo1.cfg,zoo2.cfg,zoo3.cfg,此外我们还需要创建3个不同的数据文件夹,分别是zoo1,zoo2和zoo3,目录位于/var/lib/zookeeper,如1-16、1-17和1-18三个配置清单所示。
清单1-16 配置文件zoo1内容
[root@localhost conf]# cat zoo1.cfg# The number of milliseconds of each ticktickTime=2000# The number of ticks that the initial# synchronization phase can takeinitLimit=10# The number of ticks that can pass between# sending a request and getting an acknowledgementsyncLimit=5# the directory where the snapshot is stored.# do not use /tmp for storage, /tmp here is just# example sakes.dataDir=/var/lib/zookeeper/zoo1# the port at which the clients will connectclientPort=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=1server.1=localhost:2666:3666server.2=localhost:2667:3667server.3=localhost:2668:3668
清单1-17 配置文件zoo2内容
[root@localhost conf]# cat zoo2.cfg# The number of milliseconds of each ticktickTime=2000# The number of ticks that the initial# synchronization phase can takeinitLimit=10# The number of ticks that can pass between# sending a request and getting an acknowledgementsyncLimit=5# the directory where the snapshot is stored.# do not use /tmp for storage, /tmp here is just# example sakes.dataDir=dataDir=/var/lib/zookeeper/zoo2# the port at which the clients will connectclientPort=2182# 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=1server.1=localhost:2666:3666server.2=localhost:2667:3667server.3=localhost:2668:3668
清单1-18 配置文件zoo3内容
[root@localhost conf]# cat zoo3.cfg# The number of milliseconds of each ticktickTime=2000# The number of ticks that the initial# synchronization phase can takeinitLimit=10# The number of ticks that can pass between# sending a request and getting an acknowledgementsyncLimit=5# the directory where the snapshot is stored.# do not use /tmp for storage, /tmp here is just# example sakes.dataDir=/var/lib/zookeeper/zoo3# the port at which the clients will connectclientPort=2183# 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=1server.1=localhost:2666:3666server.2=localhost:2667:3667server.3=localhost:2668:3668
注意,每一个虚拟机器都对应一个自己的zoo{$}.cfg,其中的{$}需要通过清单1-19所示命令来进行设置。
Tips
由于采用的是“>”,所以命令会创建文件,如果采用“>>”,则Linux会在原有文件基础上新增内容。
清单1-19 设置myid
[root@localhost conf]# echo 1 > /var/lib/zookeeper/zoo1/myid[root@localhost conf]# echo 2 > /var/lib/zookeeper/zoo2/myid[root@localhost conf]# echo 3 > /var/lib/zookeeper/zoo3/myid
接下来我们开始启动ZooKeeper的3个实例(虚拟的3台机器),需要调用三次zkServer.sh的Start命令,采用不同的配置文件,如清单1-20所示命令及输出。
清单1-20 启动伪分布式集群服务
[root@localhost bin]# ./zkServer.sh start/home/zhoumingyao/zookeeper/zookeeper-3.4.7/conf/zoo1.cfgZooKeeper JMX enabled by defaultUsing config: /home/zhoumingyao/zookeeper/zookeeper-3.4.7/conf/zoo1.cfgStarting zookeeper ... STARTED[root@localhost bin]# ./zkServer.sh start/home/zhoumingyao/zookeeper/zookeeper-3.4.7/conf/zoo2.cfgZooKeeper JMX enabled by defaultUsing config: /home/zhoumingyao/zookeeper/zookeeper-3.4.7/conf/zoo2.cfgStarting zookeeper ... STARTED[root@localhost bin]# ./zkServer.sh start/home/zhoumingyao/zookeeper/zookeeper-3.4.7/conf/zoo3.cfgZooKeeper JMX enabled by defaultUsing config: /home/zhoumingyao/zookeeper/zookeeper-3.4.7/conf/zoo3.cfgStarting zookeeper ... STARTED
清单1-21 查看服务
[root@localhost bin]# jps5537 QuorumPeerMain5617 Jps5585 QuorumPeerMain
确认服务都正常启动,我们就可以通过zkCli.sh脚本方式连接到ZooKeeper集群,命令为./zkCli.sh -server localhost:2181,localhost:2182,localhost:2183,效果和单机模式一样。
由于ZooKeeper单机模式不支持单点失败保护,所以不推荐在生产环境下使用。
ZooKeeper有另外一种支持多台机器的模式,即真正的分布式模式,这多台包含在一个应用体内的集群机器被称为quorum,这些机器最小配置为3台,最佳配置为5台,其中包含1台Leader(领导者)机器,由5台机器内部选举产生,另外4台机器就立即成为Follower(跟随者)机器,一旦Leader宕机,剩余的Follower就会重新选举出Leader。
从配置文件内部的字段定义上来说,分布式模式的ZooKeeper与单机模式的ZooKeeper有一些差距,例如下面三个字段:
Ø initLimit:follower对于Leader的初始化连接timeout时间;Ø syncLimit:follower对于Leader的同步timeout时间;Ø timeout的计算公式是initLimit*tickTime,syncLimit*tickTime。
此外,我们需要把组成quorum的所有机器也都列在这个配置文件里面。假设我们有两个端口,第一个端口2889用于Follower和Leader之间的通信,通信方式是采用tcp方式,第二个端口3889是为选举Leader用的,用于quorum内部的Leader选举响应。那么我们配置文件如清单1-22所示。
清单1-22 分布式模式配置文件
server.1=node1:2889:3889server.2=node2:2889:3889server.3=node3:2889:3889
注意,分布式模式也需要设置myid,这个和伪分布式模式基本一样,只需要在每一台机器上实现一个myid,例如第一台机器是1,第二台机器上设置为2,第三台机器上设置为3,以此类推。
分布式模式的启动方式和单机唯一的差距是每一台机器上都需要启动ZooKeeper服务,即运行命令./zkServer.sh start。
ZooKeeper服务端运行后,我们可以通过在每台机器上运行./zkServer.sh status来查看选举结果,其中Follower节点的运行结果如清单所示,Leader节点的运行结果如清单1-23所示。
清单1-23 Follower节点的运行结果
[root@node3 bin]# ./zkServer.sh statusJMX enabled by defaultUsing config: /usr/lib/zookeeper-3.4.6/bin/../conf/zoo.cfgMode: follower
清单1-24 Leader节点的运行结果
[root@node2 bin]# ./zkServer.sh statusJMX enabled by defaultUsing config: /usr/lib/zookeeper-3.4.6/bin/../conf/zoo.cfgMode: leader
差距就在于Mode这一栏。接下来可以通过zkCli命令行访问ZooKeeper服务,假如我们访问node2节点,如清单1-25所示。
清单1-25 访问ZooKeeper服务及输出
[root@localhost bin]# ./zkCli.sh -server node2:2182Connecting to node2:21822016-01-19 16:15:06,702 [myid:] - INFO [main:Environment@100] - Clientenvironment:zookeeper.version=3.4.7-1713338, built on 11/09/2015 04:32 GMT2016-01-19 16:15:06,710 [myid:] - INFO [main:Environment@100] - Client environment:host.name=node22016-01-19 16:15:06,710 [myid:] - INFO [main:Environment@100] - Client environment:java.version=1.7.0_792016-01-19 16:15:06,714 [myid:] - INFO [main:Environment@100] - Client environment:java.vendor=OracleCorporation2016-01-19 16:15:06,714 [myid:] - INFO [main:Environment@100] - Client environment:java.home=/usr/lib/jdk1.7.0_79/jre2016-01-19 16:15:06,715 [myid:] - INFO [main:Environment@100] - Clientenvironment:java.class.path=/home/zhoumingyao/zookeeper-3.4.7/bin/../build/classes:/home/zhoumingyao/zookeeper-3.4.7/bin/../build/lib/*.jar:/home/zhoumingyao/zookeeper-3.4.7/bin/../lib/slf4j-log4j12-1.6.1.jar:/home/zhoumingyao/zookeeper-3.4.7/bin/../lib/slf4j-api-1.6.1.jar:/home/zhoumingyao/zookeeper-3.4.7/bin/../lib/netty-3.7.0.Final.jar:/home/zhoumingyao/zookeeper-3.4.7/bin/../lib/log4j-1.2.16.jar:/home/zhoumingyao/zookeeper-3.4.7/bin/../lib/jline-0.9.94.jar:/home/zhoumingyao/zookeeper-3.4.7/bin/../zookeeper-3.4.7.jar:/home/zhoumingyao/zookeeper-3.4.7/bin/../src/java/lib/*.jar:/home/zhoumingyao/zookeeper-3.4.7/bin/../conf:.:/usr/lib/jdk1.7.0_79/lib:/usr/lib/jdk1.7.0_79/jre/lib:2016-01-19 16:15:06,715 [myid:] - INFO [main:Environment@100] - Clientenvironment:java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib2016-01-19 16:15:06,715 [myid:] - INFO [main:Environment@100] - Client environment:java.io.tmpdir=/tmp2016-01-19 16:15:06,715 [myid:] - INFO [main:Environment@100] - Client environment:java.compiler=2016-01-19 16:15:06,716 [myid:] - INFO [main:Environment@100] - Client environment:os.name=Linux2016-01-19 16:15:06,716 [myid:] - INFO [main:Environment@100] - Client environment:os.arch=amd642016-01-19 16:15:06,716 [myid:] - INFO [main:Environment@100] - Clientenvironment:os.version=3.10.0-123.el7.x86_642016-01-19 16:15:06,716 [myid:] - INFO [main:Environment@100] - Client environment:user.name=root2016-01-19 16:15:06,717 [myid:] - INFO [main:Environment@100] - Client environment:user.home=/root2016-01-19 16:15:06,717 [myid:] - INFO [main:Environment@100] - Client environment:user.dir=/home/zhoumingyao/zookeeper-3.4.7/bin2016-01-19 16:15:06,720 [myid:] - INFO [main:ZooKeeper@438] - Initiating client connection,connectString=node2:2182 sessionTimeout=30000watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@5dc6bb75Welcome to ZooKeeper!2016-01-19 16:15:06,774 [myid:] - INFO [main-SendThread(node2:2182):ClientCnxn$SendThread@1032] - Openingsocket connection to server node2/172.10.201.56:2182. Will not attempt toauthenticate using SASL (unknown error)2016-01-19 16:15:06,783 [myid:] - INFO [main-SendThread(node2:2182):ClientCnxn$SendThread@876] - Socketconnection established to node2/172.10.201.56:2182, initiating sessionJLine support is enabled2016-01-19 16:15:06,820 [myid:] - INFO [main-SendThread(node2:2182):ClientCnxn$SendThread@1299] - Sessionestablishment complete on server node2/172.10.201.56:2182, sessionid =0x25258f06e1f0000, negotiated timeout = 30000WATCHER::WatchedEvent state:SyncConnected type:None path:null[zk: node2:2182(CONNECTED) 0] helpZooKeeper -server host:port cmd args connect host:port get path [watch] ls path [watch] set path data [version] rmr path delquota [-n|-b] path quit printwatches on|off create [-s] [-e] path dataacl stat path [watch] close ls2 path [watch] history listquota path setAcl path acl getAcl path sync path redo cmdno addauth scheme auth delete path [version] setquota -n|-b val path[zk: node2:2182(CONNECTED) 1]
关于“ZooKeeper怎么启动”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
--结束END--
本文标题: ZooKeeper怎么启动
本文链接: https://lsjlt.com/news/311199.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0