叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践

news2024/11/18 10:33:35

导读: 随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时 OLAP 数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入 Apache Doris 作为最终的 OLAP 分析引擎,Doris 作为核心的 OLAP 引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。

作者叮咚买菜资深数据工程师 韩青

叮咚买菜创立于 2017 年 5 月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵化,不断为人们提供美好生活的解决方案,致力让更多人吃得新鲜、吃得省心、吃得丰富、吃得健康…以更美好的舌尖体验,为现代家庭创造美味与幸福感。

业务需求

随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,这些需求最终被数据看板、实时 Ad-Hoc、行为分析、B/C 端业务平台和标签平台等系统应用所承载,为实现这些系统应用,叮咚大数据希望引入一款实时 OLAP 数据库,旨在提供一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。基于上述诉求,我们希望所引入的数据库具备以下能力:

  • 可以实时高效地分析和使用数据;
  • 可以支持明细数据、汇总数据两种不同的数据查询方式;
  • 可以对入库后的数据即席选择维度和条件查询,实时/近实时返回结果

选型和对比

我们主要对比了 Apache Doris 和 ClickHouse 两款市面上最常见的开源 OLAP 引擎,在选型过程中我们主要考虑以下几个方面:

  1. 支持标准 SQL,无需投入额外的时间适应和学习新的 SQL 方言、直接用标准 SQL 即可直接查询,最大化降低使用门槛;
  2. 支持 Join 操作,方便事实表与维度表进行关联查询,在应对维度更新时具有更高的灵活性、无需对处理后的宽表进行重刷;
  3. 支持高并发查询,系统面临多条业务线的同时使用,因此需要有比较强的并行查询能力,以更好满足业务需求;
  4. 支持离线和实时导入,可与已有技术栈轻松对接,支持多个数据源或大数据组件的离线和实时导入,以更好适配不同使用场景;
  5. 支持大数据量的明细数据查询,以满足不同业务用户灵活多变的分析需求;

经过详尽的技术调研,Apache Doris 各项能力都比较优异,在我们的大多数业务场景中都需要明细数据级别的查询、高并发的点查和大数据量的 Join,而这几个方面 Apache Doris 相较于 ClickHouse 均更胜一筹,因此我们决定使用 Apache Doris 来搭建新的架构体系。

架构体系

在整体架构中,各个组件承载着特定的功能,Elasticsearch 主要负责存储标签系统的数据,HBase 是实时数仓的维表层,MySQL 用于存储业务系统的数据存储,Kafka 主要存储实时数据,Spark 主要提供 Ad-Hoc 查询的计算集群服务,而 Apache Doris 作为核心的 OLAP 引擎支持复杂地分析操作、提供多维的数据视图。

  • 离线部分: 数据从业务库通过 DataX 导入到数据仓库 ODS 层,经过层层处理输出到 Doris 中,上层 BI 系统链接到 Doris 进行报表展示。
  • 实时部分: 数据通过 Flink 消费 Kafka 中的数据,进行相应的逻辑处理后,输出到 Doris 或者 HDFS 中,供应用层使用。

在数据应用的 OLAP 层中,Doris 应用方案如下图所示:

  • 模型创建规范化: 采用流程审批的方式进行数据建模,根据具体的业务场景来搭建 Duplicate,Unique Key 和 Aggregate 模型,并按照用户提供的数据量设置合适的 Bucket 数目,做好模型归属关系。

  • 数据入口的统一: 数据的流入主要有实时和离线两种,实时数据用 Flink 任务从 Kafka 消费数据,逻辑处理流入 Doris ;离线数据通过 Broker Load 方式从 Hive 中将数据灌入 Doris 中。

  • 服务对外出口的统一: 对外服务主要通过两种方式暴露接口,一种是使用 JDBC 直连,上层系统配置 Doris 集群的 FE 的连接信息直连 Doris;另一种是业务通过内部的 One API 服务配置业务接口使用 Doris。

  • 业务 SQL 的优化治理:  通过采集 Doris FE 的审计日志,以此来对 SQL 的性能进行分析优化,以及对 Doris 服务进行治理。

应用实践

叮咚买菜目前已经将 OLAP 引擎统一为 Apache Doris 广泛应用于业务场景中,我们将 Doris 集群拆分成了四个集群,分别支持核心报表、行为分析与算法应用、B/C 端业务和实时数据,根据不同业务场景的业务量及数据规模,集群的资源配置也不尽相同。目前总的机器规模达数十台,以行为分析场景为例,单个集群近 20 个节点、 存储数据量超过百 TB,每日新增数据量达数十亿条

接下来分享 Apache Doris 在叮咚买菜常见业务场景中的应用实践及使用经验。

实时数据分析

从下方数仓模型图可知,数据通过 Flink 作业进行逻辑处理,在不同层级 Kafka 中进行流转加工,经过数据汇总层之后,应用层需要一个组件来存储结果数据,该组件一般是从 MySQL 数据库、KV 存储和 OLAP 引擎三者中选择其一。

考虑到我们的结果数据大多以计算指标数据居多,缺乏维度数据,因此应用层的组件需要具备高效、低延迟的数据 Join 能力。基于以上因素,我们最终选择 Apache Doris 作为实时数仓和实时业务的数据应用层,Doris 可以有效降低数据处理延时,提高查询效率

比如在销量计划项目中,该项目需要每日实时写入大量预测数据,并且这些数据需要较低时延提供给分析师进行及时对比分析、修改该预测值,并提供到供应链端。因修改预测值会影响到系统调拨,所以选用的存储必须是要具有高吞吐低延迟特性,Doris 完全符合该要求。从销量计划的整个数据生产及处理链路来看,使用 Doris 后,最慢 2 秒内可以看到最新的数据。

当前公司已经有数十个实时业务需求接入到 Doris 中,随着业务的不断发展,这个数字也在慢慢增加。

B 端业务查询取数

在实际的使用中,通常会有 B 端业务或系统需要从数据仓库中取数的需求,比如自研 Pylon 系统(主要用来基于用户偏好的数据查询)会根据 UID 查询用户画像信息。在这种场景下,通常需要进行复杂的模型关联,同时要求在秒级或者毫秒级返回查询结果。

  • 使用前:我们最初使用 Spark 的 JDBC 方式来直接查询数据仓库 Hive 表数据,由于存放用户标签数据的 Hive 表的数据量有几千万体量,通过 Spark JDBC 方式要耗费几分钟才能查出结果,同时还存在 Yarn 调度耗时较高的问题,有时会因为队列资源紧张产生延迟,导致一个普通的查询甚至需要十几分钟才能跑出结果,用户的体验度非常不好。
  • 使用后:经过我们对数据链路的改造,将 Hive 的用户标签数据离线灌入 Doris 中,再用同样的 SQL 查询,Doris 的性能在绝大多数场景下比 Spark 要好很多,可以在秒级别得到返回结果。

标签系统

最初我们的标签数据存放在 ES 中,但是随着业务的扩展、下游业务越来越多,标签数据规模急速膨胀,策略规则不断增加变化,标签系统遭遇严重的性能瓶颈。

  • 聚合和 Join 查询的性能低
  • 人群圈选花费时间近 20 分钟
  • ES 导入慢、查询性能低

为解决以上问题,我们目前正在尝试使用 Doris 来替换 ES,希望通过 Doris 解决上述问题,选择 Doris 主要考虑以下三点:

1、分布式 Join 大大提升查询效率

原有商品 ID 和仓库 ID 通过嵌套类型存储在 ES 中,替换为 Doris 存储之后,需要将复杂的嵌套类型拆解为两张表来做表级关联,同时可以试用 Doris 的多种分布式的 Join 提高查询得性能。Doris 的分布式 Join 主要有 Shuffle Join、Broadcast Join 和 Colocate Join。

其中 Colocate Join 查询性能是最好的,旨在为某些 Join 查询提供本地性优化,来减少数据在节点间的传输耗时、加速查询,另外我们在该场景下基本均为千万级的表。综合来看,Colocate Join 比较符合场景与需求,最终决定使用 Colocate Join方式提升 Join 性能。

如何使用: 标签数据的使用主要涉及到两张大表的 Join,建表时需要设置相同的 Distributed Key、相同的 Bucket数、相同的副本数,还要将两个表通过 colocate_with 属性划分到一个组 Colocation Group(CG)。

 CREATE TABLE `profile_table` (
`pdate` date NULL COMMENT "null", 
`product_mongo_id` varchar(4000) NULL COMMENT "商品ID", 
`station_id` varchar(4000) NULL COMMENT "仓id", 
 ......
 ) ENGINE=OLAP
UNIQUE KEY(`pdate`,
`product_mongo_id`, `station_id`)
COMMENT "OLAP"
PARTITION BY RANGE(`pdate`)()
DISTRIBUTED BY 
HASH(`product_mongo_id`) BUCKETS 7
PROPERTIES ("colocate_with" = "profile_table","in_memory" = "false","storage_format" = "V2") 
CREATE TABLE 
`station_info_table` ( `product_mongo_id` varchar(4000) NULL COMMENT "商品id", `station_id` varchar(4000)NULL 
COMMENT "站点id", 
`snapshot` date NULL COMMENT "日期", 
`product_id` bigint(20) NULL COMMENT "商品id", ......) 
ENGINE=OLAPUNIQUE KEY(`product_mongo_id`, `station_id`, `snapshot`)
COMMENT "OLAP"
PARTITION BY RANGE(`snapshot`)()
DISTRIBUTED BY 
HASH(`product_mongo_id`) BUCKETS 7
PROPERTIES ("colocate_with" = "profile_table","in_memory" = "false","storage_format" = "V2") 

比如我们有这样一条查询语句:

select count(psp.product_mongo_id) from profile_table psp 
left join station_info_table psi on psp.product_mongo_id=psi.product_mongo_id and psp.station_id=psi.station_id
where psp.pdate='2023-03-16' and psp.four_category='特色醋' and psp.brand_name='宝鼎天鱼' and psp.weight_unit='ml' and psp.pmg_name='粮油调味组';

经过使用 Colocate Join 方式优化后,可以达到毫秒级的查询效果。接下来我们介绍一下 Colocate Join 的查询性能高的原因有哪些呢?

A. 数据导入时保证数据本地性

Doris 的分区方式如下所示,先根据分区字段 Range 分区,再根据指定的 Distributed Key Hash 分桶。

所以我们在数据导入时保证本地性的核心思想就是两次映射,对于 Colocate Tables,我们保证相同 Distributed Key 的数据映射到相同的 Bucket Seq,再保证相同 Bucket Seq 的 Buckets 映射到相同的 BE。可以同查看执行计划查看是否使用了Colocate Join:

对于 HashJoinFragment,由于 Join 的多张表有了数据本地性保证,所以可以去掉 Exchange Node,避免网络传输,将 ScanNode 直接设置为 Hash Join Node 的 Child。

B. 查询调度时保证数据本地性

  • 查询调度的目标: 一个 Colocate Join 中所有 ScanNode 中所有 Bucket Seq 相同的 Buckets 被调度到同一个 BE。

  • 查询调度的策略:第一个 ScanNode 的 Buckets 随机选择 BE,其余的 ScanNode 和第一个 ScanNode 保持一致。

C. 数据 Balance 后保证数据本地性

新增一个 Daemon 线程专门处理 Colocate Table 的 Balance,并让正常的 Balance 线程不处理 Colocate Table 的 Balance。正常 Balance 的粒度是 Bucket,但是对于 Colocate Table,必须保证同一个 Colocate Group 下所有 Bucket 的数据本地性,所以 Balance 的单位是 Colocate Group。

2、高效简易的array_contains函数

在做人群圈选时,有以下类似的 Json 结构[{"K1":"V1","K2":200},{"k1":"v2","k2":300}],当配置 k1=v1,k2=200,只要该 Value 里的 Json 项有一项满足全部条件就会被圈出来,我们可以借助 Doris 1.2 版本中的 array_contains 数组函数处理,将 Json 转化为 Array 数组处理。

3、Broker Load 加速数据导入效率

Doris Broker Load 是一种高效、稳定的数据导入方式,它可以将数据分成多个分片,然后将每个分片分配给不同的 Broker 节点进行处理,我们使用 Broker Load 将标签数据从 Hive 导入 Doris 中,有效提高了数据导入的效率和稳定性。

BI 数据看板

我们商业智能分析使用的 BI 分析平台主要是帆软和自研的阿尔法 BI,底层使用 Doris 来存储数据,目前用来做报表的 Doris 表数量已达到了 3000 多张,四个 Doris 集群的日 UV 1000+PV 达到十几万,由于 Doris 可以达到毫秒级响应速度支持高并发查询,因此单集群的 QPS 可以达到达到 120次/秒,符合我们的要求。

OLAP 多维分析

随着业务的增长,我们在运营的过程中我们常常有一些疑问:最近三个月哪个品类的下单量最高?变化趋势如何?各个时段人均下单是多少?某个区域,发生购买行为的年龄段分布是怎样的?…而想要获得结果,必须根据用户行为日志进行事件分析。

目前我们的用户行为数据日均增量为 20亿+,高峰期 100亿+,为了更好的进行事件分析,我们需要保留半年的数据,也就是几千亿的数据量。 我们使用 Doris 来存储如此庞大的数据量,在应对复杂的分析场景时可以达到分钟级的响应。在多维分析的过程中, 往往也伴随着大数据量的复杂查询,接下来分享如何使用 Doris 应对:

1、 Bitmap 去重

业务使用过程中需要分析用户参与情况以及活跃程度,考查进行初始行为后的用户中,有多少人会进行后续行为,这时候一般都是使用留存分析模型实现此类需求。该模型使用中有去重操作,计算周期有某天/某周/某月/最近三个月等,由于每天的埋点数据量都能达到几十亿,高峰期 100 亿,在这个情况下,使用 count(distinct)性能太差、甚至查询超时(或超过设置的时间),而如果使用 Bitmap 来可以成倍的缩短查询时间

select
event_id,
date,
count(distinct uid) as count
from event
where 
dt>='2022-06-01' and dt<'2022-06-06' and event_id in (......) group by event_id, str_to_date(dt,'%Y-%m-%d');

使用 Bitmap 优化 SQL 后

select
event_id,
date,
bitmap_count(uid) as count
from event
where 
dt>='2022-06-01' and dt<'2022-06-06' and event_id in (......) group by event_id, str_to_date(dt,'%Y-%m-%d');

使用中需要注意 Bitmap 函数在 Apache Doris 中仍然需要先把数据汇聚到一个 FE 节点才能执行计算,并不能充分发挥分布式计算的优势,在数据量大到一定的情况下, Bitmap 函数并不能获得比 COUNT(DISTINCT) 更好的性能,上述实例之所以能达到预期结果是由于做了分组计算。

如果处理大数据量的全量去重,在建表时将 Bitmap 列的值按照 Range 划分,不同 Range 的值存储在不同的分桶中,保证了不同分桶的 Bitmap 值是正交的。当查询时,先分别对不同分桶中的正交 Bitmap 进行聚合计算,然后顶层节点直接将聚合计算后的值合并汇总并输出,从而解决顶层单节点计算瓶颈问题。

2、前缀索引和 Bloom Filter 索引

Doris 主要支持两类索引:内建的智能索引(包括前缀索引)和创建的二级索引(包括 Bloom Filter 索引和 Bitmap 倒排索引)。实际使用时我们会用到前缀索引和 Bloom Filter 索引来提高查询效率。

前缀索引

Aggregate、Unique 和 Duplicate 三种数据模型中,底层的数据存储是按照各自建表语句中 AGGREGATE KEY、UNIQUE KEY 和 DUPLICATE KEY 指定的列进行排序存储的。前缀索引即在排序的基础上实现的一种根据给定前缀列、快速查询数据的索引方式,实现方式是将一行数据的前 36 个字节作为这行数据的前缀索引,当遇到 VARCHAR 类型时,前缀索引会直接截断。

比如我们要查询按照日期和 event_id 分组的去重人数,建表语句如下:

CREATE TABLE ubs_event_log_small_event (
event_id int(11) NULL COMMENT "事件id",
dt datetime NOT NULL COMMENT "事件时间",
uid char(128) NULL COMMENT "用户id",
dict_id int(11) NULL COMMENT "用户id字典值",
os varchar(24) NULL COMMENT "操作系统",
......
dict_id_bitmap bitmap BITMAP_UNION NULL COMMENT "bitmap用户id"
) ENGINE=OLAP
AGGREGATE KEY(event_id, dt, uid, dict_id, os, ......)
COMMENT "用户行为事件表"
PARTITION BY RANGE(dt)
()
DISTRIBUTED BY HASH(dt, event_id, uid) BUCKETS 64

SQL 查询的 Where 条件一般遵循建表的 AGGREGATE 模型的 KEY 的顺序,这样可以命中 Doris 内置的前缀索引。

SELECT 
CONCAT(
TO_DATE(dt), 
' 00:00:00'
) AS tm, 
event_id, 
BITMAP_UNION_COUNT(dict_id_bitmap) AS UNIQ_1908_1 
FROM 
kepler.ubs_event_log_small_event 
WHERE event_id = 1908 AND 
dt >= '2023-03-26' 
AND dt < '2023-04-05'
AND 
os IN (1, 2)
GROUP BY 
1, 
2;

Bloom Filter 索引

针对大数据量的事件表进行查询时我们会设置 bloom_filter_columns,加快查询效率:

alter table datasets set("bloom_filter_columns" = "area_name, is_booking, user_source, source_first_order......");

查询语句中 where 条件有以上设置的字段就会命中该索引。

SELECT * FROM datasets WHERE area_name="****" AND is_booking=0 

3、物化视图

为了获得更粗粒度的聚合数据,Doris 允许在建表语句创建出来的 Base 表的基础上,创建若干 Rollup 表。

例如上表 ubs_event_log_small_event,我们可以对 dtevent_iddict_id_bitmap 建立 Rollup 物化视图,这样 Rollup 只包含三列: dtevent_iddict_id_bitmap

这时再进行上述查询就会命中这个 Rollup,从而只扫描极少的数据量就可以完成此次聚合查询。

优化经验

Broker Load 导数任务流程化

为了 Doris 使用更加便捷,我司在内部自研的叮咚大数据平台上对整个过程进行流程化;从建模到配置 Broker Load 导数任务再到导数任务调度均进行了调整,具体优化如下所述:

建模过程: 需要用户发起建模流程申请,填写需求内容、具体建模语句、预估数据量大小、数据保留时长、所需相关权限账号等信息,足够完整的信息可以在审批时获得建模过程中的元数据信息以及选择更合适的数据模型。

Broker Load 导数任务配置: 为了提高用户使用效率、降低使用门槛,我们通过 Mapping 映射和自动化配置方式,自动生成导数任务。

导数任务调度: 配置完 Broker Load 导数任务,就可以由用户根据需求配置小时或者天级别的调度,这样整个 Doris 数据导入流程,就可以由用户配置自动完成。

总结与展望

Apache Doris 作为叮咚买菜整体架构体系中的核心 OLAP 分析引擎,不论是作为数仓数据看板类的应用层、还是作为实时数据汇总结果接入层、或是作为 B/C 端服务数据提供方,均能够很好的满足业务需求。除此之外,Doris 使得我们无需在存储选型上耗费过多时间,大大缩短了开发的周期;同时,Doris 支持 MySQL 协议和标准 SQL ,大大降低内部人员的使用成本和门槛。未来,我们希望使用 Doris 支撑内部更多的业务场景,更大范围了提升工作效率。我们也会紧跟社区步伐,积极使用推出的新版本特性,以更好解决场景需求,提升业务效果。

最后,非常感谢 SelectDB 团队对我们在 Doris 使用上的技术支持,祝愿 SelectDB 和 Apache Doris 发展越来越好!

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

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

相关文章

一键构建分布式云原生平台

目录专栏导读一、分布式云原生平台1、应用无所不能2、运行无处不在3、服务千行白业二、分布式云原生平台关键要素1、统一应用管理2、统一流量自治3、统一数据管理4、统一运维三、多云多集群已经广泛应用四、分布式云的优势&#xff1a;1、避免厂商锁定2、满足合规化要求3、增强…

收藏!7个国内「小众」的程序员社区

技术社区是大量开发者的集聚地&#xff0c;在技术社区可以了解到行业的最新进展&#xff0c;学习最前沿的技术&#xff0c;认识有相同爱好的朋友&#xff0c;在一起学习和交流。 国内知名的技术社区有CSDN、博客园、开源中国、51CTO&#xff0c;还有近两年火热的掘金&#xff…

基于决策树及集成算法的回归与分类案例

基于决策树及集成算法的回归与分类案例 描述 本任务基于决策树及集成算法分别实现鲍鱼年龄预测案例和肿瘤分类案例。鲍鱼年龄预测案例是建立一个回归模型&#xff0c;根据鲍鱼的特征数据&#xff08;长度、直径、高度、总重量、剥壳重量、内脏重量、壳重&#xff09;等预测其…

Python:超级大全网上面试题搜集整理(四)

转载参考&#xff1a; python 面试题(高级)_python高级面试题_梦幻python的博客-CSDN博客 cpython pypy_介绍Cython&#xff0c;Pypy Cpython Numba各有什么缺点【面试题详解】_函明的博客-CSDN博客 Cython、PyPy专题开篇 - 知乎 Python抽象类和接口类_python 接口类_代码输…

蓝桥杯客观题知识点

一、异步和同步的在于 有无统一的时钟信号 异步无 同步有 RS485 半双工、异步、串行、差分输入------多级通信&#xff08;USB\键盘等外设&#xff09; RS232 全双工、异步、串行、单端输入------一对一通信 二、组合逻辑电路和时序逻辑电路的区别 组合&#xff1a;任意时…

使用反射重新执行不同的方法

0. 用到的技术 反射获取正在执行的方法名称Class[]数组的获取 1. 为什么要这样做? 情况如下: 当我调用sendCommands方法发送请求时可能会收到errorCode为403也就是代码中的MDS_ERROR,就是当token(mds)失效了这种情况,我们就需要重新刷新token,并且重新执行该方法 假设还有1…

SYN FLOOD攻击和HTTP慢速攻击实验笔记

SYN_FLOOD攻击和HTTP慢速攻击是DDOS攻击的两种方式。 SYN Flood攻击 SYN Flood攻击的原理就是阻断TCP三次握手的第三次ACK包&#xff0c;即不对服务器发送的SYNACK数据包做出应答。由于服务器没有收到客户端发来的确认响应&#xff0c;就会一直保持连接直到超时&#xff0c;当…

产品营销软文怎么写吸引人?

随着互联网的发展&#xff0c;人们获取信息的渠道变得越来越多&#xff0c;其中软文营销成为了众多企业推广自己产品的主要方式之一。那么&#xff0c;软文营销怎么写才能吸引人呢&#xff1f;这里有一些建议&#xff0c;可以帮助你解决这个问题。 要想写出一篇成功的软文&…

自拍的照片不太清晰怎么办?拍摄的模糊照片如何修复高清?

如果您的人像照片不太清晰&#xff0c;可能是由于手持相机时快门速度过慢、摄像机抖动或者焦点不准确等原因造成的。 自己拍摄的照片总是感觉不太清晰&#xff0c;放大看的话更是模糊&#xff0c;该如何是好&#xff1f; 以下是一些避免自拍照片模糊的方法&#xff1a; 1、使…

XSKY星辰天合荣获环球网“年度科技优秀创新案例”

近日&#xff0c;环球网主办的第四届环球趋势大会在广州举行&#xff0c;由环球时报、环球网联合主办的“2022 环球趋势案例征集活动”评选结果同步揭晓&#xff0c;XSKY星辰天合荣获 2022 环球趋势案例“年度科技创新优秀案例”。“2022 环球趋势案例”是人民日报旗下&#xf…

6个免费高清图库素材库,设计师、自媒体都在用~

免费高清图片素材分享&#xff0c;建议收藏起来. 1、菜鸟图库 https://www.sucai999.com/pic.html?vNTYxMjky 超大图库网站&#xff0c;含有几百万张图片素材&#xff0c;自然、植物、人物、日常、交通等涵盖多种类型&#xff0c;全部都有详细的标签分类。图片素材质量都很高…

DOM 事件相关知识总结——事件绑定、事件流(事件冒泡、捕获)

1. 事件绑定方式 1. 直接给元素添加事件属性 <input onclick"alert(我被点击了&#xff01;)" type"button" value"点我试试" />优点&#xff1a;大家都会&#xff0c;几乎所有的浏览器都支持 缺点&#xff1a;夹杂在HTML代码中&…

79-Linux_Socket实现客户端与服务器端间通讯

Socket实现客户端与服务器端间通讯一.网络编程的接口1.socket2.bind3.listen4.accept5.connect6.close7.ssize_t recv和ssize_t send8.UDP 数据读写二.tcp流式服务和粘包问题三.客户端及服务器端实现的代码.1.客户端2.服务器端一.网络编程的接口 头文件: #include <sys/typ…

win11使用移动硬盘(固态非固态)卡顿问题解决

以前win10使用移动硬盘没用出现过卡顿的问题&#xff0c;后来更新win11后&#xff0c;硬盘在处理文件和文件新建以及编辑的时候&#xff0c;都会莫名其妙卡1-3秒左右。以为是盘坏了&#xff0c;各种检测和修复。发现没有问题 后来还找移动硬盘的商家沟通&#xff0c;也无果打算…

C语言基础应用(四)选择结构

引言&#xff1a; 在日常生活中&#xff0c;我们时时刻刻面临着选择&#xff0c;在C语言中&#xff0c;如果我们需要判断条件从而实现不同的要求&#xff0c;我们就需要使用选择结构。 注&#xff1a;以下代码均未导入头文件&#xff0c;如果读者使用了代码&#xff0c;请记得…

day9 条件变量的基本使用

目录 条件变量 条件变量 应用场景&#xff1a;生产者消费问题&#xff0c;是线程同步的一种手段&#xff1b; 必要性&#xff1a;为了实现等待某个资源&#xff0c;让线程休眠&#xff0c;提高运行效率&#xff1b; 等待资源&#xff1a; //1、一直等待资源 int pthread_c…

linux 匿名文件 memfd_create

专栏内容&#xff1a;linux下并发编程个人主页&#xff1a;我的主页座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物&#xff0e;目录 前言 概述 原理 接口 代码演示 结尾 前言 本专栏主要分享linux下并发编程相关知识…

慌了!ChatGPT吃我饭,还要掀我碗?

ChatGPT面世&#xff0c;各种被AI取代“失业言论”笼罩在人们头顶&#xff0c;本文聚焦这一问题&#xff0c;推荐关注ChatGPT的小伙伴阅读。 一时间火爆全网的新晋网红——ChatGPT&#xff0c;就问&#xff1a;还有谁不认识&#xff1f; 谷歌计划在旗舰搜索引擎中添加对话式人…

TCP/UDP协议 (详解)

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点!人生格言&#xff1a;当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔&#x1f9be;&am…

网络安全之入侵检测

目录 网络安全之入侵检测 入侵检测经典理论 经典检测模型 入侵检测作用与原理 意义 异常检测模型&#xff08;Anomaly Detection&#xff09; 误用检测模型&#xff08;Misuse Detection&#xff09; 经典特征案例 ​编辑自定义签名 ​编辑 签名检查过程 检测生命周期…