|
手艺频道
|
51CTO旗下网站
|jss530.com
|
挪动端

让Elasticsearch飞起去!百亿级及时查询优化实战

近来的一个项目是风控历程数据及时统计分析和聚合的一个 OLAP 剖析监控平台,日流量峰值在 10 到 12 亿高低,每一年数据约 4000 亿条,占用空间也许 200T。

作者:土豆的奥特之女泉源:|2019-03-25 08:05

【51CTO.com原创稿件】近来的一个项目是风控历程数据及时统计分析和聚合的一个 OLAP 剖析监控平台,日流量峰值在 10 到 12 亿高低,每一年数据约 4000 亿条,占用空间也许 200T。

面临如许一个数据量级的需求,我们的数据怎样存储和实现及时查询将是一个严重的应战。

经由对 Elasticsearch 多方调研和凌驾几百亿条数据的插入和聚合查询的考证以后,我们总结出以下几种可以或许有用提拔机能和处理那一题目的计划:

  • 集群计划
  • 存储战略
  • 索引拆分
  • 紧缩
  • 冷热分区等

本文所运用的 Elasticsearch 版本为 5.3.3。

什么是时序索引?其主要特点表现在以下两个方面:

  • 存,以工夫为轴,数据只要增添,没有调换,而且必需包含 timestamp(日期工夫,称号随便)字段。

其感化和意义要大于数据的 id 字段,常见的数据好比我们一般要纪录的操纵日记、用户行动日记、或股市行情数据、服务器 CPU、内存、网络的使用率等。

  • 与,肯定是以工夫局限为第一过滤前提,然后是其他查询前提,好比远一天、一周、本月等等,然后在这个范围内停止二次过滤。

好比性别或地区等,查询效果中对照存眷的是每条数据和 timestamp 字段详细发作的工夫点,而非 id。

此类数据一样平常用于 OLAP、监控剖析等场景。

集群布置计划

我们皆晓得在 Elasticsearch(下称 ES)集群中有两个重要脚色:Master Node 和 Data Node,其他如 Tribe Node 等节点可凭据业务需求另行设立。

为了让集群有更好的机能显示,我们应当对那两个脚色有一个更好的计划,在 Nodes 之间做读取星散,包管集群的稳定性和快速相应,在大规模的数据存储和查询的压力之下可以或许安然面临,各自兴奋的合作。

Master Nodes

Master Node,全部集群的管理者,负有对 index 的管理、shards 的分派,和全部集群拓扑信息的管理等功用。

尽人皆知,Master Node 能够经由过程 Data Node 兼任,然则,若是对群集范围和稳固要求很下的话,就要职责星散,Master Node 推荐自力,它的状况关乎全部集群的存活。

Master 的设置:

  1. node.master: true  
  2. node.data: false  
  3. node.ingest: false 

如许 Master 不到场 I、O,从数据的搜刮和索引操纵中摆脱出来,专门卖力集群的管理工作,因而 Master Node 的节点设置能够相对低一些。

别的防备 ES 集群 split brain(脑裂),公道设置 discovery.zen.minimum_master_nodes 参数,官方推荐 master-eligible nodes / 2 + 1 向下与整的个数。

这个参数决意推举 Master 的 Node 个数,太小轻易发作“脑裂”,可能会泛起多个 Master,太大 Master 将没法推举。

更多 Master 推举相关内容请参考:

  1. https://www.elastic.co/guide/en/elasticsearch/reference/5.3/modules-discovery-zen.html#master-election 

Data Nodes

Data Node 是数据的承载者,对索引的数据存储、查询、聚合等操纵供应支撑。

这些操纵严峻斲丧体系的 CPU、内存、IO 等资本,因而,应当把最好的资本分配给 Data Node,由于它们是真正干累活的脚色,一样 Data Node 也不兼任 Master 的功用。

Data 的设置:

  1. node.master: false  
  2. node.data: true  
  3. node.ingest: false 

Coordinating Only Nodes

ES 自己是一个分布式的盘算集群,每一个 Node 皆能够相应用户的恳求,包孕 Master Node、Data Node,它们皆有完好的 Cluster State 信息。

正如我们晓得的一样,在某个 Node 收到用户恳求的时刻,会将恳求转发到集群中所有索引相干的 Node 上,以后将每一个 Node 的盘算效果兼并后返回给恳求方。

我们临时将这个 Node 称为查询节点,整个过程跟分布式数据库道理相似。那题目去了,这个查询节点若是在并发和数据量比较大的状况下,因为数据的聚合可能会让内存和网络泛起瓶颈。

因而,在职责星散指导思想的条件下,这些操纵我们也应当从这些脚色中剥离出来,官方称它是 Coordinating Nodes,只卖力路由用户的恳求,包孕读、写等操纵,对内存、网络和 CPU 要求对照下。

本质上,Coordinating Only Nodes 能够笼统的明白为是一个负载均衡器,大概反向署理,只卖力读,自己不写数据,它的设置是:

  1. node.master: false  
  2. node.data: false  
  3. node.ingest: false  
  4. search.remote.connectfalse 

增添 Coordinating Nodes 的数目能够进步 API 恳求相应的机能,我们也能够针对差别量级的 Index 分派自力的 Coordinating Nodes 去知足恳求机能。

那是否是越多越好呢?在一定范围内是一定的,但凡事有个度,过了背感化便会突显,太多的话会给集群增添肩负。

在做 Master 推举的时刻会先确保所有 Node 的 Cluster State 是同等的,同步的时刻会守候每一个 Node 的 Acknowledgement 确认,以是适当分派能够让集群痛快酣畅的事情。

search.remote.connect 是禁用跨集群查询,防备在停止集群之间查询时发作二次路由:

  1. https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-cross-cluster-search.html 

Routing

类似于分布式数据库中的分片原则,将相符划定规矩的数据存储到统一分片。ES 经由过程哈希算法去决意数据存储于哪个 Shard:

  1. shard_num = hash(_routing) % num_primary_shards 

个中 hash(_routing) 得出一个数字,然后除以主 Shards 的数目获得一个余数,余数的局限是 0 到 number_of_primary_shards - 1,这个数字就是文档地点的 Shard。

Routing 默许是 id 值,固然能够自定义,公道指定 Routing 可以或许大幅提拔查询效力,Routing 支撑 GET、Delete、Update、Post、Put 等操纵。

如:

  1. PUT my_index/my_type/1?routing=user1 
  2.   "title""This is a document" 
  3.  
  4. GET my_index/my_type/1?routing=user1 

不指定 Routing 的查询历程:

简朴的来讲,一个查询恳求过来今后会查询每一个 Shard,然后做效果聚合,总的工夫也许就是所有 Shard 查询所斲丧的工夫之和。

指定 Routing 今后:

会凭据 Routing 查询特定的一个或多个 Shard,如许便大大削减了查询工夫,进步了查询效力。

固然,怎样设置 Routing 是一个难点,需求一点技能,要凭据业务特性公道组合 Routing 的值,去分别 Shard 的存储,终究连结数据量相对平衡。

能够组合几个维度做为 Routing ,有点类似于 Hbase Key,比方差别的业务线加差别的种别,差别的城市和差别的范例等等,如:

  • _search?routing=beijing:按城市。
  • _search?routing=beijing_user123:按城市和用户。
  • _search?routing=beijing_android,shanghai_android:按城市和手机类型等。

数据不平衡?如果您的业务在北京、上海的数据远远大于其他二三线城市的数据。

再比方我们的业务场景,A 业务线的数据量级远远大于 B 业务线,有时候很易经由过程 Routing 指定一个值包管数据在所有 Shards 上均匀分布,会让局部 Shard 变的愈来愈大,影响查询机能,怎么办?

一种解决办法是零丁为这些数据量大的渠道建立自力的 Index,如:

  1. http://localhost:9200/shanghai,beijing,other/_search?routing=android 

如许能够凭据需求在差别 Index 之间查询,但是每一个 Index 中 Shards 的数据能够做到相对平衡。

另一种设施是指定 Index 参数 index.routing_partition_size,去处理终究能够发生群集不平衡的题目,指定这个参数后新的算法以下:

  1. shard_num = (hash(_routing) + hash(_id) % routing_partition_size) % num_primary_shards 

index.routing_partition_size 应具有大于 1 且小于 index.number_of_shards 的值。

终究数据会在 routing_partition_size 几个 Shard 上匀称存储,是哪个 Shard 取决于 hash(_id) % routing_partition_size 的盘算效果。

指定参数 index.routing_partition_size 后,索引中的 Mappings 必需指定 _routing 为 "required": true,别的 Mappings 不支持 parent-child 父子干系。

许多状况下,指定 Routing 后会大幅提拔查询机能,究竟结果查询的 Shard 只要那么几个,然则怎样设置 Routing 是个困难,可凭据业务特性奇妙组合。

索引拆分

Index 经由过程横向扩大 Shards 实现分布式存储,如许能够处理 Index 大数据存储的题目。

但在一个 Index 变的愈来愈大,单个 Shard 也愈来愈大,查询和存储的速度也愈来愈缓。

更主要的是一个 Index 实在是有存储上限的(除非您设置充足多的 Shards 和机械),如官方声明单个 Shard 的文档数不能超过 20 亿(受限于 Lucene index,每一个 Shard 是一个 Lucene index)。

考虑到 I、O,针对 Index 每一个 Node 的 Shards 数最好不超过 3 个,那面临如许一个重大的 Index,我们是接纳更多的 Shards,照样更多的 Index,我们怎样选择?

Index 的 Shards 总量也不宜太多,更多的 Shards 会带来更多的 I、O 开消,实在谜底便曾经很明白,除非您能接管长时间的查询守候。

Index 拆分的思绪很简朴,时序索引有一个优点就是只要增添,没有调换,定时间积累,自然对索引的拆分友爱支撑,能够根据工夫和数据量做恣意时间段的拆分。

ES 供应的 Rollover Api + Index Template 能够异常便利和友爱的实现 Index 的拆分事情,把单个 index docs 数目掌握在百亿内,也就是一个 Index 默许 5 个 Shards 阁下便可,包管查询的立即相应。

简朴引见一下 Rollover API 和 Index Template 那两个器械,怎样实现 index 的拆分。

Index Template

我们晓得 ES 能够为统一目标或同一类索引建立一个 Index Template,以后建立的索引只要相符婚配划定规矩便会套用这个 Template,没必要每次指定 Settings 和 Mappings 等属性。

一个 Index 能够被多个 Template 婚配,那 Settings 和 Mappings 就是多个 Template 兼并后的效果。

有抵触经由过程 Template 的属性"order" : 0 从低到高掩盖(那局部听说会在 ES6 中会做调解,更好的处理 Template 婚配抵触题目)。

示例:

  1. PUT _template/template_1 
  2.     "index_patterns" : ["log-*"], 
  3.     "order" : 0, 
  4.     "settings" : { 
  5.         "number_of_shards" : 5 
  6.     }, 
  7.     "aliases" : { 
  8.         "alias1" : {} 
  9.     } 

Rollover Index

Rollover Index 能够将现有的索引经由过程肯定的划定规矩,如数据量和工夫,索引的定名必需是 logs-000001 这类花样,并指定 aliases,示例:

  1. PUT /logs-000001  
  2.   "aliases": { 
  3.     "logs_write": {} 
  4.   } 
  5.  
  6. Add > 1000 documents to logs-000001 
  7.  
  8. POST /logs_write/_rollover  
  9.   "conditions": { 
  10.     "max_age":   "7d"
  11.     "max_docs":  1000 
  12.   } 

先建立索引并指定别号 logs_write,插入 1000 条数据,然后恳求 _rollover api 并指定拆分划定规矩。

若是索引中的数据大于划定规矩中指定的数据量大概工夫过期,新的索引将被建立,索引称号为 logs-000002,并凭据划定规矩套用 Index Template,同时别号 logs_write 也将被调换到 logs-000002。

注意事项:

  • 索引定名划定规矩必需犹如:logs-000001。
  • 索引必需指定 aliases。
  • Rollover Index API 挪用时才去搜检索引是不是超越指定划定规矩,不会主动触发,需求手动挪用,能够经由过程 Curator 实现自动化。
  • 若是相符前提会建立新的索引,老索引的数据不会发作转变,若是你已经插入 2000 条,拆分后照样 2000 条。
  • 插入数据时一定要用别号,不然您能够一向在往一个索引里追加数据。

技能是按日期转动索引:

  1. PUT /<logs-{now/d}-1> 
  2.   "aliases": { 
  3.     "logs_write": {} 
  4.   } 

如果天生的索引名为 logs-2017.04.13-1,若是您在当天实行 Rollover 会天生 logs-2017.04.13-000001,越日的话是 logs-2017.04.14-000001。

如许便会按日期停止切割索引,那若是你想查询 3 天内的数据能够经由过程日期划定规矩去婚配索引名,如:

  1. GET /<logs-{now/d}-*>,<logs-{now/d-1d}-*>,<logs-{now/d-2d}-*>/_search 

到此,我们便能够经由过程 Index Template 和 Rollover API 实现对 Index 的恣意拆分,并根据需求停止恣意时间段的兼并查询,如许只要您的工夫跨度不是很大,查询速度一样平常能够掌握在毫秒级,存储机能也不会碰到瓶颈。

Hot-Warm 架构

冷热架构,为了包管大规模时序索引及时数据剖析的时效性,能够凭据资源配置差别将 Data Nodes 停止分类构成分层或分组架构。

一部分支撑新数据的读写,另外一局部仅支撑历史数据的存储,寄存一些查询发作机率较低的数据。

即 Hot-Warm 架构,对 CPU,磁盘、内存等硬件资本公道的计划和应用,到达机能和效力的最大化。

我们能够经由过程 ES 的 Shard Allocation Filtering 去实现 Hot-Warm 的架构。

实现思绪以下:

  • 将 Data Node 凭据差别的资本配比打上标签,如:Host、Warm。
  • 界说 2 个时序索引的 Index Template,包孕 Hot Template 和 Warm Template,Hot Template 能够多分派一些 Shard 和具有更好资本的 Hot Node。
  • 用 Hot Template 建立一个 Active Index 名为 active-logs-1,别号 active-logs,支撑索引切割。
  • 插入肯定数据后,经由过程 roller over api 将 active-logs 切割,并将切割前的 Index 挪动到 Warm Nodes 上,如 active-logs-1,并阻挠写入。
  • 经由过程 Shrinking API 膨胀索引 active-logs-1 为 inactive-logs-1,本 Shard 为 5,恰当膨胀到 2 或 3,能够在 Warm Template 中指定,削减检索的 Shard,使查询更快。
  • 经由过程 force-merging api 兼并 inactive-logs-1 索引每一个 Shard 的 Segment,节约存储空间。
  • 删除 active-logs-1。

Hot,Warm Nodes

Hot Nodes

具有最好资本的 Data Nodes,如更高机能的 CPU、SSD 磁盘、内存等资本,这些特别的 Nodes 支撑索引所有的读、写操纵。

若是您企图以 100 亿为单元去切割 Index,那最少需求三个如许的 Data Nodes,Index 的 Shard 数为 5,每一个 Shard 支撑 20 亿 Documents 数据的存储。

为这类 Data Nodes 打上标签,以便我们在 Template 中辨认和指定,启动参数以下:

  1. ./bin/elasticsearch -Enode.attr.box_type=hot 

大概配置文件:

  1. node.attr.box_type: hot 

Warm Nodes

存储只读数据,而且查询量较少,但用于存储少多时间历史数据的 Data Nodes,这类 Nodes 相对 Hot Nodes 较差的硬件设置,凭据需求设置稍差的 CPU、机器磁盘和其他硬件资本,至于数目凭据需求保存多长时间的数据去配比,一样需求打上标签,要领跟 Hot Nodes 一样,指定为 Warm,box_type: warm。

Hot,Warm Template

Hot Template

我们能够经由过程指定参数"routing.allocation.include.box_type": "hot",让所有相符定名划定规矩索引的 Shard 都将被分派到 Hot Nodes 上:

  1. PUT _template/active-logs 
  2.   "template""active-logs-*"
  3.   "settings": { 
  4.     "number_of_shards":   5, 
  5.     "number_of_replicas": 1, 
  6.     "routing.allocation.include.box_type""hot"
  7.     "routing.allocation.total_shards_per_node": 2 
  8.   }, 
  9.   "aliases": { 
  10.     "active-logs":  {} 
  11.   } 

Warm Template

一样相符定名划定规矩索引的 Shard 会被分派到 Warm Nodes 上,我们指定了更少的 Shards 数目和复本数。

注重,这里的复本数为 0,和 best_compression 级别的紧缩,轻易做迁徙等操纵,和停止一些数据的紧缩:

  1. PUT _template/inactive-logs 
  2.   "template""inactive-logs-*"
  3.   "settings": { 
  4.     "number_of_shards":   1, 
  5.     "number_of_replicas": 0, 
  6.     "routing.allocation.include.box_type""warm"
  7.     "codec""best_compression" 
  8.   } 

如果我们曾经建立了索引 active-logs-1 ,固然您能够经由过程 _bulk API 快速写入测试的数据,然后参考上文中引见的 Rollover API 停止切割。

Shrink Index

Rollover API 切割今后,active-logs-1 将酿成一个热索引,我们将它挪动到 Warm Nodes 上。

先将索引置为只读状况,谢绝任何写入操纵,然后修正 index.routing.allocation.include.box_type 属性,ES 会主动挪动所有 Shards 到目的 Data Nodes 上:

  1. PUT active-logs-1/_settings 
  2.   "index.blocks.write"true
  3.   "index.routing.allocation.include.box_type""warm" 

Cluster Health API 能够检察迁徙状况,完成后停止膨胀操纵,实在相当于复制出来一个新的索引,旧的索引借存在。

  1. POST active-logs-1/_shrink/inactive-logs-1 

我们能够经由过程 Head 插件检察全部集群索引的转变状况。关于 Shard 的分派请参考:

  1. https://www.elastic.co/guide/en/elasticsearch/reference/current/shard-allocation-filtering.html 

Forcemerge

到现在为止我们曾经实现了索引的冷热星散,和索引的膨胀,我们晓得每一个 Shard 上面由多个 Segment 构成,那 inactive-logs-1 的 Shard 数是 1,但 Segment 照样多个。

这类索引不会在接管写入操纵,为了勤俭空间和改进查询机能,经由过程 Forcemerge API 将 Segment 适当兼并:

  1. PUT inactive-logs-1/_settings 
  2. "number_of_replicas": 1 } 

ES 的 Forcemerge 历程是先建立新的 Segment 删除旧的,以是旧 Segment 的紧缩体式格局 best_compression 不会在新的 Segment 中见效,新的 Segment 照样默许的紧缩体式格局。

如今 inactive-logs-1 的复本照样 0,若是有需求的话,能够分派新的复本数:

  1. PUT inactive-logs-1/_settings 
  2. "number_of_replicas": 1 } 

最初删除 active-logs-1,由于我们曾经为它做了一个查询复本 inactive-logs-1。

DELETE active-logs-1

走到这里,我们便曾经实现了 Index 的 Hot-Warm 架构,凭据业务特点将一段时间的数据放在 Hot Nodes,更多的历史数据存储于 Warm Nodes。

其他优化计划

索引断绝

金沙js娱乐场开户

在多条业务线的索引共用一个 ES 集群时会发作流量被独吃独有的状况,由于人人皆共用雷同的集群资本,流量大的索引会占用大部分盘算资本而流量小的也会被拖慢,得不到立即相应,大概道业务流量大的索引能够按天拆分,几个流量小的索引能够按周或月拆分。

这种情况下我们能够将范围大的索引和其他相对小规模的索引自力存储,离开查询或兼并查询。

除 Master Nodes 之外,Data Nodes 和 Coordinating Nodes 皆能够自力运用(实在若是每一个索引的量皆稀奇大也应当接纳这类架构),另有一个优点是对方的某个 Node 挂掉,本身不受影响。

一样应用 ES 支撑 Shard Allocation Filtering 功用去实现索引的资本自力分派,先将 Nodes 停止打标签,分别地区,类似于 Hot-Warm 架构:

  1. node.attr.zone=zone_a、node.attr.zone=zone_b 

大概:

  1. node.attr.zone =zone_hot_a、node.attr.zone=zone_hot_b 

等打标签的体式格局去区分对应差别的索引,然后在各自的 Index Template 中指定差别的 node.attr.zone 便可。

如"index.routing.allocation.include.zone" : "zone_a,zone_hot_a",

大概排除法"index.routing.allocation.exclude.size": "zone_hot_b"

分派到 zone_hot_b 之外的所有 Data Nodes 上。

更多用法能够参考 Hot-Warm 架构,或 shard-allocation-filtering:

  1. https://www.elastic.co/guide/en/elasticsearch/reference/current/shard-allocation-filtering.html 

跨数据中心

若是您的业务遍及全国各地,四海八荒,若是您数据要存储到多个机房,若是您的 Index 有几万个以至更多( Index 稀奇多,集群重大会致使 Cluster State 信息量稀奇大,由于 Cluster State 包含了所有 Shard、Index、Node 等所有相干信息,它存储在每一个 Node 上,这些数据发作转变都邑及时同步到所有 Node 上,当这个数据很大的时刻会对集群的机能形成影响)。

这些状况下我们会思索布置多个 ES Cluster,那我们将怎样处理跨集群查询的题目呢?

现在 ES 针对跨集群操纵供应了两种计划 Tribe Node 和 Cross Cluster Search。

Tribe Node

需求一个自力的 Node 节点,到场其他 ES Cluster,用法有点类似于 Coordinating Only Node。

所差别的是 Tribe 是针对多个 ES 集群之间的所有节点,Tribe Node 收到恳求播送到相干集群中所有节点,将效果兼并处置惩罚后返回。

表面上看起来 Tribe Node 将多个集群勾通成了一个整体,碰到同名 Index 发生冲突,会选择个中一个 Index,也能够指定:

  1. tribe: 
  2.   on_conflict: prefer_t1 
  3.   t1: 
  4.     cluster.name: us-cluster 
  5.     discovery.zen.ping.multicast.enabled: false 
  6.     discovery.zen.ping.unicast.hosts: ['usm1','usm2','usm3'
  7.   t2: 
  8.     cluster.name: eu-cluster 
  9.     discovery.zen.ping.multicast.enabled: false 
  10.     discovery.zen.ping.unicast.hosts: ['eum1','eum2','eum3'

Cross Cluster Search

Cross Cluster Search 能够让集群中的恣意一个节点结合查询其他集群中的数据, 经由过程设置 elasticsearch.yml 大概 API 去启用这个功用,API 示例:

  1. PUT _cluster/settings 
  2.   "persistent": { 
  3.     "search": { 
  4.       "remote": { 
  5.         "cluster_one": { 
  6.           "seeds": [ 
  7.             "127.0.0.1:9300" 
  8.           ] 
  9.     ... 
  10.         } 
  11.       } 
  12.     } 
  13.   } 

提交今后全部集群所有节点都邑见效,皆能够做为署理去做跨集群结合查询,不外我们最好照样经由过程 Coordinating Only Nodes 去提议恳求。

  1. POST /cluster_one:decision,decision/_search 
  2.     "match_all": {} 

对集群 cluster_one 和本集群中名为 Decision 的索引结合查询。

现在这个功用借在测试阶段,但将来可能会庖代 Tribe Node,之间的最大的差别是 Tribe Node 需求设置自力的节点,而 Cross Cluster Search 不需要,集群中的恣意一个节点皆能够兼任。

好比能够用我们的 Coordinating Only Nodes 做为结合查询节点,另一个长处是设置是静态的,不需要重启节点。

实际上能够明白为是一个 ES 集群之间特定的静态署理东西,支撑所有操纵,包孕 Index 的建立和修正,而且经由过程 Namespace 对 Index 停止断绝,也处理了 Tribe Node 之 Index 称号抵触的题目。

小结

我们在文中引见了几种计划用来处理时序索引的海量数据存储和查询的题目,凭据业务特性和运用场景去零丁或组合运用可以或许施展出意想不到的结果。

特别是 Nodes 之间的读写星散、索引拆分、Hot-Warm 等计划的组合运用对索引的查询和存储机能有明显的提拔。

别的 Routing 在新版本中增添了 routing_partition_size,处理了 Shard 难以平衡的题目。

若是您的索引 Mapping 中没有 parent-child 联系关系干系能够思索运用,对查询的机能提拔异常有用。

本文参考内容:

  • hot-warm-architecture-in-elasticsearch-5-x
  • managing-time-based-indices-efficiently
  • what-is-evolving-in-elasticsearch

【51CTO原创稿件,协作站点转载请说明原文作者和出处为51CTO.com】

【编纂推荐】

【责任编辑:武晓燕 TEL:(010)68476606】

点赞 0
  •     
分享:
www.36989F.com
金沙澳门官方js55658
人人皆在看
猜您喜好

编纂推荐

存眷
头条
热点
头条
热点
24H热文
一周话题
本月最赞

定阅专栏

共章 |

人定阅进修

共章 |

人定阅进修

视频课程

讲师:939人进修过

讲师:8583人进修过

讲师:27364人进修过

CTO品牌

最新专题

精选博文
论坛热帖
下载排行

读 书

本书针对低级网管同伙所需把握的网络组建和网络管理妙技,以示例体式格局编写而成,其主要特点就是实用性和可操作性异常强。 全书共分8章,分...

定阅51CTO邮刊

51CTO服务号

51CTO播客