设为首页 收藏本站
查看: 1013|回复: 0

[经验分享] 支持海量数据的 MongoDB NoSQL

[复制链接]

尚未签到

发表于 2015-7-7 07:38:41 | 显示全部楼层 |阅读模式



关于这个速查卡
  MongoDB是一个文档型数据库,它可以方便的应用于大多数语言。这个小清单列出了MongoDB经常使用和容易忘记的一些操作,命令和技术。

配置选项

安装选项
  启动MongoDB的选项可以通过命令行或者配置文件设置,两者的语法稍微有点不同,这里有一个三种选项的设置例子:

命令行配置文件


--dbpath /path/to/dbdbpath=/path/to/db
--authauth=true
-vvvvvv=true
  在mongod下运行--help可以列出所有的操作选项,但是这里我们列出了一些最常用的:

操作选项描述



--config /path/to/config
指定其他配置选项的配置文件.


--dbpath /path/to/data
数据存储目录.


--port 27017
监听端口号.


--logpath /path/to/file.log
日志输出文件,这是个明确的文件路径,不是目录.


--logappend
重启后,以追加的方式创建日志防止把之前的日志删除了。在使用--logpath时总是开启.


--fork
把mongod配置为守护进程.


--auth
单个服务器的安全验证.


--keyFile /path/to/key.txt
副本集和分片时安全验证,需要使用一个路径共享密钥。


--nohttpinterface
关闭http访问接口


--bind_ip address
只允许指定的网络ip访问.
  如果想安全的启动mongod,就要使用nohttpinterface和bind_ip操作选项,确定外网不能直接访问。尤其确保你没有其余的选项启动,MongoDB需要以下网络环境可以访问:


  • 单个服务器 - 客户端程序可以获取访问连接
  • 副本集 - 任何成员集能够访问,包括自己;客户端能够访问任何一个成员集,并且可访问的成员集都能够成为主节点(活跃节点).
  • 分片- mongos进程必须能够连接到配置的服务器和分片,分片必须能够彼此连接。客户端程序必须能够连接到mongos进程。配置服务器没必要彼此提供访问连接的支持。
  所有的连接都是通过tcp建立的.


DSC0000.jpg


缪斯的情人
翻译于 2天前

  6人顶


顶 翻译的不错哦!






其它翻译版本(2)







查看配置
  如果你6个月前启动mongod时做了一堆配置,那么现在你如何知道做了什么配置呢?这里提供了一个shell小助手:

> db.serverCmdLineOpts()
{ "argv" : [ "./mongod", "--port", "30000" ], "parsed" : { },
"ok" : 1 }
  解析后的字段是从配置文件读取的一些参数列表.

使用shell

Shell帮助
  当你忘记一个命令时,mongodb提供了许多功能帮助你:

> // basic help
> help
db.help() help on db methods
db.mycoll.help() help on collection methods
sh.help() sharding helpers
rs.help() replica set helpers
help admin administrative help
help connect connecting to a db help
...
  注意对于数据库,集合,副本集,分片,管理员等提供了单独了帮助功能。这里没有一一列出,像游标的帮助功能如下:

> // list common cursor functions
> db.foo.find().help()
  你可以使用这个功能和小助手作为一个内置的备忘清单。




缪斯的情人
翻译于 2天前

  0人顶


顶 翻译的不错哦!








查看方法的定义
  如果你不知道一个方法是干什么用的,你可以在shell中通过去除括号的方式运行它,查看它的源码:

> // run the function
> db.serverCmdLineOpts()
{ "argv" : [ "./mongod" ], "parsed" : { }, "ok" : 1 }
> // see its source
> db.serverCmdLineOpts
function () {
return this._adminCommand("getCmdLineOpts");
}
  这可以帮助我们获悉这个方法需要什么参数和抛出什么错误,以及如何在其他语言中使用。




缪斯的情人
翻译于 2天前

  0人顶


顶 翻译的不错哦!








使用编辑功能
  shell命令限制多行的支持,因此在里面编写程序很费劲,shell编辑小助手让它更加简单,打开一个文本编辑器,编辑一个变量,例如:

> x = function() { /* some function we're going to fill in */ }
> edit x
  在编辑器修改一个变量保存退出。这个变量就在shell里面被设定好了。
  不管是编辑器的环境变量或者MongoDB shell的变量编辑环境,都必须设置使用edit模式。你可以在MongoDB shell中通过如下命令配置:

> EDITOR="/usr/bin/emacs"
  编辑模式在JavaScript脚本下是无法使用的,只能在交互的shell中使用。




缪斯的情人
翻译于 2天前

  1人顶


顶 翻译的不错哦!








.mongorc.js
  如果你的主目录下有个.mongorc.js文件,那么当你启动shell时他就会自动运行。使用它可以初始化任何你经常使用的helper方法和你不想意外操作的删除方法.
  比如,你不想使用默认的dropDatabase()方法了,你可以在.mongorc.js文件中添加下面的命令:

DB.prototype.dropDatabase = function() {
print("No dropping DBs!");
}
db.dropDatabase = DB.prototype.dropDatabase;
  上面的例子改变了dropDatabase() helper方法,使他只打印出一行信息,而没有真正的删除数据库.
  注意这个技巧不是一个安全手段,固执的用户仍然可以在不使用helper前提下删除数据库。然而,移除危险的admin权限命令也可以帮助阻止“大堤的奔溃”.
  几个建议在.mongorc.js中使用helper命令时移除的:


  • DB.prototype.shutdownServer
  • DBCollection.prototype.drop
  • DBCollection.prototype.ensureIndex
  • DBCollection.prototype.reIndex
  • DBCollection.prototype.dropIndexes






缪斯的情人
翻译于 2天前

  0人顶


顶 翻译的不错哦!








改变提示
  shell的提示可以通过一个方法设置提示变量的方式来改变:

prompt = function() {
try {
db.getLastError();
}
catch (e) {
print(e);
}
return (new Date())+"$ ";
}
  如果你设置了提示,每次执行时都会重新返回提示信息(上面的例子将返回最后执行的信息)。
尝试在你的提示里面调用db.getLastError()方法,这将包含默认的提示和服务器重新连接以及返回的错误信息.
  同时,把任何可能出现异常的用try/catch包裹起来,那是非常恼人的,当你的提示变成了一个异常信息!





缪斯的情人
翻译于 2天前

  0人顶


顶 翻译的不错哦!








操作诊断

查看和终止操作
  你可以通过currentOp查看当前操作状态:

> db.currentOp()
{
"inprog" : [
{
"opid" : 123,
"active" : false,
"locktype" : "write",
"waitingForLock" : false,
"secs_running" : 200,
"op" : "query",
"ns" : "foo.bar",
"query" : {
}
...
},
...
]
}
  使用上面的opid字段,你可以终止这个操作:

> db.killOp(123)
  不是所有的操作都能被终止或者立刻终止,通常,操作不会被终止,直到他们获取到锁.
  active字段表明操作当前是否在运行,如果一个操作没有运行,通常是要么没启动,要么在等待锁,要么执行了其他操作。通过numYields你可以查看操作执行的时间.




缪斯的情人
翻译于 2天前

  0人顶


顶 翻译的不错哦!








索引使用
  使用explain()来查看当前查询操作使用了哪个索引.

> db.foo.find(criteria).explain()
{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 2,
"nscannedObjects" : 2,
"nscanned" : 2,
"nscannedObjectsAllPlans" : 2,
"nscannedAllPlans" : 2,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
},
"server" : "ubuntu:27017"
}
  explain()输出中有几个重要的字段:


  • n: 返回记录行数.
  • nscanned: 使用索引读取的记录数量.
  • nscannedObjects: 被扫描的文档数量.
  • indexOnly: 如果查询没有使用集合本身.
  • nYields: 查询读取锁的释放时间和等待下次操作时间.
  • indexBounds: 当使用索引时,显示的索引扫描范围.






缪斯的情人
翻译于 2天前

  0人顶


顶 翻译的不错哦!







  游标类型
一个遍历游标(BasicCursor)意味着没有使用索引;一个B树游标(BtreeCursor)意味着使用了一个常用的索引;平行游标被用于分片;二维空间索引(geospatial indexes)使用他们自己特殊的游标。
  一旦一个数组被索引,那么索引上就会设定一个“multikey”标记,这就是对上面isMultiKey字段的解释。这个标记在索引生命周期内一直保存,除非你去掉了数组的索引。
  
如果应用索引做查询的话,explain输出的信息里将包含索引范围字段,它描述了索引遍历到的那部分记录。比如,如果你知道你的文档里面有个age字
段,并且年龄在0-120之间均匀分布,索引范围从3-5,你可以看到索引只需扫描一小部分数据就能满足你的查询需要。
  





缪斯的情人
翻译于 2天前

  0人顶


顶 翻译的不错哦!








暗示(Hinting)
  使用hint()能让查询强制使用一个特殊的索引:

> db.foo.find().hint({x:1})
  这个暗示必须和你想使用的的索引key相匹配,你可以通过运行下面命令查看可用的索引:

> db.foo.getIndexes()
  一般来说,你可以创建一个索引用于查询。如果你有一个查询和排序,建索引最合适的字段取决于你的查询。如果查询一个单一的值(如:{x:y}),索引应该 这样建{queryField: 1, sortField: 1}。如果查询的是一个范围或者集合,采用这样的方式建索引可能更高效:{sortField: 1, queryField: 1}。如果你是用这个索引,MongoDB必须扫描所有的索引查找结果集,但是它可以在不使用内存排序的情况下返回有序的结果。




缪斯的情人
翻译于 2天前

  0人顶


顶 翻译的不错哦!








系统性能分析
  你可以打开系统分析,看看数据库的操作信息。虽然性能上会有损失,但可以帮助我们避免慢查询。

> db.setProfilingLevel(2) // profile all operations
> db.setProfilingLevel(1) // profile operations that take longer
than 100ms
> db.setProfilingLevel(1, 500) // profile operations that take
longer than 500ms
> db.setProfilingLevel(0) // turn off profiling
> db.getProfilingLevel(1) // see current profiling setting
  性能条目保存在开启性能分析的数据库中名为 system.profile 的集合。可以针对单个数据库开启和关闭性能分析。

DSC0001.jpg


Khiyuan
翻译于 2天前

  1人顶


顶 翻译的不错哦!








副本集
  要找到延迟的复制,连接到一个备节点并运行这个函数:

> db.printReplicationStatus()
configured oplog size: 2000MB
log length start to end: 23091secs (6.4hrs)
oplog first event time: Fri Aug 10 2012 04:33:03 GMT+0200 (CEST)
oplog last event time: Mon Aug 20 2012 10:56:51 GMT+0200 (CEST)
now: Mon Aug 20 2012 10:56:51 GMT+0200 (CEST)
  要查看某个成员对集合的性能状况,连接到这个成员,并运行:

> rs.status()
  此命令会告诉你其他成员之于它的状态和地位。
  在一个备节点上运行 rs.status() 将告诉你备节点是从 syncingTo字段中哪个中同步数据的。




Khiyuan
翻译于 2天前

  0人顶


顶 翻译的不错哦!








分片
  要查看群集的元数据(分片,数据库,文件,数据等),请运行下面的函数:

> db.printShardingStatus()
> db.printShardingStatus(true) // show all chunks
  您也可以连接到 Mongos ,使用“use config”查看分片,数据库,集合,或块的数据,然后查询相关的集合。

> use config
switched to db config
> show collections
chunks
databases
lockpings
locks
mongos
settings
shards
system.indexes
version
  永远都连接到 mongos 获取分片信息。永远不要直接连接配置服务器。永远不要直接写入配置服务器。。永远使用分片命令和帮助。
在维护之后,有时实际上没有实施维护的 mongos 进程的配置版本号将不会更新。无论是回弹服务还是运行 flushRouterConfig 命令都能快速解决问题。

> use admin
> db.runCommand({flushRouterConfig:1})
  通常这个问题将表现为 setShardVersion 失败的错误。
无需担心日志中的 setShardVersion 错误,但它们不应该出现在您的应用程序中(除非 mongos 无法连接到任何配置服务器,否则你不应该得到错误)。D
要添加新的分片,运行:

> db.addShard("rsName/seed1,seed2,seed3")
  要在数据库上运用分片,运行:

> db.adminCommand({enableSharding: true})
  要在集合上运用分片,运行:

> db.adminCommand({shardCollection: "dbName.collName",
unique: true, key: {fieldName: 1}})
  既不应该已经存在 dbName.collName,也不应该已经索引fieldName(分片关键字)。如果你在使用唯一分片关键字,它必须是唯一索引的。




Khiyuan
翻译于 2天前

  0人顶


顶 翻译的不错哦!







  
在集群中,如果你不是在 _id 上分片,_id 无需唯一。不管怎样,它们都在独立的分片上(就是说,你可以在 shard1
上有一个_id:123,在 shard2 生也有一个_id:123,但它们不能同时存在于
shard1中)。文件往往在分片间移动,如果是自己生成的_id,你需要确保你的_id唯一。如果你用的是Object_Id 就不会出问题。
要关闭均衡器,通过的 mongos 更新 config.settings 集合:

> sh.setBalancerState(false)
  要恢复,则使用同样的命令,传递一个 True。




Khiyuan
翻译于 2天前

  0人顶


顶 翻译的不错哦!








Mongo监控服务 (MMS)
  MMS 是一种免费的、易操作的监控 MongoDB 的方式。要使用它,先在 http://mms.10gen.com. 创建一个账号。

DSC0002.png   查看 http://mms.10gen.com/help 以获得更多的文档。

简单规则

数据库
  数据库的名称不能包含 ".","$","\0"(空字符)。名称只能包含在你的文件系统中可以用做文件名的字符。Admin,config,local是数据库的保留名(你可以在其中保存数据,单永远不要删除它们)。
  另一个强大的选项是 post-commit 钩子。钩子将在提交到库时被触发。这是比周期构建或 Poll SCM 选项更高效的方法。





Khiyuan
翻译于 2天前

  0人顶


顶 翻译的不错哦!








集合
  集合名不能含有 "$" 或 "\0"。前缀为 "system." 的名字为 MongoDB 的保留集合,不能删除(哪怕是你创建的)。“点”经常被用于集合名称的组织,但它们没有语义。名为“che.se”的集合跟名为“che”的集合以及名为“cheese”的集合没有任何关联。

字段名
  字段名不能含有 "." 或 "\0"。当字段为数据库引用时,它应当只含有"$"。

索引选项

background 在后台建立索引,同时可数据库可读写
unique 每个键的值都是唯一的。
sparse 不索引不存在的值。轻松索引文档中的唯一字段,而没有该字段的文档不参与索引。
expireAfterSeconds 设定集合的生存时间。
dropDups 当创建唯一索引时,遭遇重复则删除,而非报错。注意,这个选项将删除有重复值的文档。

查询格式
  查询语句通常为一下格式:

{key : {$op : value}}
  例如:

{age : {$gte : 18}}
  有三个例外的规则: $and, $or, 和 $nor,此三者优先级最高:

{$or : [{age: {$gte : 18}}, {age : {$lt : 18},
parentalConsent:true}}]}
更新格式
  更新语句总是如下格式:

{key : {$mod : value}}
  例如:

{age : {$inc : 1}}





Khiyuan
翻译于 2天前

  0人顶


顶 翻译的不错哦!








查询操作符


  • √: 匹配
  • x: 不匹配

操作符  查询示例  文档示例  



$gt, $gte, $lt, $lte, $ne {numSold : {$lt:3}} √ {numSold: 1}
x {numSold: "hello"}
x {x : 1}
$in, $nin {age : {$in : [10, 14,
21]}}
√ {age: 21}
√ {age: [9, 10, 11]}
x {age: 9}
$all {hand : {$all :
["10","J","Q","K","A"]}}
√ {hand: ["7", "8", "9",
"10", "J", "Q", "K", "A"]}
x {hand:["J","Q","K"]}
$not {name : {$not : /jon/i}} √ {name: "Jon"}
x {name: "John"}
$mod {age : {$mod : [10, 0]}} √ {age: 50}
x {age: 42}
$exists {phone: {$exists: true}} √ {phone: "555-555-
5555"}
x {phones: ["555-555-
5555", "1-800-555-
5555"]}
$type* {age : {$type : 2}} √ {age : "42"}
x {age : 42}
$size {"top-three":{$size:3}} √ {"top-three":["gold","s
ilver","bronze"]}
x {"top-three":["blue
ribbon"]}
  *参见 http://www.mongodb.org/display/DOCS/Advanced+Queries 获取全部类型。

更新修饰符

修饰符  初始文档  修改示例  最终文档  




$set
{x:"foo"}
{$set:{x:[1,2,3]}}
{x:[1,2,3]}


$unset
{x:"foo"}
{$unset:{x:true}}
{}


$inc
{countdown:5}
{$inc:{countdown:-1}}
{countdown:4}


$push, $pushAll
{votes:[-1,-1,1]}
{$push:{votes:-1}}
{votes:[-1,-1,1,-1}}


$pull, $pullAll
{blacklist:["ip1","ip2","ip3"]}
{$pull:{blacklist:"ip2"}}
{blacklist:"ip1",
"ip3"} {blacklist:
"ip1","ip3"}


$pop
{queue:["1pm","3pm","8pm"]}
{$pop:{queue:-‐1}}
{queue:["3pm","8pm"]}


$addToSet,$each
{ints:[0,1,3,4]}
{$addToSet:{ints:{
$each:[1,2,3]}}}
{ints:[0,1,2,3,4]}


$rename
{nmae:"sam"}
{$rename:{nmae:"name"}}
{name:"sam"}


$bit
{permission:6}
{$bit:{permissions:{or:1}}}
{permission:7}

聚合管道操作符
  聚合框架可以用来做任何事情,从简单的查询语句到复杂的聚合查询。
  使用聚合框架,将聚合操作符通过管道传递给 aggregate() 函数:

> db.collection.aggregate({$match:{x:1}},
... {$limit:10},
... {$group:{_id : "$age"}})
  下面是可用操作符的列表:

操作符简述



{$project : projection}
包含、排除、重命名和显示字段。


{$match : match}
查询,需要同 find() 一样的参数。


{$limit : num}
限制结果数量


{$skip : skip}
忽略结果的数量。


{$sort : sort}
按照给定字段排序结果。


{$group : group}
按照给定表达式(见下)组合结果。


{$unwind : field}
分割的嵌入数组到其自己顶层文件。
  要引用一个字段,使用 $fieldName 语句。例如,下面的映射将返回一个重新命名为“time since epoch ” 的原存在的“$time”字段:

{$project: {"time since epoch": "$time"}}
  $project 和 $group 不能同时表达,你可以用 $fieldName 语句,如下:

表达操作符示例简述



$add : ["$age", 1]
age 字段加1.


$divide : ["$sum", "$count"]
使用 sum 字段 除以 count 字段


$mod : ["$sum", "$count"]
sum 字段除以 count 字段后的余数。


$multiply : ["$mph", 24, 365]
mph 字段乘以 24*365.


$subtract : ["$price","$discount"]
price 字段减去 discount 字段。


$strcasecmp : ["ZZ", "$name"]
如果 name 字段小于 “ZZ” 则为 1,如果 name 字段大于 “ZZ” 则为 0。 -1 if name is greater than ZZ.


$substr : ["$phone", 0, 3]
获取的电话区号(前三个字符)。


$toLower : "$str"
Converts str to all lowercase.


$toUpper : "$str"
str 字段全部大写。


$ifNull : ["$mightExist",
$add : ["$doesExist", 1]]
若 mightExist 不为空,则返回 mightExist 的值,否则返回第二个表达式的结果。


$cond : [exp1, exp2, exp3]
如果 exp1 结果为真,返回 exp2的结果,否则返回 exp2的结果。






Khiyuan
翻译于 2天前

  0人顶


顶 翻译的不错哦!









备份
  当状态一致时(备份时没有发生读写操作),最好的备份方式就是把数据库文件拷贝一份。


  • 使用fsync+lock命令。这个命令将所有的写操作强制写入磁盘,并且阻止了新的写入。> db.fsyncLock()
  • 把数据库文件拷贝到本地一个新路径下
  • 使用unlock命令解锁数据库。> db.fsyncUnlock()
  恢复备份的方法是拷贝文件到正确的服务器路径下,重启。
  如果你有一个文件系统来做文件系统快照,你的日志在同样的卷标下,并且做了RAID共享存储,你可以使用一个无锁的快照做处理。既然这样,当你重启时,日志就能同步来保持始终一致性。
  在特殊情况下可以使用Mongodump做备份。如果你决定使用它,首先不要使用fsync+lock。





缪斯的情人
翻译于 2天前

  0人顶


顶 翻译的不错哦!



其它翻译版本(1)






副本集维护

活跃节点成员的保持
  停止一个活跃节点的方法是把他的优先级调为0:

> var config = rs.config()
> config.members[2].priority = 0
> rs.reconfig(config)
  阻止从节点成为临时活跃节点的方法是连接到它发送一条冻结命令:

> rs.freeze(10*60) // # of seconds to not become primary
  如果你不想永久的改变优先级只是暂时做维护工作,这个方法是非常方便的.

成员的降级
  如果一个成员当前是活跃节点,你可以通过下面的方式对它降级:

> rs.stepDown(10*60) // # of seconds to not try to become primary
again





缪斯的情人
翻译于 2天前

  0人顶


顶 翻译的不错哦!




  以独立服务器的方式启动一个成员
为了维护,你通常需要启动一个从节点并且确保它可写(比如,建索引),为了达到这个目的你需要把从节点作为一个临时独立的mongod.
  如果从节点初始启动使用下面的参数:

$ mongod --dbpath /data/db --replSet setName --port 30000
  关闭清除后使用下面配置重启:

$ mongod --dbpath /data/db --port 30001
  注意dbpath没有改变,但是端口改变了,replSet设置也被移除了。这个mongod将作为一个单独的服务启动,其余的副本集将通过30000端口查找成员,而不是30001,因此看起来他只是把其余的副本集降级了.
  当你维护完成了,使用初始的参数设置并重启就ok了.

更多资源


  • MongoDB 下载http://www.mongodb.org/downloads
  • 文档 http://docs.mongodb.org
  • 里程碑、修改的问题、添加功能http://jira.mongodb.org
  • 问题: http://groups.google.com/group/mongodb-user
  • IRC chat聊天,能及时得到问题答案:irc.freenode.net/#mongodb

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-83877-1-1.html 上篇帖子: MongoDB Replica Sets 下篇帖子: MongoDB 自动分片 auto sharding
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表