观测云实现日志存储与分析 10 倍性价比提升|SelectDB 技术团队

作者:观测云 CEO 蒋烁淼 & 飞轮科技技术团队

在云计算逐渐成熟的当下,越来越多的企业开始将业务迁移到云端,传统的监控和故障排查方法已经无法满足企业的需求。而观测云可提供整体数据的分析、洞察、可视化、自动化、监测告警、智能巡查、安全巡查等服务。为更好提供上述服务,要求观测云能够统一整合来自多个场景和多种结构的海量数据,并提供全面的日志检索分析能力,快速实现数据查询、筛选和分析。

因此,飞轮科技与观测云进行了全面合作。通过 SelectDB 的倒排索引能力、Variant 数据类型、冷热数据分层存储等特性,为观测云日志存储和分析场景服务注入强大的动力,实现存储成本降低 70% 的同时,查询性能提升 2-4 倍,最终实现整体性价比 10 倍提升!

GuanceDB 原有架构

观测云-原有架构.PNG

观测云具备强大的数据接入能力,通过自研的 All In One 采集工具 DataKit 可以从不同端侧、业务层、中间件、基础设施等不同层获取数据,同时进行预处理和元信息关联。除了广泛支持日志数据以外,Datakit 还支持采集和处理基础设施的时序指标、链路追踪、安全事件以及在 APP 端或浏览器端的用户行为数据等。为了满足多元化的多场景需求,DataKit 不仅对开源探针和采集器进行了全面兼容,还支持对自定义格式的数据源接入。

DataKit 采集的数据,经过核心计算层处理后,会统一存储到 GuanceDB 中。GuanceDB 是一个观测云自主研发的由多种数据库技术组成的多模态数据库。

观测云-原有架构2.png

GuanceDB 的内部架构如上图所示,主要包含查询引擎 Query Engine 和存储引擎 Storage Engine 两层。在逻辑结构上查询引擎与存储引擎通过抽象解耦,整体架构上实现了可拔插可替换。

观测云基于 VictoriaMetrics 存储模块研发了时序存储引擎 Metric Store,同时在泛日志场景集成了 Elasticsearch/OpenSearch。这样的设计使 GuanceDB 对外有统一的写入和查询接口,能适应不同类型的数据格式和业务需求。在当前的实现中,MetricStore 已经具备卓越的性能。然而,对于日志类和用户行为类数据的处理来说,Elasticsearch 却有诸多不足,具体表现如下:

  • 写入占用资源多:Elasticsearch 在处理高频写入大量的数据时,会占用较高的 CPU 和内存资源,这不仅会显著增加集群成本,还会挤占查询所占用的资源。
  • 对无模式表支持差:Elasticsearch 对于 Schemaless 支持有限,当前的 Dynamic Mapping 在面对大量的用户自定义字段时,会频繁造成字段类型冲突,导致数据丢失,需要人工介入进行手动处理。
  • 聚合查询性能差:Elasticsearch 在面对海量数据时,聚合性能表现较差。例如对亿级数据计算分位数、错误率时,极易出现超时,很难满足大规模数据下的业务分析需求。

选型目标及调研

原有架构中 Elasticsearch 存在的问题推动我们对架构进行升级,在升级之前,我们调研了包括 SelectDB 在内的多款数据库。结合实际可观测性场景,我们选型目标如下:

  • 高吞吐高性能:在可观测场景下,业务数据的规模会随着业务复杂度和业务规模线性递增。为满足这一需求,我们需要一种既能支持高吞吐实时写入,又能支持高性能数据分析,同时集群本身易于运维、支持横向拓展的存储方案。
  • 全文倒排索引:全文倒排索引能够显著提升检索性能并降低查询的资源开销,是实现高效日志分析的必备能力。在调研中,我们也注意到了像 Loki 这样的无索引方案, 这类方案虽然简单,但当请求 QPS 稍高时,全盘扫描时磁盘 IO 和 CPU 资源开销争抢就会非常激烈,无法承载日志图表展示、聚类筛选分析、实时告警等业务需求。
  • 支持多种业务写入和查询场景:观测云采集的业务场景丰富多样,包括海量吞吐的追加写、进程和主机等对象数据的整体周期性更新、 RUM 场景下 Session 会话部分更新等,同时覆盖高频点查、列表查询、大范围聚合查询等多种查询场景,这就需要新方案能够支持多种业务写入和多样化场景查询。
  • 支持无模式表:可观测业务场景中有大量的字段元信息是业务工程师根据业务需求手工维护的,为了更好的适配这种场景,存储层就需要支持 SchemaLess,无需上层业务维护数据表的 Schema 信息,并且能够自动处理类型冲突。
  • 支持大规模租户隔离:在 SaaS 场景中,我们有大量的租户和分表,这些元数据本身会给系统造成较大管理压力。在使用 Elasticsearch 时,其单个集群能支持的索引数有限,一旦达到某个索引数量,性能就会急剧下降,因此需要将数据分散到不同的集群中,这给集群管理造成了诸多困扰
  • 降低长期存储成本:可观测类的数据价值会随时间迁移而递减,我们希望能通过冷热分离、存算分离等技术手段,将长期存储的数据保存到对象存储中,以降低数据的总体存储成本。

综合来看,SelectDB 能够满足观测云的大部分需求,并且在与同类产品的对比中表现出色,我们也会在后面的章节中详细介绍基于 SelectDB 的改造实践。特别值得一提的是,在前期调研中,以下特性是吸引我们的重要特性:

  • SelectDB 倒排索引可使得存储空间节约超 80% 、写入速度是 Elasticsearch 的 5 倍、查询性能是 Elasticsearch 的 2.3 倍。
  • SelectDB 针对 JSON 等半结构化数据设计了 Variant 数据类型,可以将任意结构的 JSON 存入 Variant 类型中,可以对 JSON 内部的字段和类型自动分析、对频繁出现的字段采用列式存储,提升存储和分析的效
  • SelectDB 可以支持上千个数据库和上万个数据表,能够实现一个租户独立使用一个数据库,实现多租户数据隔离的需求,满足数据的隔离和安全性。

基于 SelectDB 的存储架构升级

因此我们引入 SelectDB 对 GuanceDB 内部架构进行升级,为了更好地介绍 SelectDB 如何在 GunaceDB 中作为存储引擎发挥作用,我们首先介绍一下 DQL 查询语言。

在可观测性场景中,几乎所有的查询都涉及时间的筛选,同时大部分的聚合也需要按照时间窗口来进行,并且针对时间序列,还需要支持按单个序列在时间窗口前后进行 Rollup。在这些场景中,使用 SQL 来表达相同的语义就需要嵌套多层子查询,导致表达过程和编写都异常复杂。

因此我们尝试简化语法元素,在此基础上设计出了新的查询语言 DQL,并且增强了在可观测场景下的常见计算函数,通过 DQL 即可查询指标、日志、链路追踪、对象等所有的可观测数据。

从 GuanceDB 内部结构来看,本次升级我们使用 SelectDB 替换了 Elasticsearch/OpenSearch,原有的查询架构保持不变。

观测云-架构升级.png

接下来我们介绍在引入 SelectDB 之后,DQL 查询是如何工作的:

观测云-架构升级2.png

如上图所示,Guance-Insert 是数据写入组件,Guance-Select 是 DQL 查询引擎。

  • 在 Guance-Insert 中,实现了分租户的数据攒批逻辑,均衡了写入吞吐量和写入延迟两大指标,尽量高效地将数据通过 Stream Load 接口写给 SelectDB Doris BE 组件。当海量日志产生时,该方式攒批速度很快,平均日志入库延迟在 2-3 秒。
  • 在 Guance-Select 中, Guance-Select 会根据当前查询 SelectDB 的 SQL 支持情况,选择是否将查询下推给 FE 计算。通常情况下,常见的聚合查询都可以下推给 FE 计算,但当遇到 FE 不支持的 SQL 语义或函数时,我们就会选择 Fallback 到仅下推谓词到 BE,通过 Thrift RPC 接口获取 Arrow 格式的列存数据,再在 Guance-Select 中计算。由于此方案无法将计算逻辑下推 BE ,因此实际性能会略差于在 FE 中的查询。不过在大部分场景下,这种方案是可以满足需求的。

当前的查询架构是综合 FE 和 BE 能力的混合计算架构,DQL 即可以利用 SelectDB 已经充分优化的查询能力,也可以让语法拓展不受 SelectDB 本身 SQL 能力的限制。

架构升级的收益

01 存储成本降低约 70%、查询性能提升 3 倍

SelectDB 的引入,实现了综合成本的大幅降低。之前我们在云上某可用区使用的是由 20 台 16C 64G 云主机组成的 Elasticsearch 集群提供查询服务,同时采用了独立的索引写入服务(相当于使用 20 台云主机)。在替换成 SelectDB 之后,只需要 13 台同配置的云主机,总成本下降了 67%。成本的大幅降低主要得益于两个因素:

  • SelectDB 写入性能高于 Elasticsearch :在应对 1GB/s 的持续高吞吐写入时,SelectDB 所占用 CPU 保持在 20% 以下,折合约占 2.6 台云主机的成本,仅为 Elasticsearch 索引写入服务成本的 13%。这一优势可以在降低写入成本的同时应对更大的突发流量,保障系统的稳定性。

观测云-写入速度.png

观测云- BE占用CPU.png

  • SelectDB 数据和索引压缩率高于 Elasticsearch:SelectDB 数据和索引采用列式存储和 ZSTD 压缩技术,使得线上集群整体压缩比可达 1:8 ,而 Elasticsearch 压缩比只有 1:1.5,因此使用 SelectDB 时,所占用存储空间仅是 Elasticsearch 的 20% 左右。
  • SelectDB 支持冷热数据分层存储:我们可以将近期较频繁查询的热数据存储在本地盘,长时间不使用的冷数据自动上传至对象存储中,这样可大幅降低数据存储成本。同时,SelectDB 支持根据存储策略的配置自动进行冷热数据迁移,并且数据生命周期管理和查询对上层应用透明,使用起来更加灵活方便。此外,SelectDB 还可通过本地 Cache 加速对冷数据的访问,从而提升用户查询冷数据的使用体验。

SelectDB 的引入,实现了查询性能显著提升。在减少机器数量以后,我们对比了相同的查询在两个集群下的性能,实践表明 SelectDB 的点查和列表查询速度比 Elasticsearch 快近 2 倍,在聚合查询不进行采样的情况下,SelectDB 相比 Elasticsearch 快将近 4 倍。

综上,采用 SelectDB 替换 Elasticsearch 后,仅使用 Elasticsearch 的 1/3 成本、获得 2~4 倍的性能提升,整体性价比提升了近 10 倍!

02 倒排索引满足日志场景全文检索需求

倒排索引能够显著提升全文检索的性能并降低查询的资源开销,是实现高效日志分析的必备能力。SelectDB 支持倒排索引,以下是我们从 Elasticsearch 迁移到 SelectDB 过程中关键能力的介绍:

  • 支持字符串全文检索,包括可同时匹配多个关键字 MATCH_ALL、匹配任意一个关键字 MATCH_ANY 、匹配短语词组 MATCH_PHRASE 的查询方式。我们对日志文本内容创建倒排索引时使用 MATCH_PHRASE 进行查询,能够完整覆盖原来在 Elasticsearch 上的功能。
  • 支持英文、中文及 Unicode 多语言分词,中文分词还支持自定义词库、自定义停用词。我们将原先在 Elasticsearch 上使用的中文词库和停用词配置到 SelectDB 上,完成了用户体验平滑迁移。
  • 加速普通的等值(=, !=, IN)、范围查询(>, >=, <, <=),同时支持数字、日期、字符串类型。
CREATE TABLE httplog
(
  `ts` DATETIME,
  `clientip` VARCHAR(20),
  `request` TEXT,
  INDEX idx_ip (`clientip`) USING INVERTED, --不分词
  INDEX idx_req (`request`) USING INVERTED PROPERTIES("parser" = "chinese") --中文分词
)
DUPLICATE KEY(`ts`)
...

-- 查询clientip为'8.8.8.8'的最新10条数据
SELECT * FROM httplog WHERE clientip = '8.8.8.8' ORDER BY ts DESC LIMIT 10;
-- 检索request字段中有error或者404的最新10条数据
SELECT * FROM httplog WHERE request MATCH_ANY 'error 404' ORDER BY ts DESC LIMIT 10;
-- 检索request字段中有image和faq的最新10条数据
SELECT * FROM httplog WHERE request MATCH_ALL 'image faq' ORDER BY ts DESC LIMIT 10;
-- 检索request字段中有'查询错误'词组的最新10条数据
SELECT * FROM httplog WHERE request MATCH_PHRASE '查询错误' ORDER BY ts DESC LIMIT 10;

除了在功能上能够满足日志全文检索的需求,SelectDB 倒排索引还支持在线按需增减索引。Elasticsearch 索引在创建时是固定的,后续无法新增索引字段,这就需要提前规划哪些字段需要建立索引,后续如需变更索引则需要重写,变更成本非常高。SelectDB 支持在运行过程中按需增加索引,新写入的数据索引立即生效。同时 SelectDB 可以控制对哪些分区创建索引,使用起来非常灵活。

03 Variant 数据类型,解决数据 Schema 频繁变化痛点

在可观测场景中,数据的种类繁多且变化频繁。例如我们在收集用户在网页上的每一次点击、每一次导入等行为时,都可能会追加新的业务指标,这样的场景对数据库的 Schema 变更实时性提出了更高的要求。

在常见的数据库中,大部分数据表的 Schema 是静态的,也有一些数据库如 Elasticsearch 可以通过 Mapping 实现动态 Schema。然而,动态 Schema 可能会遇到字段类型冲突或因历史字段不失效而导致字段数量达到上限的问题。在引入 SelectDB 之后,我们使用最新特性 Variant 动态数据类型(该特性将在 Apache Doris 2.1 版本中正式发布)可以很好地支持这类场景。

SelectDB 针对半结构化数据设计了 Variant 数据类型,具备以下特色能力

  • 支持任何合法的 JSON 数据存储在 Variant 类型的列中,并且能够自动识别 JSON 中的子字段和类型。
  • Variant 数据类型可以避免字段过多导致的 Schema 爆炸问题。对于频繁出现的子字段,Variant 类型采用列式存储方式,以提高数据存储和分析的效率。而对于不频繁出现的子字段,Variant 类型则会将其合并为一列进行存储,以避免列的数量过大。
  • Variant 数据类型可以避免业务变更字段类型冲突无法写入的问题。Variant 允许一个字段存在不同的类型,并采用不同的存储方式,对新老数据采用不同的类型存储,对于新老交替的混合部分采用最小公共类型存储。

Variant 类型与 Elasticsearch Dynamic Mapping 最显著区别在于,Dynamic Mapping 的作用域是当前表的完整生命周期,而 Variant 的作用域只在当前的动态分区内。这个差异化的设计使得 Variant 列可以随着业务数据写入的变化而周期性失效,从而降低类型冲突的概率。例如,当我们今天变更了业务逻辑代码,并对部分业务字段进行了重命名,那么旧的字段名将不会出现在明天的 Variant 列中。因此,我们可以认为 Variant 只维护了最新数据的类型数据。

另外当单个分区内的字段类型冲突时会升级到 JSON 数据类型,从而避免出现数据错误和数据丢失的问题。例如业务系统中有两处都用到了 status 字段,其中一处为字符串,一处为数字,那么我们在查询时可以根据实际的语义来选择当前查询需要的是字符串、数字或二者都要。(假设在筛选条件中写 status = "ok",此时就只会筛选 status 类型为字符串的数据。)

使用 Variant 数据类型后,在实际的写入和查询中,用户都无需感知 Variant 的存在。用户可以根据自身的业务需求增删字段,就如同使用普通列一样。在进行查询时,也无需额外的语法或注解,只需要将其当成普通列进行运算即可。

在当前版本中,Variant 数据类型在使用时还需要额外的类型断言,自动的类型断言将在后续版本中更新。而当前在 DQL 的查询中,我们已经实现 Variant 列的自动类型断言。大部分情况下可直接根据 Variant 的实际数据类型来直接进行断言,只有极少数类型冲突的情况下 Variant 列会升级到 JSON 数据类型,此时我们会根据 DQL 查询中的聚合算子或操作符关联语义来进行实际断言。

04 设计采样逻辑,加速聚合查询性能

在适配过程中我们发现,尽管 SelectDB 性能强大,但在需要对超大数据集进行聚合计算时,仍然会占用较多的系统资源,计算的开销相对很高。而在可观测场景中,大部分的计算都是定性分析,而不是定量的绝对值精确分析。

基于这样的业务背景,我们在 GunaceDB 中设计了如下的采样逻辑:

  • 估算查询时间范围内的原始数据行数,当需要查询的原始数据行数大于 1000 万时开启采样,并固定采样行数为 1000 万反推计算采样率。
  • 在存储层利用 SelectDB 的 TableSample 能力进行实际数据采样,配合一定的表写入均衡策略,保证聚合结果不产生严重偏差。
  • 在查询引擎层,根据不同的聚合算子适配采样结果,大部分的分位数、平均值之类计算无需处理,仅需要处理 Sum 和 Count 函数等比例放大。
  • 当 Count 聚合查询在采样后命中结果过少时,我们会关闭采样重新查询,避免大的误差出现。此外,我们会在响应结果中标注采样率,当用户怀疑采样结果有偏差时可以关闭采样重新发起请求。

在这样的采样逻辑下,可以显著减少超大规模计算所需的计算开销和用户等待时间,相比之前有数十倍的性能提升,极大的提升了用户的使用体验。

结束语

SelectDB 的引入满足了我们 Schema Free 的要求,解决了数据 Schema 频繁变化痛点;提高了数据写入的性能,保证了数据写入的时效性和查询的实时性;提升了全文检索的性能并降低查询的资源开销… 总而言之,SelectDB 的应用,使观测云最终实现存储成本降低 70% 的同时,查询性能提升 2-4 倍,最终实现整体性价比 10 倍提升!未来,我们还将持续与飞轮科技协作,打造更受用户欢迎的解决方案,同时也将共同推动 Apache Doris 社区的发展和壮大!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

单周爆售150w+,“不是羽绒服买不起,而是军大衣更有性价比”

拼多多收盘市值超过阿里&#xff0c;成在美中概股市值第一。 截至美股收盘&#xff08;11月30日&#xff09;&#xff0c;拼多多收盘市值超过阿里巴巴&#xff0c;成为在美中概股中的市值第一股。拼多多收涨4.03%&#xff0c;报147.44美元&#xff0c;市值1959亿美元&#xff…

Tiled Matrix Multiplication

if(true) { (function(i,s,o,g,r,a,m){i[‘GoogleAnalyticsObject’]r;i[r]i[r]||function(){ (i[r].qi[r].q||[]).push(arguments)},i[r].l1*new Date();as.createElement(o), ms.getElementsByTagName(o)[0];a.async1;a.srcg;m.parentNode.insertBefore(a,m) })(window,docum…

uniapp微信小程序分包,小程序分包

前言&#xff0c;都知道我是一个后端开发、所以今天来写一下uniapp。 起因是美工给我的切图太大&#xff0c;微信小程序不让了&#xff0c;在网上找了一大堆分包的文章&#xff0c;我心思我照着写的啊&#xff0c;怎么就一直报错呢&#xff1f; 错误原因 tabBar的页面被我放在分…

五肽-13|提亮肤色,美白肌肤

五肽-13 INCI名称&#xff1a;五肽-13 说明&#xff1a; 五肽-13是一种合成肽&#xff0c;由丙氨酸、精氨酸、赖氨酸、脯氨酸和缬氨酸组成 功能&#xff1a; 五肽-13起到增白剂的作用 应用程序&#xff1a; 提亮和美白

2023年2月8日 Go生态洞察:Profile-Guided Optimization预览

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

Streamlit框架的定制化

Streamlit框架的定制化 最近做了一个关于streamlit框架的项目&#xff0c;颇有感触&#xff0c;所以在这里记录一下。 什么是streamlit? Streamlit 是一个python的WEB UI库&#xff0c;它做了高度的封装以便于不懂后前端开发的人员也能轻松构建画面。你可以从官网进行详细的…

Linux文件结构与文件权限

基于centos了解Linux文件结构 了解一下文件类型 Linux采用的一切皆文件的思想&#xff0c;将硬件设备、软件等所有数据信息都以文件的形式呈现在用户面前&#xff0c;这就使得我们对计算机的管理更加方便。所以本篇文章会对Linux操作系统的文件结构和文件权限进行讲解。 首先…

halcon如何设置窗口背景颜色?

halcon窗口背景默认是黑色&#xff0c;有时候图片背景是黑色&#xff0c;不方便观察边缘&#xff0c;如果需要设置窗口背景颜色&#xff0c;可以使用如下算子。 设置窗口背景颜色&#xff1a;白色 set_window_param (WindowHandle, background_color, white) 设置白色后的效…

13款趣味性不错(炫酷)的前端动画特效及源码(预览获取)分享(附源码)

文字激光打印特效 基于canvas实现的动画特效&#xff0c;你既可以设置初始的打印文字也可以在下方输入文字可实现激光字体打印&#xff0c;精简易用。 预览获取 核心代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8&q…

关于 mapboxgl 的常用方法及效果

给地图标记点 实现效果 /*** 在地图上添加标记点* point: [lng, lat]* color: #83f7a0*/addMarkerOnMap(point, color #83f7a0) {const marker new mapboxgl.Marker({draggable: false,color: color,}).setLngLat(point).addTo(this.map);this.markersList.push(marker);},…

从【注意力机制】开始的,零基础【大模型】系列

注意力机制 原理&#xff1a;从关注全部到关注重点软注意力-计算方式传统注意力问题 键值注意力&#xff1a;单标签的检索系统计算方式 多头注意力&#xff1a;多标签的检索系统自注意力&#xff1a;对输入数据内部关系进行预处理计算方式 Transformer 原理&#xff1a;从关注全…

医院预约挂号平台的设计与实现

摘 要 网络的空前发展给人们的工作和生活带来了极大的便利&#xff0c;信息技术已成为节约运营成本、提高工作效率的首选。相比之下&#xff0c;国内相当多的中小医院在医院预约工作中的手工工作比较保守&#xff0c;数据查询和存储成本都很高&#xff0c;但效率很低。为了使医…

docker-compose部署sonarqube 8.9 版本

官方部署文档注意需求版本 所以选择8.9版本 一、准备部署配置 1、持久化目录 rootlocalhost:/root# mkdir -p /data/sonar/postgres /data/sonar/sonarqube/data /data/sonar/sonarqube/logs /data/sonar/sonarqube/extensions rootlocalhost:/root# chmod 777 /data/sona…

天眼销为电销行业降低获客成本

当下&#xff0c;做电销的老板都有一个深刻体会&#xff1a;市场竞争越来越激烈&#xff0c;获客成本不断攀升&#xff0c;但效率不升返降&#xff0c;企业经营困难。特别是在这一两年&#xff0c;市场环境紧张&#xff0c;业务不好开展&#xff0c;更是雪上加霜。 销售也感觉…

Matlab 曲线动态绘制

axes(handles.axes1); % 选定所画坐标轴 figure也可 h1 animatedline; h1.Color b; h1.LineWidth 2; h1.LineStyle -; % 线属性设置 for i 1 : length(x)addpoints(h1,x(i),y(i)); % x/y为待绘制曲线数据drawnow;pause(0.01); % 画点间停顿 end 示例&#xff1a; figure…

BearPi Std 板从入门到放弃 - 引气入体篇(8)(ADC)

简介 基于前面的文章, 缩略STM32CubeMx创建项目的过程&#xff0c;直接添加ADC相关初 始化; 开发板 &#xff1a; Bearpi Std(小熊派标准板) 主芯片: STM32L431RCT6 LED : PC13 \ 推挽输出即可 \ 高电平点亮 串口: Usart1 ADC1: PC2步骤 创建STM32CubeMX LED/串口ADC1初始…

「音视频处理」音频编码AAC详解,低码率提高音质?

AAC&#xff08;高级音频编码&#xff09; 也称为 MPEG-4 音频。数码音频压缩和编码的标准方式。AAC 编码文件可与音乐光盘的质量相匹敌&#xff0c;且声音质量通常等同于或高于以相同或甚至更高的位速率编码的 MP3 文件。 我们按这样的顺序讨论 &#xff1a; 1、 封装格式的…

如何使用 Zotero 导出所选条目的 PDF 文件

如何使用 Zotero 导出所选条目的 PDF 文件 Zotero 是一款强大的参考文献管理工具&#xff0c;但它并不直接提供将整个文件夹导出为 PDF 的选项。不过&#xff0c;您可以使用以下步骤来导出您所选的 Zotero 条目中的 PDF 文件&#xff0c;无需额外的插件。 选择所需的 Zotero 条…

2023年危险化学品生产单位安全生产管理人员证考试题库及危险化学品生产单位安全生产管理人员试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年危险化学品生产单位安全生产管理人员证考试题库及危险化学品生产单位安全生产管理人员试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&a…

二叉树链式结构

1.前置说明 我们手动构建一棵二叉树&#xff1a; 注意&#xff1a;上述代码并不是创建二叉树的方式 从概念中可以看出&#xff0c;二叉树定义是递归式的&#xff0c;因此后序基本操作中基本都是按照该概念实现的 2.二叉树的遍历 2.1前序、中序以及后序遍历 学习二叉树结构&a…