深入解密 Elasticsearch 查询优化:巧用 Profile 工具/API 提升性能

news2024/9/20 16:39:18

1、Elasticsearch Profile 工具介绍

在使用 ES 进行检索查询时,我们常常要去优化一些复杂的查询语句,这里 ES 结合 lucene 的生态制作了 Profile API 和图形化的 Profile 分析界面以供用户使用。

这里我们来简单讲解一下这个工具 API,希望能给广大的 ES 检索用户提供一些帮助。

这里的 profile API 以 ES 8.15 版为准。

1.1 Profile API

Profile API 给用户提供了更细粒度的查询执行细节,暴露出的每个查询执行类的主要方法执行时间是用户排障优化的主要依据。

我们先来看一下 Profile 的主要执行:

GET /my-index-000001/_search
{
  "profile": true,//开启 profile 参数
  "query" : {
    "match" : { "message" : "GET /search" }
  }
}

就会发现返回的 json 结果里包含一个 profile 模块。由于 json 返回比较长,这里就不贴了,我们简要的来看看 profile 模块主要的组成结构:

{
   "profile": {
        "shards": [
           {
              "id": "[q2aE02wS1R8qQFnYu6vDVQ][my-index-000001][0]", //这里返回了分片的 id,由 节点名[q2aE02wS1R8qQFnYu6vDVQ] + 索引名[my-index-000001] + 分片号 [0]
              "node_id": "q2aE02wS1R8qQFnYu6vDVQ",
              "shard_id": 0,
              "index": "my-index-000001",
              "cluster": "(local)", //是不是本地集群解析的            
              "searches": [
                 {
                    "query": [...], // query 阶段的耗时,其中包括各种 query 执行类、执行描述以及相关方法的执行耗时            
                    "rewrite_time": 51443, // 总共的 rewrite 耗时     
                    "collector": [...] // collector 阶段的耗时,包括阶段名称、阶段描述和执行耗时           
                 }
              ],
              "aggregations": [...], //分析聚合阶段的各个执行类、执行描述以及相关方法的耗时           
              "fetch": {...} //fetch 阶段的执行类、执行描述以及相关方法的耗时                   
           }
        ]
     }
}

注意:

  1. 添加_search?human=true可以增加 profile 数据的可读性,在主要阶段的耗时数据后加上ms,micros单位。

  2. 在各阶段 breakdown 的方法里,数据单位默认都是纳秒(time_in_nanos)

1.2 kibana 的 Search Profiler

行业内有句话“一图胜千言”,清晰明了的图形化工具能大大提高分析的效率。

更何况 ES 默认返回 json 数据常常成百上千行,很容易让人读不下去。

因此 ES 在 kibana 上做了一个图形化分析模块,在 Dev Tools -> Search Profiler。

你可以将需要被解析的索引名和查询 DSL 贴入相应的区域进行直接执行Profile解析。

e5272934d46f4d6283f2aec89500399b.png


除了 query 阶段,也可以看到有 aggregation 聚合阶段。

view detail 我们还可以看到各个执行方法的耗时。

17ad8739d594c55b751498d68fad8b6c.png


除了解析执行语句,也可以直接解析 profile 结果,将 profile API 返回 json 数据直接贴入查询 DSL (Elasticsearch 查询语句)的区域执行。

affa512d9844d943c3700ba0d438ecc8.png

kibana 的 Search Profiler 的一个最大优势在于,清晰明了的展现了耗时分布,关注每个执行类的 self time 可以快速找到查询语句中最大的耗时条件

不管是 Profile API 还是 kibana 的 Search Profiler,提供的只是 ES 执行查询各阶段的方法细节。

想要判断出各个阶段的执行效率是否最佳,有没有使用误区,我们还得从 ES 查询主要阶段说起。

2、Elatsicsearch 检索核心原理

ES 是一个分布式系统,一个索引数据查询需要汇总每个索引分片的结果。

如下图,search 请求发送给 ES 后,会由内部的协调节点发送到数据节点,由数据节点上的分片去执行具体的查询任务。

6af6f89e1991f93a583cebc7a081f5b5.png

同时,大多数的 ES 查询请求是一个二阶段的查询

第一阶段数据节点上的分片接收到协调节点传来的查询请求,分片执行查询任务后,会将查询到匹配的 DocID 反馈给协调节点,协调节点会对各个分片的结果进行汇总。

第二阶段协调节点根据汇总后的 DocID,到数据对应的分片上去获取完整文档。

整个过程叫做 query and fetch,query 和 fetch 也是分片在这两个阶段主要执行的任务,也是 profile 主要分析的阶段(低版本只分析 query 阶段)。

进行二阶段查询的主要原因是为了减少 fetch 阶段的资源损耗,获取完整的文档信息涉及数据文件的读取和解压缩,需要相对多的 IO 和 cpu 资源。

为了保证数据的召回率和准确性,query 阶段需要在每个分片上获取查询完整结果,比如一个查询需要 Top 10 的结果,每个分片都会找出它的 Top 10,返回给协调节点。如果有 10 个分片,那么就需要返回 100 个结果,再由协调节点排出所有分片的 Top 10。

如果由一阶段完成,则需要 fetch 100 个文档,二阶段则只需要 fetch 10 个文档。

完整的二阶段查询流程如下图:

dbec9f46d40312266df3d5b01dc3d740.png


注:这里的流程图来自于文末的参考文档《Elasticsearch内核解析 - 查询篇》

3、Profile API 可解析的阶段

现在我们来看看 Profile API 可以解析的阶段。

3.1 query 查询阶段

Query 阶段是一阶段查询的主体,我理解是主要在二阶段查询流程中lucene::searchrescore这2个环节,这里 Profile API 将查询涉及的 lucene 执行代码类构成的一个查询树,这个查询树通过名称和描述把查询条件与执行类进行完整的勾兑,这样可以精确定位到是哪个查询条件造成了慢查询的主要耗时。

查询树重写的过程是将查询语句拆分成一个个不可被拆解的基础查询(比如 term 查询)的过程。

大部分时候查询树的结构与查询 DSL 的结构相似,有些情况下会重写的面目全非,比如:ngram 分词器,它会根据 ngram 分词器将查询内容进行细维度的拆解,最终形成一大堆 TermQuery。

下面一个例子是一个 match 查询的拆解,首先来看查询条件。

GET /_search
{
  "query": {
    "match": {
      "message": {
        "query": "get search"
      }
    }
  }
}

返回的结果。

"query": [
    {
       "type": "BooleanQuery",
       "description": "message:get message:search",
       "time_in_nanos": "11972972",
       "breakdown": {...},               
       "children": [
          {
             "type": "TermQuery",
             "description": "message:get",
             "time_in_nanos": "3801935",
             "breakdown": {...}
          },
          {
             "type": "TermQuery",
             "description": "message:search",
             "time_in_nanos": "205654",
             "breakdown": {...}
          }
       ]
    }
]

这里的主要过程:

  1. 将 match 查询重写成一个 boolean 查询,这个 boolean 查询描述是message:get message:search,展现了其总耗时(包括它的子查询耗时)和 breakdown。

  2. boolean 查询下还有两个子查询,是对 message 字段进行 get 和 search 这两个文本的 TermQuery。

  3. 分别展示了 TermQuery 的耗时/描述/breakdown。

值得注意的是,Query 阶段是 ES 查询中最容易出现慢查询的阶段

3.2 collector 聚集阶段

Collector 也由各类的子 Collector 组成,它们的主要目标是在分片内收集各个 segment 的查询结果,实现排序,对自定义结果集过滤和收集等,这也导致了在查询流程中,Add Collectors在执行 lucene 的 search 之前。

Collector 耗时独立于 Query 耗时。

它们是独立进行计算和组合的。由于 Lucene 执行的性质,不可能将来自 Collector 的耗时“合并”到 Query 部分。

"collector": [
  {
    "name": "QueryPhaseCollector",
    "reason": "search_query_phase",
    "time_in_nanos": 775274,
    "children" : [
      {
        "name": "SimpleTopScoreDocCollector",
        "reason": "search_top_hits",
        "time_in_nanos": 775274
      }
    ]
  }
]

Collector 提供的信息相对较少只提供了名称/原因/耗时。各类原因如下:

  • search_top_hits:对文档进行评分和排序的收集器。这是最常见的收集器,在大多数简单搜索中都会看到

  • search_count:仅统计符合查询条件的文档数量但不获取源的收集器。当size: 0指定 时,可以看到此信息

  • search_query_phase:一个收集器,将收集热门匹配项以及聚合作为查询阶段的一部分。它支持在n找到匹配文档后终止搜索执行(当 terminate_after指定时),以及仅返回得分大于的匹配文档n(当min_score提供时)。此外,它还能够根据提供的过滤匹配的热门匹配项post_filter。

  • search_timeout:在指定时间段后停止执行的收集器。当timeout指定了顶级参数时,就会出现这种情况。

  • aggregation:Elasticsearch 用于针对查询范围运行聚合的收集器。单个aggregation 收集器用于收集所有聚合的文档,因此您将在名称中看到聚合列表。

  • global_aggregation:针对全局查询范围(而不是指定查询)执行聚合的收集器。

3.3 rewrite 重写阶段

Lucene中的所有查询都经历了一个“重写”过程。查询(及其子查询)可能被重写一次或多次,直到只剩基础查询。

这个过程允许Lucene执行优化,例如删除冗余子句,替换一个查询以获得更有效的执行路径等。

例如,Boolean→Boolean→TermQuery可以重写为TermQuery,最终把 boolean 查询全都解析完。Query 查询树的变化也正是这个重写过程的体现。

重写过程复杂且难以显示,因为查询可能会发生巨大变化。总重写时间不是显示中间结果,该值是累积的,包含重写所有查询的总时间。

3.4 aggregations 聚合阶段

聚合部分的结构与 Query 部分类似,也是将查询树的结构展现出来。

有时候聚合可能会返回 debug 信息,这些信息描述了聚合的底层执行的特性,但大部分情况下没什么用。随着版本、聚合和聚合执行策略等条件的变化,这些信息差异很大。

3.5 fetch 获取阶段

这个就是二阶段查询中 fetch 阶段的耗时分析。

其主要内容就是加载 store_field/source/docvalue 三类存储信息。使用者也可以根据这三类字段处理格式的使用耗时,进行实际方案的选择。

其中,next_reader展示的是每个 segment 的读取计数和耗时,load_stored_fields中加载存储字段所花费的时间。

Debug 包含的是一些非耗时信息,特别是会展示 stored_fields 列出的 fetch 必须加载的存储字段;如果它是一个空列表,那么 fetch 将完全跳过加载存储字段。

4、使用局限

当然 Profile API 和 kibana 的 Search Profiler 也有相关的使用限制:

  1. Profile API 不会测试网络的开销。所有的耗时数据不包含节点间的网络耗时。

  2. Profile API 不包含在任务对列拥堵耗时、内存构建耗时、协调节点合并的耗时。

  3. kibana-Search Profiler 并不完全展示 Profile API 的信息。比如没有 fetch 阶段;没有底层方法的执行次数。

  4. kibana-Search Profiler 统计的总耗时是各个分片耗时的 sum 值,而一个查询的耗时取决于各分片耗时的 max 值。

5、小结

在 Elasticsearch 中,分片是一个最小级别的“工作单元”,它保存了索引中所有数据的一部分,同时每一个分片还是一个Lucene实例。

因此 Elasticsearch 分片执行查询过程基础类都与 lucene 相关,了解 lucene 的查询类可以增加对查询执行细节的理解。

相比起 lucene 的学习成本,Profile API 则提供了一种更为直观高效又低成本的慢查询分析工具。

通过聚焦各个执行阶段的耗时,我们直接可以定位到最大耗时的查询条件,它有可能是整个查询过于复杂,也有可能是某个字段类型不适合查询的场景。

也就是说,解决慢查询的方法并不一定要从 ES/lucene 本身去寻找,因为造成慢查询的原因并不只源于程序本身,它会是各种各样的原因,甚至是系统配置的错误、网络不稳定等等。

而 Profile API 给我们提供了更直接的印证。

6、更多慢查询优化建议

除了使用 Profile API 定位耗时的查询条件外,这里附带一些慢查询优化的建议,供读者参考:

6.1 合理利用缓存

ES 设计了多种缓存模式,有效利用缓存能保持查询的低延迟,做好缓存的监控。

6.2 设计好字段类型

特别是针对关键词字段,number 和 keyword 类型在查询和聚合方面有完全不同的查询效率,资源足够的情况下,设计双字段。

有兴趣的读一下这篇,

https://elasticsearch.cn/article/446

6.3 区分精确匹配和全文检索的使用场景。

精确匹配注重查询效率但是需要设计好数据模型;

全文检索可以面对自然语言信息的提炼,但是解析效果依赖分词器,并占用资源较多。

6.4 注意 MultiTermQuery 的出现

MultiTermQuery 是 wildcard/正则/前缀等查询常见的执行子类,这些查询容易引发大规模的资源消耗。

6.5 灵活使用 doc value

Fetch 阶段的高耗时,可以通过行存属性 source 与列存属性 doc value 的读取测试比较来选取最优方案。

7、附加 breakdown:lucene 执行类的类属方法

这里的介绍主要用于参考,lucene 实现类的方法是各种基础算法的实现,优化或者规避这些方法造成的高耗时需要对 ES 源码以及 lucene 数据文件有相当的理解和知识储备。

这也导致了,即便能看到慢查询具体的花费时间在哪个方法上,你也没办法轻易的改变它(除非自己重新实现基础的算法去维护私有版本或者贡献给社区 PR)。

每个阶段各个主要方法的耗时体现在 breakdown 内,下面做了详尽汇总,仅供参考:

7.1 query 阶段

方法名含义涉及lucene的类或者方法
create_weightLucene要求每个查询生成一个Weight对象,这个对象作为一个临时上下文对象来保存多个IndexSearcher与query相关的状态。权重度量显示了这个过程需要多长时间Query抽象类createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost):Constructs an appropriate Weight implementation for this query.
build_scorer此参数显示为查询构建Scorer所需的时间。Scorer是一种迭代匹配文档并为每个文档生成分数的机制(例如,“foo”与文档的匹配程度如何?)注意,这记录了生成Scorer对象所需的时间,而不是实际对文档进行评分。一些查询的Scorer初始化速度更快或更慢,这取决于优化、复杂性等。如果启用和/或适用于查询,这还可以显示与缓存相关的时间Scorer抽象类:A Scorer exposes an iterator() over documents matching a query in increasing order of doc id.
next_docLucene 方法next_doc返回与查询匹配的下一个文档的 Doc ID。此统计数据显示确定下一个匹配的文档所需的时间,该过程根据查询的性质而有很大差异,不同的实现类以及数据结构会有完全不同的效率。Next_doc 是 advance() 的一种特殊形式,对于 Lucene 中的许多查询来说更为方便。它相当于 advance(docId() + 1)DISI 抽象类 nextDoc():Advances to the next document in the set and returns the doc it is currently on, or NO_MORE_DOCS if there are no more docs in the set.
advanceadvance是 next_doc 的“低级”版本:它用于查找下一个匹配的文档,但需要调用查询执行额外的任务,例如识别和跳过跳过等。但是,并非所有查询都可以使用 next_doc,因此advance这些查询也会计时。DISI抽象类 advance(int target):Advances to the first beyond the current whose document number is greater than or equal to target, and returns the document number itself.
match某些查询(例如短语查询)使用“两阶段”过程匹配文档。首先,文档“近似”匹配,如果近似匹配,则使用更严格(且昂贵)的过程再次检查。第二阶段验证是统计数据所衡量的match。由于只有少数查询使用这个两阶段过程,因此match统计数据通常为零PhraseMatcher类:Base class for exact and sloppy phrase matching
score这记录了通过评分器对特定文档进行 Scorer 所花费的时间Scorer 抽象类 score():Returns the score of the current document matching the query.
*_count记录特定方法的调用次数。例如,"next_doc_count": 2, 表示该nextDoc()方法在两个不同的文档上被调用。这可以通过比较不同查询类之间的计数来帮助判断查询的选择性。

7.2 aggregations 阶段

方法名含义
build_aggregation创建聚合对象需要的时间
initialize初始化聚合所耗费的时间
collect对聚合结果进行 collect
build_leaf_collector运行聚合的 getLeafCollector() 方法所花费的时间
post_collectionpost 查询 collect 耗时
reducereduce 属性保留以供将来使用,并且总是返回0
*_count记录特定方法的调用次数

8、参考资料

[1] kibana search profiler:

https://www.elastic.co/guide/en/kibana/current/xpack-profiler.html

[2] Profile API:

https://www.elastic.co/guide/en/elasticsearch/reference/current/search-profile.html

[3] Elasticsearch内核解析 - 查询篇:

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

作者介绍

金多安,Elastic 认证专家,Elastic 资深运维工程师,死磕 Elasticsearch 知识星球嘉宾,星球Top活跃技术专家,搜索客社区日报责任编辑

铭毅天下审稿并做了部分微调。

更多推荐

  1. Elasticsearch 使用误区之一——将 Elasticsearch 视为关系数据库!

  2.   Elasticsearch 使用误区之二——频繁更新文档

  3.  Elasticsearch 使用误区之三——分片设置不合理

  4. Elasticsearch 使用误区之四——不合理的使用 track_total_hits

  5. Elasticsearch Filter 缓存加速检索的细节,你知道吗?

  6. 深入解析 Elasticsearch IK 分词器:ik_smart 和 ik_max_word 的区别与应用场景

  7. 图解 Elasticsearch 的 Fielddata Cache 使用与优化

  8. 探究:Elasticsearch 文档的 _id 是 Lucene 的 docid 吗?

  9.    《一本书讲透 Elasticsearch》读者群的创新之路

8fbcaf8386e648c4118b60b6c48f958f.png

更短时间更快习得更多干货!

和全球2000+ Elastic 爱好者一起精进!

elastic6.cn——ElasticStack进阶助手

1ff8d8479b52f8ee46b7a963ebc4cce9.gif

抢先一步学习进阶干货!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2108649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

全双工语音交互

文章目录 微软小冰全双工字节大模型语音交互[Language Model Can Listen While Speaking](https://arxiv.org/html/2408.02622v1) 微软小冰全双工 全双工的定义:一路持续的听,upload audio;一路持续的输出,download audio&#xf…

C#中的Graphics类和SetQuality()自定义方法

在 C# 中,Graphics 类是 System.Drawing 命名空间的一部分,它提供了一组方法和属性,用于在 Windows Forms 应用程序中进行二维绘图。Graphics 对象可以绘制文本、线条、曲线、形状和图像,并可以对它们进行变换和剪辑。 Graphics …

【JAVA入门】Day33 - Collections

【JAVA入门】Day33 - Collections 文章目录 【JAVA入门】Day33 - Collections Collections 是集合的工具类。其包含的方法如下表所示,其中前两个方法最为常用。 以下代码演示了如何创建集合并批量添加数据,然后打乱集合元素顺序,然后用二分法…

数据结构:(LeetCode203)移除链表元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val val 的节点,并返回 新的头节点 。 示例 1: 输入:head [1,2,6,3,4,5,6], val 6 输出:[1,2,3,4,5]示例 2: 输入&#xff1…

代码随想录:343. 整数拆分

343. 整数拆分 class Solution { public:int integerBreak(int n) {int dp[100]{0};//拆分i的最大乘积为dp[i]dp[1]1;//初始化&#xff0c;主要是为了dp[2]初始for(int i2;i<n;i){for(int j1;j<i;j){ dp[i]max(dp[i],max(j,dp[j])*max(i-j,dp[i-j]));//取最大值&#x…

深入Linux轻量级进程管理:线程创建、线程ID解析与进程地址空间页表探究

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 &#x1f6b2;Linux线程控制&#x1f40f;POSIX线程库&#x1f415;创建线程&#x1f41f;指令查看轻量级进程指令&#xff1a;ps -a…

Python(TensorFlow)和Java及C++受激发射损耗导图

&#x1f3af;要点 神经网络监督去噪预测算法聚焦荧光团和检测模拟平台伪影消除算法性能优化方法自动化多尺度囊泡动力学成像生物研究多维分析统计物距粒子概率算法 Python和MATLAB图像降噪算法 消除噪声的一种方法是将原始图像与表示低通滤波器或平滑操作的掩模进行卷积。…

汇编伪指令 GNU 风格(24)

先来看看关于标号的内容。 这里的局部标号是需要注意的。 全局标号&#xff0c;以及注释 可以不看。 来看一个例子&#xff1b; 这里的 BSYM 我不知道是什么意思。 在来看看关于伪操作的内容&#xff0c; 一般是以 . 开头的。 这是基本的一些操作。 然后是举例&#xff1a; …

前后端时间正确传递

引言&#xff1a;后端传递给前端去展示时间的时候将时间转化为String类型的时间数据去返回。此时就需要加上 JsonFormat 注解来解决这个问题。 框架环境配置中&#xff0c;时间配置为 情形一&#xff1a; 数据库字段exam_time类型为date 后端实体类中examTime类型为Date 1.前…

搭建VUE+VScode+elementUI环境遇到的问题

手把手教你搭建VUEVScodeelementUI开发环境-CSDN博客 vue : 无法加载文件 C:\Users\xxx\AppData\Roaming\npm\vue.ps1&#xff0c;因为在此系统上禁止运行脚本 vue : 无法加载文件 C:\Users\xxx\AppData\Roaming\npm\vue.ps1&#xff0c;因为在此系统上禁止运行脚本 - 知乎 更…

Django+Vue家居全屋定制系统的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 需要的环境3.2 Django接口层3.3 实体类3.4 config.ini3.5 启动类3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质创作者&…

虚拟机苹果系统MacOS中XCode的安装

1、背景介绍 主机系统Win11&#xff0c;虚拟机VMWare17&#xff0c;苹果系统MacOS 13.6.7 2、Xcode的在线 点击应用市场&#xff0c;输入Xcode搜索&#xff1a; 看来Xcode无法安装在macOS V13上&#xff0c;直接在线安装失败。 3、采用下载安装包的方法进行安装 解决办法参考链…

Linux操作系统下的一些常用命令分享(ubuntu16.04)

注意一般Linux命令字符与字符之间都是空格来隔开的&#xff0c;所以千万不能忘记打空格&#xff0c;而且Linux区分大小写。&#xff08;目录就是文件夹&#xff09; 1、pwd 查看当前所在目录 2、查看帮助 命令 --help 但是这个命令会把所有内容一次性全部显示我们看帮助时很…

Linux远程管理工具推荐

原文阅读:【巨人肩膀社区专栏分享】Linux远程管理工具推荐 前两天xshell不让用了&#xff0c;刚好一台新电脑要装一个远程连接工具&#xff0c;准备试试其他。网上找了一些资料整理如下。 欢迎各位看官评论区说出你在使用的工具&#xff0c;期待你的使用经验分享&#xff08;…

Git的基本使用(持续更新)

基本使用 创建仓库 命令&#xff1a;git initgit init&#xff1a;将当前文件夹作为Git仓库&#xff0c;并在该文件夹中生成一个.git目录&#xff0c;该目录包含了资源的所有元数据&#xff0c;不可修改里面的内容。 git init newWareHouse&#xff1a;新建一个newWareHouse…

JVM性能监控和调优

JVM性能监控和调优 文章目录 JVM性能监控和调优性能优化的步骤GC日志分析GC日志参数测试GC分类日志结构 OOM&#xff1a;堆溢出模拟堆溢出dump文件分析gc日志分析 OOM&#xff1a;元空间溢出模拟元空间溢出dump文件分析原因及解决方案 OOM&#xff1a;GC overhead limit exceed…

python学习第二节:安装开发工具pycharm

python学习第二节&#xff1a;安装开发工具pycharm 1.下载安装包&#xff1a;https://www.jetbrains.com/pycharm/ 点击 Download 下滑页面到下面的社区版&#xff0c;&#xff08;上面的专业版是收费的&#xff0c;下面的社区版是免费的&#xff09; 2.安装 点击安装文件 …

计算机基础知识复习9.5

数据交换 电路交换&#xff1a;交换信息的两个主机之间简历专用通道&#xff0c;传输时延小&#xff0c;实时性强&#xff0c;效率低&#xff0c;无法纠正错误。 报文交换&#xff1a;信息拆分成小包(报文&#xff09;大小无限制&#xff0c;有目的/源等信息提高利用率。有转…

C++入门项目:Linux下C++轻量级Web服务器 跑通|运行|测试(小白进)

TinyWebServer是一个开源的项目&#xff0c;适合小白入门C网络编程&#xff0c;注意该项目是在linux系统下。 Linux下C轻量级Web服务器&#xff0c;助力初学者快速实践网络编程&#xff0c;搭建属于自己的服务器. 使用 线程池 非阻塞socket epoll(ET和LT均实现) 事件处理(R…

时钟分频流程

具体流程&#xff1a; 外部晶振&#xff08;XTIpll&#xff09;和 外部时钟&#xff08;EXTCLK&#xff09;经过OM【3&#xff1a;2】选择进入时钟模块 我们可以看到&#xff0c;在不同的模式下会选择不同的时钟源和状态。 时钟信号进入锁相环(PLL)后&#xff0c;会改…