Cat API
官方地址:https://www.elastic.co/guide/en/elasticsearch/reference/current/cat.html
介绍
JSON 在计算机领域是个伟大的发明,尽管他可以以美化格式,但是视图从 JSON 发现数据直接的关系还是很沉闷的.人眼,尤其是看着终端,还是需要紧凑和对齐的文本.而 cat API 就是以图完成这个需求.
所有的 cat 命令都接受一个查询字符串参数,以查看它们提供的所有标题和信息,而/ _cat 命令仅列出所有可用的命令。
常用参数
-
verbose
每个_cat 命令都会接受一个"v"参数,会返回详细的结果输出.比如
GET /_cat/master?v
将会返回
id host ip node u_n93zwxThWHi1PDBJAGAg 127.0.0.1 127.0.0.1 u_n93zw
-
help
每个_cat 命令都会接受一个"help"参数,会在返回结果中说明每列的含义,比如
GET /_cat/master?help
将会返回
id | | node id host | h | host name ip | | ip address node | n | node name
-
header
每个_cat 命令都会接受一个"h"参数,会在返回结果中强制所指定的列,比如
GET /_cat/nodes?h=ip,port,heapPercent,name
将会返回
127.0.0.1 9300 27 sLBaIGK
你也可以在请求的多个列的参数中使用通配符,如/_cat/thread_pool?h=ip,bulk.*来返回所有以 bulk 开始的列
格式化数字
许多命令提供一些类型的数字输出,要么是字节,要么是大小,要么是时间值。默认情况下,这些类型是人为格式化的,例如,3.5 mb 而不是 3763212。人类的可读的值并不方便进行数字排序,因此,为了在秩序重要的地方进行操作,你可以改变它。
假设您希望在集群中找到最大的索引(所有分片的存储容量,而不是文档的数量)。/_cat/indices
API 是理想的。我们只需要调整两件事。首先,我们要关闭人类可读模式。我们将使用字节级的解析格式。然后,我们将使用适当的列将输出进行排序,在本例中是第 8 列
curl '192.168.56.10:9200/_cat/indices?bytes=b' | sort -rnk8
返回结果
green wiki2 3 0 10000 0 105274918 105274918
green wiki1 3 0 10000 413 103776272 103776272
green foo 1 0 227 0 2065131 2065131
如果你想改变时间单位,请使用"time"参数
如果你想改变大小单位,请使用"size"参数
如果你想改变字节单位,请使用"bytes"参数
返回各种格式的结果,如 json,smile,yaml,cbor
curl 'localhost:9200/_cat/indices?format=json&pretty'
将返回
[
{
"pri.store.size": "650b",
"health": "yellow",
"status": "open",
"index": "twitter",
"pri": "5",
"rep": "1",
"docs.count": "0",
"docs.deleted": "0",
"store.size": "650b"
}
]
当前支持的格式化类型有: text(默认),json,smile,yaml,cbor,请使用“format”参数.
另外一个可选的选择是:在 HTTP 请求头中添加“Accept”参数来进行格式化.上述所有的格式化类型都支持.比如:
curl '192.168.56.10:9200/_cat/indices?pretty' -H "Accept: application/json"
将返回
[
{
"pri.store.size": "650b",
"health": "yellow",
"status": "open",
"index": "twitter",
"pri": "5",
"rep": "1",
"docs.count": "0",
"docs.deleted": "0",
"store.size": "650b"
}
]
每个命令都接受一个查询字符串参数 s,它通过指定为参数值的列对表进行排序。列按名称或别名指定,并作为逗号分隔的字符串提供。默认情况下,排序以升序方式进行。":desc"表示一个列将反转该列的顺序。":asc"也被接受,但其表现与默认排序相同。
比如:
GET _cat/templates?v&s=order:desc,index_patterns
将返回:
name index_patterns order version
pizza_pepperoni [*pepperoni*] 2
sushi_california_roll [*avocado*] 1 1
pizza_hawaiian [*pineapples*] 1
排序
排序
cat aliases
别名 api 显示一些关于当前配置的所有别名信息,比如与哪些索引关联,包含的过滤器,以及路由信息
GET /_cat/aliases?v
或者会返回
alias index filter routing.index routing.search
alias1 test1 - - -
alias2 test1 * - -
alias3 test1 - 1 1
alias4 test1 - 2 1,2
该输出结果显示"alias2"配置了一个过滤器,"alias3"和"alias4"指定了路由配置
如果你只想获取某个具体的别名的信息,你可以在请求 URL 中使用逗号隔开的形式来指定你想获取的别名,比如
/_cat/aliases/aliases/alias1,alias2
cat allocation
allocation api 提供了一个快照, 关于有多少分片分配给每个数据节点和他们使用多少磁盘空间
GET /_cat/allocation?v
应该返回:
shards disk.indices disk.used disk.avail disk.total disk.percent host ip node
5 260b 47.3gb 43.4gb 100.7gb 46 127.0.0.1 127.0.0.1 CSUXak2
在这里,我们可以看到每个节点都分配了一个分片,以及它们都使用了相同数量的空间。
cat count
count 提供了对整个集群或单个索引的文档计数的快速访问
GET /_cat/count?v
返回结果像这样
epoch timestamp count
1475868259 15:24:19 121
或者获取一个索引的文档数量
GET /_cat/count/twitter?v
返回结果像这样
epoch timestamp count
1475868259 15:24:20 120
该文档数量表明存活的文档集合而不包含那些在合并过程中被清除的删除文档.
cat fielddata
cat fielddata 显示了当前集群中每个数据节点上的 fielddata 使用了多少堆内存
GET /_cat/fielddata?v
返回结果如下:
id host ip node field size
Nqk-6inXQq-OxUfOUI8jNQ 127.0.0.1 127.0.0.1 Nqk-6in body 544b
Nqk-6inXQq-OxUfOUI8jNQ 127.0.0.1 127.0.0.1 Nqk-6in soul 480b
能够在 URL 参数中指定查询某个字段的 fielddata
GET /_cat/fielddata?v&fields=body
返回结果如下:
id host ip node field size
Nqk-6inXQq-OxUfOUI8jNQ 127.0.0.1 127.0.0.1 Nqk-6in body 544b
同样接受多个以逗号分隔符分开的列表
GET /_cat/fielddata/body,soul?v
返回结果如下:
id host ip node field size
Nqk-6inXQq-OxUfOUI8jNQ 127.0.0.1 127.0.0.1 Nqk-6in body 544b
Nqk-6inXQq-OxUfOUI8jNQ 127.0.0.1 127.0.0.1 Nqk-6in soul 480b
上面的结果显示为每个字段"body"和"soul"单独列出 fielddata 的使用情况
cat health
cat health 是一个简洁的、单行命令来表示和/ _cluster/ health 的相同信息
GET /_cat/health?v
epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1475871424 16:17:04 elasticsearch green 1 1 5 5 0 0 0 0 - 100.0%
我们可以添加一个 ts 选项来禁止输出时间戳
GET /_cat/health?v&ts=false
结果为:
cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
elasticsearch green 1 1 5 5 0 0 0 0 - 100.0%
该命令的一个常见用法是检查节点之间的健康状况
% pssh -i -h list.of.cluster.hosts curl -s localhost:9200/_cat/health
[1] 20:20:52 [SUCCESS] es3.vm
1384309218 18:20:18 foo green 3 3 3 3 0 0 0 0
[2] 20:20:52 [SUCCESS] es1.vm
1384309218 18:20:18 foo green 3 3 3 3 0 0 0 0
[3] 20:20:52 [SUCCESS] es2.vm
1384309218 18:20:18 foo green 3 3 3 3 0 0 0 0
一个不那么明显的用途是跟踪一个大型集群随时间的恢复进度。大量的分片,启动一个集群,甚至在失去一个节点后恢复,可能需要时间(取决于您的网络和磁盘)。跟踪其进度的一种方法是在一个延迟的循环中使用这个命令
% while true; do curl localhost:9200/_cat/health; sleep 120; done
1384309446 18:24:06 foo red 3 3 20 20 0 0 1812 0
1384309566 18:26:06 foo yellow 3 3 950 916 0 12 870 0
1384309686 18:28:06 foo yellow 3 3 1328 916 0 12 492 0
1384309806 18:30:06 foo green 3 3 1832 916 4 0 0
^C
在这种情况下,我们可以看出,恢复大约需要 4 分钟。如果这种情况持续了好几个小时,我们就可以看到未分配的碎片陡然下降。如果这个数字保持不变,我们可能意识到这是一个问题.
为什么要时间戳
当集群出现故障时,您通常使用 health 命令。在此期间,将活动与日志文件、警报系统等关联起来非常重要。
有两种输出格式。H:MM:SS 输出仅仅是为了快速的人类查看。时间戳(点)时间保留了更多的信息,包括日期,如果你的恢复持续时间的话,那就是机器排序。
cat indices
cat indices 命令为每个索引提供一个横截面. 该横截面信息横跨不同节点.比如:
GET /_cat/indices/twi*?v&s=index
输出结果如下
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open twitter u8FNjxh8Rfy_awN11oDKYQ 1 1 1200 0 88.1kb 88.1kb green open twitter2 nYFWZEO7TUiOjLQXBaYJpA 5 0 0 0 260b 260b
我们可以快速的告诉你有多少分片组成一个索引,文档的数量,删除的文档数量,主分片的存储容量,以及整个存储的容量(所有的分片包括副本)。所有这些公开的度量标准都直接来自 Lucene api。
注意
- 由于在 lucene 级别上显示的文档数量和删除的文档数量,它包括所有隐藏的文档(例如,从嵌套文档中)。
- 为了在 elasticsearch 级别获取文档的实际计数,推荐的方法是使用 cat 计数或 count API
只显示主分片信息
索引统计信息通常会显示所有分片信息,包含主分片和副本分片,有时候我们只关注主分片上的信息统计,因此我们可以通过"pri"标记来让返回结果只显示主分片统计信息.
实例
显示哪些索引的健康状态为 yellow
GET /_cat/indices?v&health=yellow
返回结果如下:
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open twitter u8FNjxh8Rfy_awN11oDKYQ 1 1 1200 0 88.1kb 88.1kb
返回文档数量最多的索引
GET /_cat/indices?v&s=docs.count:desc
返回结果如下:
ealth status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open twitter u8FNjxh8Rfy_awN11oDKYQ 1 1 1200 0 88.1kb 88.1kb green open twitter2 nYFWZEO7TUiOjLQXBaYJpA 5 0 0 0 260b 260b
查看索引"twitter"完成了多少次合并操作
GET /_cat/indices/twitter?pri&v&h=health,index,pri,rep,docs.count,mt
返回结果如下:
health index pri rep docs.count mt pri.mt
yellow twitter 1 1 1200 16 16
查看每个索引使用了多少内存
GET /_cat/indices?v&h=i,tm&s=tm:desc
结果如下:
i tm
twitter 8.1gb
twitter2 30.5kb
cat master
cat master api 没有什么特别的选项.仅仅显示主节点的 ID,绑定的 IP 地址,以及节点名称,比如:
GET /_cat/master?v
返回结果为
id host ip node
YzWoH_2BT-6UjVGDyPdqYg 127.0.0.1 127.0.0.1 YzWoH_2
这些信息也可以通过节点命令获得,但是,如果您想要做的所有节点都是在主节点上达成一致的,那么这个信息就会稍微短一些
% pssh -i -h list.of.cluster.hosts curl -s localhost:9200/_cat/master
[1] 19:16:37 [SUCCESS] es3.vm Ntgn2DcuTjGuXlhKDUD4vA 192.168.56.30 H5dfFeA
[2] 19:16:37 [SUCCESS] es2.vm Ntgn2DcuTjGuXlhKDUD4vA 192.168.56.30 H5dfFeA
[3] 19:16:37 [SUCCESS] es1.vm Ntgn2DcuTjGuXlhKDUD4vA 192.168.56.30 H5dfFeA
cat nodeattrs
cat nodeattrs 命令显示自定义的节点属性,比如:
node host ip attr value
EK_AsJb 127.0.0.1 127.0.0.1 testattr test
前几列(node,host,ip)展示每个节点的基本信息,后面的 attr 和 value 列则展示自定义的节点信息
cat nodes
cat nodes 命令显示集群的节点拓扑关系,比如
GET /_cat/nodes?v
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
127.0.0.1 65 99 42 3.07 mdi * mJw06l1
前几列(ip
, heap.percent
, ram.percent
, cpu
, load_*
) 告诉你你的节点实况,以及告诉你一个节点性能信息统计的快照.
后面几列(node.role
, master
, and name
) 则提供一些辅助信息,这些信息通常在整个集群中非常有用,尤其是大型集群,关系到我的集群到底设置多少个主节点的问题?
节点 API 接受一个额外的 URL 参数 full_id,仅接受 true 或 false。此参数的目的是在其完整长度或缩写形式(默认)中格式化 ID 字段(如果需要 ID 或 nodeId)。
cat pending tasks
cat pending_tasks 命令与"/_cluster/pending_tasks"提供相同的信息,只是以扁平的格式输出.
GET /_cat/pending_tasks?v
结果为
insertOrder timeInQueue priority source
1685 855ms HIGH update-mapping [foo][t]
1686 843ms HIGH update-mapping [foo][t]
1693 753ms HIGH refresh-mapping [foo][[t]]
1688 816ms HIGH update-mapping [foo][t]
1689 802ms HIGH update-mapping [foo][t]
1690 787ms HIGH update-mapping [foo][t]
1691 773ms HIGH update-mapping [foo][t]
cat plugins
cat plugins 命令用来显示每个节点正在运行的插件列表,该信息贯穿所有节点
GET /_cat/plugins?v&s=component&h=name,component,version,description
结果为
name component version description
U7321H6 analysis-icu 6.0.0 The ICU Analysis plugin integrates Lucene ICU module into elasticsearch, adding ICU relates analysis components. U7321H6 analysis-kuromoji 6.0.0 The Japanese (kuromoji) Analysis plugin integrates Lucene kuromoji analysis module into elasticsearch. U7321H6 analysis-phonetic 6.0.0 The Phonetic Analysis plugin integrates phonetic token filter analysis with elasticsearch. U7321H6 analysis-smartcn 6.0.0 Smart Chinese Analysis plugin integrates Lucene Smart Chinese analysis module into elasticsearch. U7321H6 analysis-stempel 6.0.0 The Stempel (Polish) Analysis plugin integrates Lucene stempel (polish) analysis module into elasticsearch. U7321H6 analysis-ukrainian 6.0.0 The Ukrainian Analysis plugin integrates the Lucene UkrainianMorfologikAnalyzer into elasticsearch. U7321H6 discovery-azure-classic 6.0.0 The Azure Classic Discovery plugin allows to use Azure Classic API for the unicast discovery mechanism
U7321H6 discovery-ec2 6.0.0 The EC2 discovery plugin allows to use AWS API for the unicast discovery mechanism. U7321H6 discovery-file 6.0.0 Discovery file plugin enables unicast discovery from hosts stored in a file. U7321H6 discovery-gce 6.0.0 The Google Compute Engine (GCE) Discovery plugin allows to use GCE API for the unicast discovery mechanism. U7321H6 ingest-attachment 6.0.0 Ingest processor that uses Apache Tika to extract contents
U7321H6 ingest-geoip 6.0.0 Ingest processor that uses looksup geo data based on ip adresses using the Maxmind geo database
U7321H6 ingest-user-agent 6.0.0 Ingest processor that extracts information from a user agent
U7321H6 jvm-example 6.0.0 Demonstrates all the pluggable Java entry points in Elasticsearch U7321H6 mapper-murmur3 6.0.0 The Mapper Murmur3 plugin allows to compute hashes of a field's values at index-time and to store them in the index.
U7321H6 mapper-size 6.0.0 The Mapper Size plugin allows document to record their uncompressed size at index time.
U7321H6 store-smb 6.0.0 The Store SMB plugin adds support for SMB stores.
我们可以快速知道每个节点有哪些插件以及这些插件的版本和描述信息
cat recovery
cat recovery 命令提供索引分片的恢复视图,不管是正在恢复还是之前的.相较于 recovery 的 JSON API,它是一种更紧凑的视图.
当索引分片上的数据移动到集群中的其他节点时上,就会发生恢复事件。这可能发生在快照恢复、分片复制级别的更改、节点故障或节点启动时。最后一种类型称为本地存储恢复,是在节点启动时从磁盘上加载的碎片的正常方式.
例如,在从一个节点传输到另一个节点时,集群的恢复情况可能看起来是这样的
GET _cat/recovery?v
结果可能如下所示
index shard time type stage source_host source_node target_host target_node repository snapshot files files_recovered files_percent files_total bytes bytes_recovered bytes_percent bytes_total translog_ops translog_ops_recovered translog_ops_percent
twitter 0 13ms store done n/a n/a 127.0.0.1 node-0 n/a n/a 0 0 100% 13 0 0 100% 9928 0 0 100.0%
在上面的例子,源节点和目标节点是同一个节点,这是由于恢复类型是存储,也就是说,他们都是在节点启动的时候从本地存储读取数据.
现在,让我们看一个更生动的恢复例子.通过增加复制分片的数量来让我们的索引数据迁移到其他节点上,让我们看看一个实时的分片恢复是什么样子的
GET _cat/recovery?v&h=i,s,t,ty,st,shost,thost,f,fp,b,bp
返回结果可能如下
i s t ty st shost thost f fp b bp
twitter 0 1252ms peer done 192.168.1.1 192.168.1.2 0 100.0% 0 100.0%
我们可以在上面的清单中看到我们的 thw twitter 分片从另一个节点中恢复。注意,恢复类型显示为 peer。复制的文件和字节是实时度量。
最后,让我们看看快照恢复是什么样子。假设我之前做了索引的备份,我可以使用快照和恢复 API 来恢复它。
GET _cat/recovery?v&h=i,s,t,ty,st,rep,snap,f,fp,b,bp
这将在响应中显示的快照类型的恢复
i s t ty st rep snap f fp b bp
twitter 0 1978ms snapshot done twitter snap_1 79 8.0% 12086 9.0%
cat repositories
cat repositories 命令显示在集群中注册的快照仓库。例如
GET /_cat/repositories?v
结果可能如下
id type
repo1 fs
repo2 s3
我们可以快速的看到注册了哪些仓库以及他们的类型.
cat segments
cat segments 命令提供某个索引的分片中的关于段的低级别信息。它提供类似于_segments 端点的信息。例如:
GET /_cat/segments?v
结果如下
index shard prirep ip segment generation docs.count docs.deleted size size.memory committed searchable version compound
test 3 p 127.0.0.1 _0 0 1 0 3kb 2042 false true 7.0.1 true test1 3 p 127.0.0.1 _0 0 1 0 3kb 2042 false true 7.0.1 true
输出结果中在前两列给出了索引名称,分片数量.如果你想了解某一个具体的索引的更多关于段信息,你需要在哎请求 URL 中添加索引名称,比如/_cat/segments/test,你也可以这样同时指定多个索引名称/_cat/segments/test,test1.
下面的列会显示额外的监控信息:
prirep
当前段是属于主分片还是副本分片
ip
当前段所在的分片的 ip 地址
segment
当前段的名称,来自于生成的段,该名称被用来在内部生成当前分片下的段文件所在的目录下的段文件名.
generation
generation 数值代表当前段每次有内容写入的时候都会递增.段的名称都来自于该值.
docs.count
该值是当前段中不包含删除文档的文档数量.请注意,这是面向 lucene 的文档数量,因此该值会包含隐藏文档(如 nested 类型文档)
docs.deleted
当前段中所存储的已经标记为删除状态的文档数量,如果这个数大于 0 就完全没问题.删除文档所占用的空间会随着端合并而进行回收.
size
当前段所占用的磁盘空间大小
size.memory
为了更加高效的检索,所有的段都会存储一些数据在内存中.该字段就是显示这些段所占用的内存容量大小
committed
不管段内容是否同步到磁盘上,那些提交过的段信息都会从一个硬件重启中存活下来,不需要担心出现错误,未提交段的数据也存储在事务日志中,以便 Elasticsearch 能够在下一次启动时重新恢复更改.
searchable
该段内容是否能被检索,如果该字段的值是 false,则很有可能意味着段信息已经被刷新到磁盘中但是还没有进行刷新操作来让其内容可以被检索.
version
当前段底层所用到的 lucene 的版本
compound
说明该段内容是否存储在复合文件中.如果该值为 true,则意味着 Lucene 将所有段文件合并成一个单独的段文件,这样能够节省文件描述符.
cat shards
cat shards 命令提供一个详细的视图,关于哪个节点包含了哪些分片信息.它将会告诉你当前分片是主分片还是副本分片,分片中的文档数量,占用的磁盘空间大小,以及该分片位于哪个节点上.这里我们来看下一个单独的索引,只有一个主分片而没有副本分片:
GET _cat/shards
将返回
twitter 0 p STARTED 3014 31.1mb 192.168.56.10 H5dfFeA
索引模式
如果你有很多分片,但是你想看某个索引的分片情况.或者你可以使用 grep 命令,但是你可以通过只提供一个索引模式来节省带宽
GET _cat/shards/twitt*
返回如下
twitter 0 p STARTED 3014 31.1mb 192.168.56.10 H5dfFeA
重新分配(Relocation)
如果说你已经检查了集群健康并且看到
cat thread pool
thread_pool 命令显示每个节点的集群范围的线程池统计数据。默认情况下,所有线程池都返回活动、队列和拒绝的统计信息。
GET /_cat/thread_pool
结果如下
node-0 bulk 0 0 0
node-0 fetch_shard_started 0 0 0
node-0 fetch_shard_store 0 0 0
node-0 flush 0 0 0
node-0 force_merge 0 0 0
node-0 generic 0 0 0
node-0 get 0 0 0
node-0 index 0 0 0
node-0 listener 0 0 0
node-0 management 1 0 0
node-0 refresh 0 0 0
node-0 search 0 0 0
node-0 snapshot 0 0 0
node-0 warmer 0 0 0
第一列显示节点名称
node_name
node-0
第二列显示线程池名称
name
bulk
fetch_shard_started
fetch_shard_store
flush
force_merge generic get index
listener
management
refresh
search
snapshot
warmer
接下来的第三列显示的是处于 active,queue,以及 rejected 状态下的线程池数量
active queue rejected
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
1 0 0
0 0 0
0 0 0
0 0 0
0 0 0
cat thread pool 允许在请求 URL 中接受一个 thread_pool_patterns 来指定一个逗号分隔符隔开的列表来匹配获取哪些线程池的名称
GET /_cat/thread_pool/generic?v&h=id,name,active,rejected,completed
结果如下
id name active rejected completed
0EWUhXeBQtaVGlexUeVwMg generic 0 0 70
在这里,主机列,active,rejected,以及 completed 建议线程池统计信息都展示出来
所有内置线程池和自定义线程池都是可用
线程池字段
对于每个线程池来说,你可以通过如下的字段来加载详细的信息.
Field Name | Alias | Description |
---|---|---|
type | t | 线程池的当前类型(fixed 或 scaling) |
active | a | 当前线程池中处于 active 状态的线程数量 |
size | s | 当前线程池中的线程数量 |
queue | t | 当前线程池中处于队列中的线程数量 |
queue_size | qs | 当前线程池中处于队列中的线程数量 |
rejected | r | 线程执行器拒绝的任务数量 |
largest | l | 当前线程池中曾经处于 active 状态的最高线程数量 |
completed | c | 线程执行器已经完成的任务数量 |
min | mi | 当前线程池中能够允许 active 线程的最小数量 |
max | ma | 当前线程池中能够允许 active 线程的最大数量 |
keep_alive | k | 线程存活时间配置 |
其他字段
除了关于每个线程池的详细信息外,还可以方便地了解这些线程池所在的位置。因此,您可以请求其他细节,比如响应节点的 ip。
Field Name | Alias | Description |
---|---|---|
node_id | id | 唯一的节点 ID |
ephemeral_id | eid | 临时节点 ID |
pid | p | 当前节点的进程 ID |
host | h | 当前节点的 host 名称 |
ip | i | 当前节点绑定的 IP 地址 |
port | po | 当前节点绑定的传输端口 |
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于