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

news/2024/5/19 1:33:57/文章来源:https://blog.csdn.net/SelectDB_Fly/article/details/130136871

导读: 随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时 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.luyixian.cn/news_show_286051.aspx

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

相关文章

阿里云服务器搭建网站流程by宝塔Linux面板

阿里云服务器安装宝塔面板教程&#xff0c;云服务器吧以阿里云Linux系统云服务器安装宝塔Linux面板为例&#xff0c;先配置云服务器安全组开放宝塔所需端口8888、888、80、443、20和21端口&#xff0c;然后执行安装宝塔面板命令脚本&#xff0c;最后登录宝塔后台安装LNMP&#…

crypto-js AES-CTR 实现密文前缀式局部解密细节 踩坑点

项目有需求&#xff0c;长明文经过AES-CTR模式加密后&#xff0c;在解密的时候&#xff0c;密文不能直接得到&#xff0c;每次通过某些方法尝试后&#xff0c;只能得到一块密文&#xff08;按顺序&#xff09;&#xff0c;所以只能一块一块的拼接解密。在使用crypto-js这个库的…

Java语言数据类型与c语言数据类型的不同

目录 一、c语言数据类型 1.基本类型&#xff1a; 2.枚举类型&#xff1a; 3.空类型&#xff1a; 4.派生类型&#xff1a; 二、C语言编程需要注意的64位和32机器的区别 三、 不同之处 一、c语言数据类型 首先&#xff0c;先来整体介绍一下C语言的数据类型分类。 1.基…

Win10+Anaconda+Pytorch_CPU+VsCode安装配置

一、安装Anaconda 1&#xff0c;官网下载Anaconda安装包&#xff0c;找到对应版本的python&#xff0c;我下的是Anaconda3-2020.07-Windows-x86_64.exe&#xff0c;python版本为3.8.3&#xff1b; 安装时注意这个界面时 第一个不要勾选&#xff0c;安装成功后&#xff0c;手动…

利用ffmpeg源码安装+vscode开发环境搭建详解

前言&#xff1a; 大家好&#xff0c;今天给大家分享一篇ffmpeg开发环境的搭建&#xff0c;我在很早之前也给搭建过ffmpeg源码的安装&#xff0c;但是并没有给大家去搭建开发环境&#xff0c;而且当时的版本也比较老&#xff0c;很多细节问题没有给大家展示如何解决&#xff01…

spring-boot怎么扫描不在启动类所在包路径下的bean

前言&#xff1a; 项目中有多个模块&#xff0c;其中有些模块的包路径不在启动类的子路径下&#xff0c;此时我们怎么处理才能加载到这些类&#xff1b; 1 使用SpringBootApplication 中的scanBasePackages 属性; SpringBootApplication(scanBasePackages {"com.xxx.xx…

一键生成元宇宙 AI又杀疯了

人类十几年的进步水平&#xff0c;AI用几个月就能轻易实现。在展示了超强的文本对话能力和一键生图功能后&#xff0c;AI大模型不打算停下&#xff0c;开始挑战搭建3D空间这一更高难度的动作。 这次&#xff0c;Facebook母公司Meta想当一把主导者。几天前&#xff0c;它的首席…

【从零开始学Skynet】基础篇(九):调试控制台服务

Skynet自带了一个调试控制台服务debug_console&#xff0c;启动它之后&#xff0c;可以查看节点的内部状态。 1、启用调试控制台 &#xff08;1&#xff09;在skynet/examples目录下新建main_console.lua文件&#xff0c;代码如下所示&#xff1a; local skynet require &quo…

详细聊一聊Android Apk的四代签名

简介 大部分开发者对apk签名还停留在APK v2&#xff0c;对APK v3和APK v4了解很少&#xff0c;而且网上大部分文章讲解的含糊不清&#xff0c;所以根据官网文档重新整理一份。 apk签名从APK v1到APK v2改动很大&#xff0c;是颠覆性的&#xff0c;而APK v3只是对APK v2的一次…

警惕“Money Message”勒索软件!数据安全不容忽视

近段时间&#xff0c;出现了一个名为“Money Message”的新型勒索软件&#xff0c;他们利用Money Message 病毒加密文件并以此向受害者勒索巨额赎金。 Money Message勒索软件是用 C编写&#xff0c;包含一个嵌入式JSON 配置文件&#xff0c;用于确定设备的加密方式。加密设备后…

一站式开发平台 加速企业数字化发展

协同办公平台、经营管理平台、生产控制平台、数字决策支持体系……当前&#xff0c;新一轮科技革命方兴未艾&#xff0c;以数字技术为基座的数字化&#xff0c;正颠覆、重构着千行百业。 数字化转型是信息技术引发的系统性变革&#xff0c;涉及单一应用、集成化、平台化、数据…

7.Java中的String类、常用类及包装类

Java中的String类、常用类及包装类 一、String类 1、String类定义 String 类代表字符串。Java 程序中的所有字符串字面值&#xff08;如 “abc” &#xff09;都作为此类的实例实现。字符串是常量&#xff1b;它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为…

新一代AI带来更大想象空间!上海将打造元宇宙超级场景!

引子 上海市经信委主任吴金城4月12日在“2023上海民生访谈”节目表示&#xff0c;上海将着力建设元宇宙智慧医院、前滩东体元宇宙、张江数字孪生未来之城等元宇宙超级场景。 吴金城说&#xff0c;新一代人工智能将带来更大的想象空间。比如&#xff0c;人工智能和元宇宙数字人的…

【论文阅读】MAMIL

1、基本信息 misc{Konstantinov_Utkin, title{Multi-Attention Multiple Instance Learning}, author{Konstantinov, AndreiV. and Utkin, LevV.} }2、摘要 本文提出了基于多注意力的MIL问题求解方法&#xff0c;该方法考虑了包中每个被分析实例的相邻实例。在该方法中&…

【记录】Git连接gitee、新建仓库

学习记录1.连接gitee2.新建仓库1.连接gitee https://www.cnblogs.com/cokefentas/p/14727592.html git安装与卸载 apt-get install git apt-get remove gitgit配置 配置用户名 git config --global user.name "your name" 配置邮箱 git config --global user.email…

学习安全攻防技能30讲-开篇|别说你没有被安全困扰过

文章目录学习安全攻防技能30讲-开篇|别说你没有被安全困扰过研读开篇安全重要吗&#xff1f;安全难学吗&#xff1f;学习安全攻防技能30讲-开篇|别说你没有被安全困扰过 研读开篇 文中说到一个竞赛叫CTF&#xff0c;这个之前从来没有听过的&#xff0c;作为开发人员涨知识了。…

5V的LDO电源的WCCA分析-可靠性分析计算过程

WCCA(WorstCase Circuit Analysis)分析方法是一种电路可靠性分析设计技术&#xff0c;用来评估电路中各个器件同时发生变化时的性能&#xff0c;用于保证设计电路在整个生命周期的都可以可靠工作。通过WCCA分析&#xff0c;验证在上述参数在其容差范围内发生变化时&#xff0c;…

springboot+thymeleaf实现发Html邮件自由

2019年&#xff0c;我刚接触测试架构和测试开发类的工作时&#xff0c;经常会有自动化发邮件的功能&#xff0c;大都是从各个平台自动化统计一些数据出来&#xff0c;每周定时发一封邮件给领导交差&#xff0c;回过头来再看看我发的邮件&#xff0c;不美观&#xff0c;不专业。…

JUC并发编程之AQS原理

1. AQS 原理 1.1 概述 全称是 AbstractQueuedSynchronizer&#xff0c;是阻塞式锁和相关的同步器工具的框架 特点&#xff1a; 用 state 属性来表示资源的状态&#xff08;分独占模式和共享模式&#xff09;&#xff0c;子类需要定义如何维护这个生态&#xff0c;控制如何获…

医院不良事件报告系统源码:基于PHP+vue2+element+laravel8技术开发

医院不良事件报告系统源码 文末获取联系&#xff01; 技术架构&#xff1a;前后端分离&#xff0c;仓储模式&#xff0c; 开发语言&#xff1a;PHP 开发工具&#xff1a;vscode 前端框架&#xff1a;vue2element 后端框架&#xff1a;laravel8 数 据 库&#xff1a;mysql5…