IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> zookeeper 使用规范 -> 正文阅读

[大数据]zookeeper 使用规范

重要参数说明与配置

参数/参数类别是否java环境变量描述默认值
Minimum Configuration
clientPort监听客户端端口
dataDirzk快照路径
tickTime时间单元,以毫秒为单位,用于心跳和超时,举个例子最小session过期是2个ticks
Advanced Configuration
dataLogDir事务日志路径
globalOutstandingLimitzookeeper.globalOutstandingLimitzk请求的缓存队列大小,避免zk oom
preAllocSizezookeeper.preAllocSizesnapshots预分配大小64m
snapCountzookeeper.snapCount记录snapCount条事务到日志文件以后开始创建新的快照和事物日志

traceFile

requestTraceFile

当定义这个属性后会记录debug日志,但会影响性能

不设置
maxClientCnxns限制每个ip的最大连接数,如不限制果设置为0代表不限制60
clientPortAddress暴露给客户端的端口
minSessionTimeoutsession过期最小周期,与tickTime关联2
maxSessionTimeoutsession过期最小周期,与tickTime关联20
fsync.warningthresholdmsfsync.warningthresholdms事务日志同步时间阀值,超出会有warn日志
autopurge.snapRetainCount保留最近数量的snapshots和transaction logs
autopurge.purgeInterval清理任务触发的时间间隔,为正整数
syncEnabledzookeeper.observer.syncEnabledThe observers now log transaction and write snapshot to disk by default like the participants. This reduces the recovery time of the observers on restart. Set to "false" to disable this feature. Default is "true"

Cluster Options

electionAlg

0:the original UDP-based version,udp基础版本

1:the non-authenticated UDP-based version of fast leader election,无认证fast-leader的udp版本

2:the authenticated UDP-based version of fast leader election,认证fast-leader的udp版本

3:TCP-based version of fast leader election,tcp?fast-leader基础版本

1
initLimitto allow followers to connect and sync to a leader,允许从连接主的最大时间
leaderServeszookeeper.leaderServesleader是否允许接受客户端连接yes
server.x=[hostname]:nnnnn[:nnnnn]

The first followers use to connect to the leader, and the second is for leader election,

第一个端口为从连接主的端口,第二个端口为选举端口

syncLimit

to allow followers to sync with ZooKeeper. If followers fall too far behind a leader, they will be dropped.

允许从同步主的最大时间,如果从远落后于主,会被提出集群

group.x=nnnnn[:nnnnn]Enables a hierarchical quorum construction."x" is a group identifier and the numbers following the "=" sign correspond to server identifiers. The left-hand side of the assignment is a colon-separated list of server identifiers. Note that groups must be disjoint and the union of all groups must be the ZooKeeper ensemble.
weight.x=nnnnn

Such a value corresponds to the weight of a server when voting,选举投票的权重

1
cnxTimeoutzookeeper.cnxTimeout

Sets the timeout value for opening connections for leader election notifications. Only applicable if you are using electionAlg 3.

设置leader选举时建立连接的超时时间,只有electionAlg为3时生效

服务端推荐配置

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/ccdata/zookeeper/data
dataLogDir=/ccdata/zookeeper/logs
clientPort=15311
server.1=ip:15312:15313
server.2=ip:15312:15313
server.3=ip:15312:15313
maxClientCnxns=100

zk运维

zk四字命令

四字命令

作用描述

执行示例

conf打印机器配置信息echo?conf?| nc 10.0.10.21 15311

clientPort=15311
dataDir=/ccdata/zookeeper/data/version-2
dataLogDir=/ccdata/zookeeper/logs/version-2
tickTime=6000
maxClientCnxns=800
minSessionTimeout=12000
maxSessionTimeout=120000
serverId=1
initLimit=10
syncLimit=5
electionAlg=3
electionPort=15313
quorumPort=15312
peerType=0

cons打印session和连接信息echo?cons?| nc 10.0.10.21 15311

/10.0.10.61:52360[1](queued=0,recved=30228,sent=30270,sid=0x16f9daff9bc0b9e,

lop=PING,est=1581665511287,to=60000,lcxid=0x216

,lzxid=0xffffffffffffffff,lresp=1582266376218,llat=0,minlat=0,avglat=0,maxlat=303)

crst重置所有连接的连接/会话统计信息echo?crst?| nc 10.0.10.21 15311Connection stats reset.
dump打印session和临时节点信息,仅主节点生效echo?dump?| nc 10.0.10.21 15311

SessionTracker dump:
org.apache.zookeeper.server.quorum.LearnerSessionTracker@38ac995f
ephemeral nodes dump:
Sessions with Ephemerals (300):
0x36e450ca29e00fc:

envi打印环境变量echo?envi?| nc 10.0.10.21 15311

Environment:
zookeeper.version=3.4.8--1, built on 02/06/2016 03:18 GMT
host.name=vpc-dev01-basic01
java.version=1.8.0_121
java.vendor=Oracle Corporation
java.home=/opt/src/jdk1.8.0_121/jre

ruok检查机器运行是否正常,正常返回imokecho?ruok?| nc 10.0.10.21 15311imok
srst重置服务统计信息echo?srst?| nc 10.0.10.21 15311Server stats reset.
srvr列出服务详细信息echo?srvr?| nc 10.0.10.21 15311

Zookeeper version: 3.4.8--1, built on 02/06/2016 03:18 GMT
Latency min/avg/max: 0/0/16
Received: 2206
Sent: 2244
Connections: 311
Outstanding: 0
Zxid: 0x24009ff0ac
Mode: follower
Node count: 127807

stat列出服务和简要连接信息echo?stat?| nc 10.0.10.21 15311

Zookeeper version: 3.4.8--1, built on 02/06/2016 03:18 GMT
Clients:
/10.0.10.61:52360[1](queued=0,recved=19,sent=19)
/10.0.10.42:58180[1](queued=0,recved=38,sent=38)
/10.0.10.53:55470[1](queued=0,recved=18,sent=18)

wchs列出服务器watches的简洁信息:连接总数、watching节点总数和watches总数echo?wchs?| nc 10.0.10.21 15311

207 connections watching 62843 paths
Total watches:12988

wchc列出每个session详细watches,注意 开销很大,慎用echo?wchc?| nc 10.0.10.21 15311

0x26e450c8abb4b75
/dubbo/com.caocao.api.service.DictionaryServiceApi/configurators
/dubbo/com.caocao.authcenter.api.CityQueryApi/configurators
/dubbo/com.caocao.api.service.BaseConfigApi/configurators
/dubbo/com.caocao.api.service.RuleServiceApi/configurators
/dubbo/com.caocao.bss.authserver.api.ExcelServiceApi/configurators

wchp列出每个路径的watches,慎用echo?wchp?| nc 10.0.10.21 15311

/dubbo/com.caocao.dic.api.marketing.MarketingServiceApi/providers
0x16f9daff9bcbc44
0x26e450c8abb29c4
0x16f5cdede03000d

mntr列出zk的一些指标,可用来检查zk的健康情况echo?mntr?| nc 10.0.10.21 15311

echo mntr | nc 10.0.10.21 15311

zk_version 3.4.8--1, built on 02/06/2016 03:18 GMT
zk_avg_latency 11
zk_max_latency 3896
zk_min_latency 0
zk_packets_received 30504
zk_packets_sent 33556
zk_num_alive_connections 313
zk_outstanding_requests 0
zk_server_state follower
zk_znode_count 127841
zk_watch_count 251483
zk_ephemerals_count 5294
zk_approximate_data_size 18371860
zk_open_file_descriptor_count 342
zk_max_file_descriptor_count 10240

需要避免的事项

一致性zk列表:

1)、客户端在使用的时候尽量写全整个zk集群列表,ps 如果只写一个子集也能正常使用,

2)、服务端的zk集群的各个服务配置必须保证一致

不正确的事务日志存放:

1)、尽量不要把事务日志放在io频繁的数据盘上,会影响zk的性能,有条件可以放多个数据盘

不合适的java堆大小:

不正确的堆内存设置

1)、如果机器只有4g,最大堆内存不要设置成4g或者更大,也许3g较合适,需要考虑系统对内存的使用情况,尤其是混部的时候

zk节点

Watches

zookeeper所有读操作(getData(),getChildren(),exists())具有设置watch的选项。
zookeeper watch的定义如下:watch事件是一次性触发器,当watch监视的数据发生变化时,通知设置了该watch的client,即watcher。

需要注意三点:

1.一次性触发器
client在一个节点上设置watch,随后节点内容改变,client将获取事件。当节点内容再次改变,client不会获取这个事件,除非它又执行了一次读操作并设置watch

2.发送至client,watch事件延迟
watch事件异步发送至观察者。比如说client执行一次写操作,节点数据内容发生变化,操作返回后,而watch事件可能还在发往client的路上。这种情况下,zookeeper提供有序保证:client不会得知数据变化,直到它获取watch事件。网络延迟或其他因素可能导致不同client在不同时刻获取watch事件和操作返回值。

3.设置watch的数据内容
涉及到节点改变的不同方式。比方说zookeeper维护两个watch列表:节点的数据watch和子节点watch。getData()和exists()设置了内容watch,getChildren()设置了子节点watch,操作返回的数据类型不同,前者是节点的内容,后者是节点的子节点列表。setData()触发内容watch,create()触发当前节点的"内容watch"和其父节点的"子节点watch",delete()同时触发"内容watch"和"子节点watch"(其子节点被全部删除),以及其父节点的"子节点watch"。说白了,对当前节点的操作,要考虑到对其父节点与子节点的影响

watch在客户端所连接的服务端本地维护。watch的设置、维护、分发操作都很轻量级。当客户端连接到新的服务端,watch将被任一会话事件触发。与服务端断开连接时,不能获取watch事件。客户端重连后,之前注册的watch将被重新注册并在需要时触发。通常这一切透明地发生,用户不会察觉到。有一种情况watch可能丢失:之前对一个尚未建立的节点的设置了exists watch,如果断开期间该节点被建立或删除,那么此watch将丢失

对于watch,zookeeper提供以下保证:
1.watch对于其他事件、watch、异步响应是有序的。zookeeper client library保证有序分发
2.客户端监视一个节点,总是先获取watch事件,再发现节点的数据变化。
3.watch事件的顺序对应于zookeeper服务所见的数据更新的顺序。

关于watch要记住的是:
1.watch是一次性触发的,如果获取一个watch事件并希望得到新变化的通知,需要重新设置watch
2.watch是一次性触发的并且在获取watch事件和设置新watch事件之间有延迟,所以不能可靠的观察到节点的每一次变化。要认识到这一点。
3.watch object只触发一次,比如,一个watch object被注册到同一个节点的getData()和exists(),节点被删除,仅对应于exists()的watch ojbect被调用
4.若与服务端断开连接,直到重连后才能获取watch事件。

Data Access

...

Ephemeral Nodes

zk临时节点,存活于session,当session断开,临时节点会被删除,且临时节点不允许有子节点

Sequence Nodes -- Unique Naming

zk序列节点,会在节点的尾部添加单调递增计数的路径,这个计数对于父节点是唯一的,10位数字,以0补齐

Time in ZooKeeper

zk多纬度跟踪时间,

zxid:zk事务id,任何zk状态变化都会更新,意味着zk变更的顺序

version number:每个节点的改变版本都会递增,共三个类型,version:节点的变更版本;cversion:自节点变更的版本;aversion:acl变更的版本

ticks:zk的时间单位,例如最小session过期时间是2个ticks

Real time:zk只在在zk stat structure用真实时间

ZooKeeper Stat Structure

  • czxid

    The zxid of the change that caused this znode to be created.

  • mzxid

    The zxid of the change that last modified this znode.

  • ctime

    The time in milliseconds from epoch when this znode was created.

  • mtime

    The time in milliseconds from epoch when this znode was last modified.

  • version

    The number of changes to the data of this znode.

  • cversion

    The number of changes to the children of this znode.

  • aversion

    The number of changes to the ACL of this znode.

  • ephemeralOwner

    The session id of the owner of this znode if the znode is an ephemeral node. If it is not an ephemeral node, it will be zero.

  • dataLength

    The length of the data field of this znode.

  • numChildren

    The number of children of this znode.

  • 只有一种情况需要我们手动

session会话

使用客户端来创建一个和zk服务端连接的句柄,这就是一个会话(session)。Session一旦建立,状态就是连接中(CONNECTING)状态,然后客户端会尝试去连接zk服务端,连接成功之后状态变成已连接(CONNECTED)。一般正常情况下只会有这两个状态。不过,还是会发生一些无法恢复的错误/故障,比如:session过期,认证失败,或者客户端关闭连接,这种情况下,session状态会变成关闭(CLOSED)状态。下图给出了zk客户顿可能的状态转换情况:

以下内容是介绍zk的特性,不过很多是结合代码来描述

为了创建一个session,代码中必须要提供一个连接字符串,连接字符串由host:port组成,用,分割,例如127.0.0.1:4545,127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002。zk客户端会随意选择一个zk服务端来尝试连接。如果这个连接失败了,或者因为某种原因断开连接了,客户端会自动尝试下一个服务端,直到连接被成功建立。

3.2.0新特性:连接字符串增加了一个chroot后缀。意思就是所有操作的节点路径都是这个路径下的相对路径(类似unix的chroot命令)。举个例子,127.0.0.1:4545/app/a,127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002/app/a,这种情况下,你访问的/foo/bar节点,其实是zk服务端的/app/a/foo/bar节点。如果你的zk服务端是多应用共享的,这个特性应该会很适合你,因为可以很清晰的隔离开各个应用的数据。

当一个session建立的时候,zk服务端会生成一个64位的数字,也就是这个session的标识(姑且称之为session id吧),zk客户端会保存这个标识。如果zk客户端因为某种原因连接到了另一个zk服务端,他会把这个session id传给新的服务端。出于安全考虑,zk服务端在创建连接时,不仅仅生成一个session id,还会同时传给zk客户端一个密码,这个session id+密码是可以被任何一个zk服务端校验的。这样,每次zk客户端重连zk服务端的时候,会同时传递session id+密码,zk服务端校验通过了才会建立连接。

为什么需要密码呢?
随便举个例子,znode的权限是和session有关联的,如果任何客户端都可以伪造session id,那这种安全性就没有意义了。

使用zk客户端创建session的一个参数是session超时时间(毫秒)。但是请注意,这个session超时时间并不是客户端可以随意设置的。zk客户端会把这个session超时时间发给服务端,服务端会返回一个他可以接受的值给客户端。标准其实就是tickTime*2 <= session timeout <= tickTime*20。

如果zk客户端和zk服务端集群断开连接之后,在session超时时间之内,重新连接上了,那么session状态重新变为connected,如果在session超时时间之内没有连接上,那么session状态会变成expired。当session断开连接的时候,最好不用自己去建立一个新的session,因为zk客户端已经帮我做了这个工作,他会自动重连的。只有一种情况需要我们手动重新创建新的session,那就是明确知道session状态为过期状态(expiration)

session是否过期是由zk服务端集群管理的,而不是zk客户端自己管理自己是否过期。zk服务端就是根据session过期时间来判断是否过期。当zk服务端超过一定的时间没有收到来自zk客户端的心跳,zk服务端就把这个session标记为过期,然后删除这个session创建的所有临时节点,并且立刻通知所有监听了这些节点的其他session。在这个时候,zk客户端处于断开连接的状态,一旦它重新连接成功了,他也会收到自己被标记为过期这一事件提醒;在还没有重新连接成功之前,这个zk客户端是不会收到过期的提醒的。

下面举个例子来形象的展示一下上面说的:

connected:session被创建,客户端和服务端正常通信。
……客户端和服务端断开连接。
disconnected:客户端和服务端失去连接。
……随着时间的流逝,超过了session的超时时间,客户端还没有重新连接成功。
……随着时间的流逝,客户端重新连接上了服务端。
expired:最后客户端连接上了服务端,但是之前的session已经被过期了,客户端也会收到过期的事件提醒。
3.2.0 – SessionMovedException:这是一个内部异常,一般不会被应用程序接触到。这个异常发生的情况比较少见,举个例子吧,当一个客户端发一个心跳请求个服务端,但是网络延时,导致服务端没有收到,过一会后,客户端连接上了另一个新的服务端,在这之后,之前的心跳被旧的服务端收到了,这时候旧的服务端会被提醒,当前session已经被转移了,然后旧的服务端会关闭这个连接。客户端一般不会感知到这个异常,因为旧连接一般都会被关闭。但是还有一个特殊情况,两个客户端同时使用保存这的session id+密码来重新连接服务端,第一个连接成功,紧着第二个又连接成功,这会导致第一个连接被关闭,然后就是这两个客户端无限重连了。

更新服务器列表,zk客户端可以使用一个新的连接字符串来更新服务列表。这个机制会使用一个负载均衡算法来重新平衡各个客户端和服务端的连接情况,所以会导致部分客户端断开连接并重新连接到其他服务端。

举个例子,如果之前的连接字符串包含了3和host,新的连接字符串除了之前的3个host还多出了2个新的host,那么会有40%的客户端需要断开连接来连接新的3个服务端,以保持负载均衡。就意味着这40%的客户端需要断开重连。

同样的道理,如果原本有5个host,新的只有3个,也就是移除了2个,那么那移除的2个服务端对应的客户端都会被断开,需要重新连接到3个服务端上。


?

zk特性

Guarantees ZooKeeper is very fast and very simple. Since its goal, though, is to be a basis for the construction of more complicated services, such as synchronization, it provides a set of guarantees. These are: zk为构建一致性系统服务,例如同步系统

Sequential Consistency - Updates from a client will be applied in the order that they were sent. 顺序一致性,更新数据通过客户端发送请求的顺序

Atomicity - Updates either succeed or fail. No partial results. 原子性,更新要么成功要么失败

Single System Image - A client will see the same view of the service regardless of the server that it connects to. 单一系统镜像,客户端看到的同一个版本视图保证一致

Reliability - Once an update has been applied, it will persist from that time forward until a client overwrites the update. 可靠性,保证数据第一次写入到下次更新时数据保持不变

Timeliness - The clients view of the system is guaranteed to be up-to-date within a certain time bound. 及时性,保证系统的客户端视图在一定时间内是最新的

zk api

create creates a node at a location in the tree

delete deletes a node

exists tests if a node exists at a location

get data reads the data from a node

set data writes data to a node

get children retrieves a list of children of a node

sync waits for data to be propagated

implementation

all write requests from clients are forwarded to a single server, called the leader. The rest of the ZooKeeper servers, called followers, receive message proposals from the leader and agree upon message delivery leader接收写消息 follow接受leader的消息,并做消息传递

The programming interface to ZooKeeper is deliberately simple. With it, however, you can implement higher order operations, such as synchronizations primitives, group membership, ownership

官方对zk性能的评估

参考:http://zookeeper.apache.org/doc/r3.4.8/zookeeperOver.html#fg_zkPerfRW?

读:写 20% tps:2w 50% rps4w 80% tps:6w

当读写比在30%,当follwer挂掉后马上恢复,zk能恢复到之前的吞吐量 一般zk选举可以在200ms选出一个主

解决zk大量连接问题-zk观察者模式

观察者的设计是希望能动态扩展zookeeper集群又不会降低写性能。

虽然通过让客户端直接连接到集群的投票成员,ZooKeeper也表现得非常好,但是这种架构使得很难扩展到有大量的客户端情况。问题是,随着我们添加更多投票成员,写入性能也会随着下降。这是因为写操作需要(通常)需要集群中至少一半的节点投票达成一致,因此随着更多投票者的加入,投票的成本会显著增加。

这里引入一种新zookeeper节点类型,叫做观察者,观察者的引入帮助解决了上面的问题同时大大增加了zookeeper的动态扩展能力。观察者不参与投票,只听取投票结果。除了这个简单的区别,Observers的功能与Followers完全相同 - 客户端可以连接到它们并向它们发送读写请求。Observer会像follower一样将消息转发给leader,但是Observer只会听取投票结果,不参与投票。由于这点,我们可以增加任意数量的Observer,同时不会影响我们集群的性能。

Observer还有其它优点。因为他们不投票,所以他们不是ZooKeeper集群的重要组成部分。 因此,它们可以失败,或者与集群断开连接,而不会损害ZooKeeper服务的可用性。对用户的好处是Observer相比Follower来说更能通过不太可靠的网络链接进行连接。实际上,Observers可用于与另一个数据中心的ZooKeeper服务器通信。Observers的客户端可以快速读取,因为所有读取都在本地提供,并且写入消耗最小的网络流量,因为在没有投票协议的情况下所需的消息数量较少。

zk客户端使用代码

推荐使用:curator

创建连接:

CuratorFrameworkFactory.newClient(zookeeperConnectionString, retryPolicy)

-----------------

RetryPolicy retryPolicy =?new?ExponentialBackoffRetry(1000,?3)

CuratorFramework client = CuratorFrameworkFactory.newClient(zookeeperConnectionString, retryPolicy);

client.start();

创建zk节点:

client.create().forPath("/my/path", myData)

好处:Curator会管理zk连接和重试操作

分布式锁:

InterProcessMutex lock =?new?InterProcessMutex(client, lockPath);

if?( lock.acquire(maxWait, waitUnit) )

{

????try

????{

????????// do some work inside of the critical section here

????}

????finally

????{

????????lock.release();

????}

}

leader选举:

LeaderSelectorListener listener =?new?LeaderSelectorListenerAdapter()

{

????public?void?takeLeadership(CuratorFramework client)?throws?Exception

????{

????????// this callback will get called when you are the leader

????????// do whatever leader work you need to and only exit

????????// this method when you want to relinquish leadership

????}

}

LeaderSelector selector =?new?LeaderSelector(client, path, listener);

selector.autoRequeue();??// not required, but this is behavior that you will probably expect

selector.start();

更多用法:

http://curator.apache.org/curator-examples/index.html

版本情况:

https://cwiki.apache.org/confluence/display/CURATOR/Releases

 

参考

zk管理

http://zookeeper.apache.org/doc/r3.4.8/zookeeperAdmin.html#sc_maintenance

watch:

http://zookeeper.apache.org/doc/r3.4.8/zookeeperProgrammers.html#ch_zkWatches

zk观察者:

http://zookeeper.apache.org/doc/r3.4.14/zookeeperObservers.html

https://zhuanlan.zhihu.com/p/42067231

curator:

http://curator.apache.org/getting-started.html

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-07-24 11:33:51  更:2021-07-24 11:34:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/4 4:22:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码