当前位置: 首页 > news >正文

HBase 在统一内容平台业务的优化实践

作者:来自 vivo 互联网服务器团队-Leng Jianyu、Huang Haitao

HBase是一款开源高可靠性、扩展性、高性能和灵活性的分布式非关系型数据库,本文围绕数据库选型以及使用HBase的痛点展开,从四个方面对HBase的使用进行优化,取得了一些不错效果。

一、业务简介

统一内容平台主要承担vivo内容生态的内容审核、内容理解、内容智作和内容分发等核心功能,通过聚合全网内容,建设行业级的业务中台和内容生态,为上下游提供优质可靠的一站式服务,目前服务的业务方包括视频业务、泛信息流业务等。

图片

作为一个内容中台,每天要新增存储大量图文和视频内容来满足分发的需要。与此同时,对这些内容加工处理的数据也都需要存储,包括基础信息,分类标签信息,审核信息等等。而且不仅仅是需要存储的数据量级很大,对数据的读取和写入操作也非常频繁,当前对数据库的读写主要集中在两个方面:

  • 核心链路的内容处理包含了大量对内容特征信息的读取和写入操作;

  • 对外提供的查询服务会产生很多回源查询数据库的操作。

在经过多年累积后,当前存储的数据量越变越大,并且可以预见数据量级会不断膨胀下去,如何选择一种可靠的存储选型,来保证服务稳定性和扩展性成了当前项目架构的重中之重。

二、存在的问题

在选用HBase之前,内容平台核心数据的存储以Mongodb为主要存储选型,但是在日常的使用中,发现存储侧存在如下一些痛点问题

  • 核心数据量大,大表有20TB 以上,总存储 60TB 以上,Mongodb 的存储架构,无法满足良好扩展性要求;

  • 访问查询流量大,需要承载智慧push、泛信息流、视频推荐侧的大回源查询流量,保持查询接口高性能;

  • 为了维护Mongodb的稳定性,需要定期切换 Mongodb 数据库主从节点,重做实例,需要运维长期投入,维护成本高。

所以我们迫切需要寻找一个更适合当前场景的数据库来满足业务请求量和存储大小日益增长的需求,并且要求具备高性能、高稳定、可扩展、低维护成本的特性。

三、存储选型

经过一些调研后发现HBase的一些特性能很好地满足当前场景的要求。

(1)高性能

HBase采用的是Key/Value的列式存储方式(对比Mongodb是行式数据库),同一个列族的数据存放在一个文件中,随着文件的增长会进行分裂,分散到其他机器上,所以即使随着数据量增大,也不会导致读写性能的下降。HBase具备毫秒级的读写性能,如果写入数据量大,还可以使用bulkload导入数据的方式进行高效入库。

(2)高扩展性、高容错性

HBase的存储是基于Hadoop的,Hadoop实现了一个分布式文件系统(HDFS),HDFS的副本机制使得其具有高容错性的特点,并且HDFS的Federation机制使得其具有高扩展性。基于Hadoop意味着HBase与生俱来的超强扩展性和高容错性。

(3)强一致性

HBase的数据是强一致性的,从CAP理论来看,HBase是属于CP的。CAP 定理表明,在存在网络分区的情况下,一致性和可用性必须二选一。HBase在写入数据时,先把操作的记录写入到预写日志中(Write-ahead log,WAL),然后再被加载到Memstore的。就算某个节点机器宕掉了,由于WAL的数据是存储在HDFS上的,所以数据并不会丢失,后续可以通过读取预写日志恢复内容。

(4)列值支持多版本

HBase的多版本特性可以针对某个列族控制列值的版本数,默认是1,即每个key保存一个版本,同一个rowkey的情况下,后面的列值会覆盖前面的列值。可以动态修改列族的版本数,每个版本使用时间戳进行标记,默认是写入时间作为该版本的时间戳,也可以在写入时指定时间戳。

综合以上特性,HBase是非常适合当前项目对数据库选型的要求。

四、HBase 优化实践

随着HBase在整个项目中逐步扩大使用,也发现了一些使用规范问题以及一些查询的性能问题。比如查询毛刺比较多、夜间Compact期间耗时比较高、流量高峰期的时候少量请求会有延迟。针对这些问题,我们从下面四个方面,对HBase的使用进行了优化。

4.1 集群升级

刚开始使用HBase的时候,我们使用的HBase集群版本是1.2版本的,此版本存在诸多弊端,如:RIT(Region-In-Transition)问题频发、请求延时突刺、建删表速度慢、meta 表稳定性差、节点故障恢复速度慢等问题。我们在使用过程发现的主要问题是响应时间突刺问题,该问题会导致我们实时查询接口在回源时超时较多,导致接口的响应时间有突刺被下游业务方熔断,影响业务查询。与HBase团队讨论与评估后,决定将业务使用的集群升级到HBase 2.4.8 版本。该版本在公司较多的业务场景中已经得到验证,可以解决大部分1.2.0版本存在的痛点问题,可以大幅提升读写性能,有效降低读毛刺,单机处理性能的提升可减少20%左右机器成本。

下面是集群升级后的读写平均耗时对比图。可以看到在升级之前,平均响应时间经常会有一些突刺,最高能达到超过10s,升级后几乎不存在这么高的平均响应时间突刺,能保持在10ms以下,偶尔较高也是几十毫秒级别。

图片

升级前

图片

升级后

4.2 连接池使用和连接预热

HBase Connection 创建对象并不是简单对应一个socket连接,需要与Zookeeper以及HMaster、RegionServer都建立连接,所以该过程是一个非常耗资源的过程,一般只创建一个 Connection 实例,其它地方共享该实例。在Connection初始化之后,用connection下的getTable方法实现对表格的连接。为了减少与表格连接带来的网络开销,我们建立了对不同表格的连接池来管理客户端和服务端的连接。大致流程图如下图所示。

通过建立连接池,带来了以下三点优势:

(1)对表和表之间进行了连接资源隔离,避免互相影响;

(2)对连接实现了复用,减少了创建连接的网络开销;

(3)防止突增的流量带来的影响,实现平滑处理流量。

此外,图中可以看到,在程序启动阶段,可以实现对HBase表连接的预热,提前建立对表格的连接,可以有效避免在程序启动阶段由于大量建立连接导致读写的响应时间变长,影响整体性能。

连接池通过使用Apache Commons Pool提供的GenericObjectPool通用对象池来实现,GenericObjectPool包含丰富的配置选项,能够定期回收空闲对象,并且支持对象验证,具有强大的线程安全性和可扩展性。然后将不同表格的连接池对象放到本地缓存LoadingCache中,LoadingCache底层通过LRU算法实现对最久远且没有使用的数据的淘汰,保证没有使用的表格连接能及时释放。通过使用第三方的对象池和本地缓存,建立了对HBase表格的连接池,并且实现了预加载,减少了一些读写HBase的开销,降低了读写耗时,对于刚启动服务时的读写突刺带来了一些改善。

图片

4.3 按列读取

HBase建表的时候是不需要确定列的,因为列是可变的,它非常灵活,唯一需要确定的就是列族。一张表的很多属性比如过期时间、数据块缓存以及是否压缩等都是定义在列族上,而不是定义在表上或者列上,这一点做法跟以往的数据库有很大的区别。同一个表里的不同列族可以有完全不同的属性配置,但是同一个列族内的所有列都会有相同的属性。一个没有列族的表是没有意义的,因为列必须依赖列族而存在,所以在HBase中一个列的名称前面总是带着它所属的列族。列族存在使得HBase会把相同列族的列尽量放在同一台机器上,不同列族的列分布在不同的机器上。

一般情况下,从客户端发起请求读取数据,到数据返回大致有如下几步:

  1. 客户端从ZooKeeper中获取meta表所在regionServer节点信息。

  2. 客户端访问meta表所在的regionServer节点,获取region所在节点信息。

  3. 客户端访问具体region所在regionServer,找到对应的region。

  4. 首先从blockCache中读取数据,存在则返回,不存在则去memstore中读取数据,存在则返回,不存在去storeFile(HFile)中读取数据,存在会先将数据写入到blockCache中,然后返回数据,不存在则返回空。

简单的示意图如下所示:

图片

整个过程中如果读取字段过多,或者字段长度过大,那么返回所有列的数据会导致大量无效的数据传输,进而导致集群网络带宽等系统资源被大量占用,必然导致读取性能降低,所以需要减少一些不必要字段的查询。

Get类是HBase官方提供的查询类,在该类中主要有以下几个方法提供来实现减少字段读取:

  • addFamily:添加要取出的列族;

  • addColumn:添加要取出的列;

  • setTimeRange:设置要取出的版本范围;

  • setMaxVersions:设置取出版本数量。

当前项目中没有使用到HBase的版本范围和版本数量的特性,但是主要场景使用的表字段都比较多(如内容的基本属性能达到上百个字段),或者字段的大小都比较大(如内容解析的一些向量字段),原本在查询时,都是直接读取所有字段,导致很多字段其实不需要使用也被一直读取,浪费性能。通过改用按列读取的方式来实现不同场景下不同字段的查询,避免了超过一半无用字段的返回,平均响应时间也下降了一些。

4.4 compact优化

HBase是基于LSM树存储模型的分布式NoSQL数据库。LSM树相比于普遍使用在各种数据库的B+树来说,能够获得较高随机写性能的同时,也能保持可靠的随机读性能。在进行读请求的时候,LSM树要把多个子树(类似B+树结构)进行归并查询, 因此归并查询的子树数越少,查询的性能就越高。当MemStore超过阀值的时候,就要flush到HDFS上生成一个HFile。因此随着不断写入,HFile的数量将会越来越多,根据前面所述,HFile数量过多会降低读性能。为了避免对读性能的影响,可以对这些HFile进行compact操作,把多个HFile合并成一个HFile。compact操作需要对HBase的数据进行多次的重新读写,因此这个过程会产生大量的IO。可以看到compact操作的本质就是以IO操作换取后续的读性能的提高。

图片

HBase的compact是针对HRegion的HFile文件进行操作的。compact操作分为major和minor两种。major compaction会把所有的HFile都compact为一个HFile,并同时忽略标记为delete的KeyValue(被删除的KeyValue只有在compact过程中才真正被"删除"),可以想象major compaction会产生大量的IO操作,对HBase的读写性能产生影响。minor则只会选择数个HFile文件compact为一个HFile,minor的过程一般较快,而且IO相对较低。在业务高峰期间,都会禁止major操作,只在业务空闲的时段定时执行。

hbase.hstore.compaction.throughput.higher.bound是HBase中控制HFile文件合并(compaction)速度的参数之一。它指定了一个HFile文件每秒最大合并数据大小的上限,以字节为单位。如果一个HFile文件的大小超过了这个上限,HBase就会尝试将其分裂成较小的文件来加快合并速度。通过调整该参数,可以控制HBase在什么条件下开始尝试合并HFile文件。较小的值会导致更频繁的文件合并,也会降低HBase的性能。较大的值则可能导致HFile文件的大小增长过快,从而影响读取性能。

hbase.hstore.compaction.throughput.lower.bound也是HBase中控制HFile文件合并速度的参数之一。它指定了一个HFile文件每秒最小合并数据大小的下限,以字节为单位。当合并速度达到这个下限时,HBase会停止合并更小的HFile文件,而等待更多的数据到达之后再进行合并操作。与higher.bound参数相比,lower.bound参数更加影响文件合并频率和性能。过高的值会导致较少的文件合并和较大的HFile文件,这会影响读取性能和写入并发性。反之,过低的值会导致过于频繁的文件合并,从而占用过多的CPU和磁盘I/O资源,影响整个HBase集群的性能。针对Compact对业务耗时的影响,我们对Compact 操作进行了限流,并且通过多次测试调整Compact上文提到的两个限流的阈值,取得了非常好的效果。Compact期间的耗时下降了70%y以上。下图展示了采取限流前后的耗时对比。

图片

4.5 字段级版本管理

除了上述提到的优化点,我们也探索了一些HBase的其它特性,以备将来用来优化其他方面。上文提到,通过对HBase进行按列读取数据,可以减少get查询的时间,通常意义来讲,列(也就是每个字段)已经是每条数据的最基本单位了,但是HBase中的数据粒度比传统数据结构更细一级,同一个位置的数据还细分成多个版本,一个列上可以存储多个版本的值,多个版本的值被存储在多个单元格里面,多个版本之间用版本号( version)来区分。所以,唯一确定一条结果的表达式应该是行键:列族:列:版本号(rowkey:column family:column:version)。不过,版本号通常是可以省略的,如果写入时不写版本号,每个列或者单元格的值都被赋予一个时间戳,这个时间戳默认是由系统制定的,当然写入时也可以由用户显式指定具体的版本号。在查询时如果不指定版本号,HBase默认获取最后一个版本的数据返回给你。当然也可以指定版本号返回需要的其他版本的数据。简单的示意图如下所示:

图片

同时HBase为了避免数据存在过多的版本造成不必要的负担,HBase提供了两种数据版本的回收方式,一是按照数量维度,保存最后的n个版本,二是按照时间维度,保存最近一段时间的版本数据,比如保存一个月。通过多版本同时存储,对于一些有时序要求的场景非常友好,通过指定版本的时间戳,可以避免在已经更新了新数据的情况下,被旧数据覆盖。当前我们建表是都是只指定了一个版本,使用也都是用的以时间戳为版本号的默认版本,没有采取版本管理的措施,不同单元格可以记录多版本的特性可以考虑应用于字段更新时记录下多个版本的数据,在不影响读写效率的情况下,方便后续在没有相关日志的情况下,回溯最近几次更新的值,并且可以防止误操作或数据损坏,因为用户可以恢复到之前的版本数据。此外我们的系统中存在一些通过消息队列异步更新场景,此时可以使用消息体中的时间戳作为当前版本号,这样可以在多线程消费时,也能保证消费的时序性,因为低版本的版本号无法更新高版本的版本号。

五、总结

本文在对统一内容平台在数据库选型分析和优化的基础上,简要介绍了HBase在实际使用中的一些优化方案,经优化后,项目整体读取和写入性能都有比较明显的提升,较好的保障了统一内容平台业务的稳定性,并且大大降低了业务侧的运维成本。Hbase本身就具备强大的功能,在大数据领域有独有的优势,但是在不同的业务场景,对于HBase的要求也是不一样的,可以结合具体的实际情况,从使用的数据库版本、从HBase底层机制的调参、从客户端调用机制的优化等多方面挖掘,探索更适合业务的方式,希望本文中提到的一些优化方案能给读者带来一些启发。

相关文章:

HBase 在统一内容平台业务的优化实践

作者:来自 vivo 互联网服务器团队-Leng Jianyu、Huang Haitao HBase是一款开源高可靠性、扩展性、高性能和灵活性的分布式非关系型数据库,本文围绕数据库选型以及使用HBase的痛点展开,从四个方面对HBase的使用进行优化,取得了一些…...

【异常解决】Unable to start embedded Tomcat Nacos 启动报错

Unable to start embedded Tomcat Nacos 启动报错解决方案 一、背景描述二、原因分析三、解决方案 一、背景描述 Windows 本地启动 Nacos(2.2.0) 服务,控制台报错 Unable to start embedded Tomcat。 报错信息:Unable to start …...

【Java面向对象】对象和类

文章目录 1.为对象定义类2.定义类2.1 主类 3.类与对象3.1 构造方法3.2 通过引用变量访问对象3.3 访问对象的数据和方法3.4 引用数据域和 null 值3.5 基本类型变量和引用类型变量的区别 4.常见的类 1.为对象定义类 面向对象程序设计(OOP) 就是使用对象进行程序设计。对象 (obje…...

在微服务架构架构中父工程中的`<dependencyManagement>`和 `<dependencies>`的区别

在微服务架构架构中父工程中的<dependencyManagement>和 <dependencies>的区别&#xff1a; 在微服务架构中&#xff0c;通常会有一个父工程&#xff08;或称作聚合工程&#xff09;来管理一组相关的子模块&#xff08;即各个微服务&#xff09;。Maven 的 <de…...

Docker安装Zookeeper、RocketMQ

安装Zookeeper 拉取镜像 docker pull zookeeper:3.9.2启动容器 -d后台启动&#xff0c;-p映射容器2181端口到宿主机2181端口&#xff0c;限制容器最大内存占用为128m&#xff0c;–restart容器自动重启 docker run -d -p 2181:2181 -m 128m --restartalways --name zookeepe…...

Ubuntu 磁盘扩容

1.下载工具 sudo apt-get install gparted 2.调整大小...

如何在QGC中接收和处理无人机上传的各种传感器数据(如GPS、IMU等)。

在 QGroundControl (QGC) 中接收和处理无人机上传的各种传感器数据&#xff08;如 GPS、IMU 等&#xff09;&#xff0c;主要通过 MAVLink 协议实现。MAVLink 是一种轻量级的消息传输协议&#xff0c;用于无人机和地面站之间的通信。QGC 通过 MAVLink 消息接收来自无人机的传感…...

Spring配置Bean自己的关系:继承和依赖

继承&#xff1a;这里的继承不是Java中类之间的继承&#xff0c; 是指配置文件中Bean配置项之间的继承。 用parent属性&#xff0c;配置要继承的bean&#xff0c;这样可以把相同的部分去去掉&#xff0c;下上两个bean的关系就变成了父bean和子bean&#xff0c; 子bean可以继承父…...

科技与狠活

科技与狠货&#xff0c;已经见怪不怪了 从黑龙江到海南&#xff0c;从上海到新疆&#xff0c;960万平方公里&#xff0c;十三亿人&#xff0c;每个地方都是科技与狠活 在抖音上面看到一个评论&#xff0c;如果蔬菜没科技与狠活&#xff0c;估计会很贵&#xff0c;但是我想到在…...

Vue:axios请求数据转存leanCloud

思路&#xff1a; 采用axios请求需要的数据&#xff0c;查看leanCloud中数据批量存储的格式&#xff0c;将两个数据进行对比&#xff0c;将请求得到的数据封装为云服务存储的格式&#xff0c;再发leanCloud存储数据的请求完成转存 1.封装js代码 //批量操作新增数据 import r…...

实战篇(九):解锁3D魔方的秘密:用Processing编程实现交互式魔方

解锁3D魔方的秘密:用Processing编程实现交互式魔方 使用 Processing 创建一个 3D 魔方效果展示1. 安装 Processing2. 项目结构3. 代码实现4. 代码解释4.1. 初始化魔方4.2. 绘制魔方4.3. 处理鼠标事件4.4. 检查点击的面4.5. 旋转面和最终确定旋转5. 运行和测试6. 细节解释6.1. …...

Android系统上常见的性能优化工具

Android系统上常见的性能优化工具 在Android系统开发中&#xff0c;性能优化是一个重要的任务&#xff0c;有许多工具可以帮助你进行各种方面的性能分析和优化。以下是一些常见的Android性能优化工具及其用途和使用方法&#xff1a; 1. Android Studio Profiler 功能: 提供CP…...

TG创建小程序交互APP登录以及机器人信息

1、搜索 BotFather &#xff0c;输入命令 /newbot 创建机器人。 2、修改机器人信息 /mybots 编辑名称 : 修改机器人名称 编辑关于: 修改关于 hayden yyds&#xff0c;修改以后打开机器人会出现在下图 编辑描述 : 机器人的描述 编辑描述图片 : 机器人的图片 编辑 Botpic…...

探索大模型能力--prompt工程

1 prompt工程是什么 1.1 什么是Prompt&#xff1f; LLM大语言模型终究也只是一个工具&#xff0c;我们不可能每个人都去训一个大模型&#xff0c;但是我们可以思考如何利用好大模型&#xff0c;让他提升我们的工作效率。就像计算器工具一样&#xff0c;要你算10的10倍&#x…...

【经验分享】运用云服务器实现挂机手机网课的操作,部分手机软件适用

目录 第一步下载手机模拟器 第二步找到模拟器的文件位置 第三步找到模拟器的下载文件进行打包处理 ​编辑 第四步将模拟器粘贴到云服务器上 第五步运行程序 第六步在模拟器中下载网课软件 第一步下载手机模拟器 这里我下载的是联想模拟器&#xff0c;用来模拟手机环境 随…...

【从0到1进阶Redis】主从复制 — 主从机宕机测试

上一篇&#xff1a;【从0到1进阶Redis】主从复制 测试&#xff1a;主机断开连接&#xff0c;从机依旧连接到主机的&#xff0c;但是没有写操作&#xff0c;这个时候&#xff0c;主机如果回来了&#xff0c;从机依旧可以直接获取到主机写的信息。 如果是使用命令行&#xff0c;来…...

Flask启动5000端口后关不掉了?

事情是这样的&#xff1a; 使用python app.py启动flask应用后&#xff0c;又启动了另一个flask测试应用&#xff0c;也能启动成功&#xff0c;也没有报设么端口冲突&#xff0c;关闭黑窗口后&#xff0c;访问还是有守护进程在运行&#xff0c; 为什么我知道5000还在运行&#…...

Redis的热key解决

1、Redis热Key会带来哪些问题 1、流量集中&#xff0c;达到物理网卡上限。 当某一热点 Key 的请求在某一主机上超过该主机网卡上限时&#xff0c;由于流量的过度集中&#xff0c;会导致服务器中其它服务无法进行。 2、请求过多&#xff0c;缓存分片服务被打垮。 如果热点过于…...

在linux中查找 / 目录下的以.jar结尾的文件(find / -name *.jar)

文章目录 1、查找 / 目录下的以.jar结尾的文件 1、查找 / 目录下的以.jar结尾的文件 [rootiZuf6332h890vozldoxcprZ ~]# find / -name *.jar /etc/java/java-1.8.0-openjdk/java-1.8.0-openjdk-1.8.0.342.b07-1.el9_0.x86_64/lib/security/policy/limited/US_export_policy.ja…...

【Python爬虫教程】第6篇-使用session发起请求

为什么要使用session 前面介绍了如何使用reqesuts发起请求&#xff0c;今天介绍如何使用session发起请求。session简单理解就是一种会话机制&#xff0c;在浏览器中我们登录完之后&#xff0c;后面再请求服务数据都不需要再登录了&#xff0c;以为Cookie里已经保存了你的会话状…...

【Hot100】LeetCode—763. 划分字母区间

目录 题目1- 思路2- 实现⭐763. 划分字母区间——题解思路 3- ACM 实现 题目 原题连接&#xff1a;763. 划分字母区间 1- 思路 思路 目标&#xff1a;同样的字母 字符串尽可能的长 问1&#xff1a;怎么确定字母数 ——> 哈希表问2&#xff1a;怎么让字符尽可能的长&#…...

分布式服务基于Zookeeper的分布式锁的实现

一、序言 ZooKeeper 的分布式锁机制是一种协调多个客户端访问共享资源的方法。通过使用 ZooKeeper 的持久化节点和临时顺序节点&#xff0c;可以实现高效且可靠的分布式锁。下面是分布式锁的工作原理以及如何使用它的具体步骤。 二、Zookeeper分布式锁的核心原理 创建锁目录节…...

Rust编程-I/O

文件读取: 依赖&#xff1a;标准库中use std::fs; 模块 读取文件&#xff1a;fs::read_to_string(filepath:string) -> Result<String> String是文件内容 下面代码来自《Rust权威指南》&#xff0c;主要作用是从文件中检索&#xff0c;并返回检索内容所在的行&#xf…...

FastAPI 学习之路(四十七)WebSockets(三)登录后才可以聊天

之前我们是通过前端自动生成的token信息&#xff0c;这次我们通过注册登录&#xff0c;保存到本地去实现。首先&#xff0c;我们实现一个登录页面&#xff0c;放在templates目录下。 <!DOCTYPE html> <html lang"en"> <head><meta charset&quo…...

数据结构—链式二叉树-C语言

代码位置&#xff1a;test-c-2024: 对C语言习题代码的练习 (gitee.com) 一、前言&#xff1a; 在现实中搜索二叉树为常用的二叉树之一&#xff0c;今天我们就要通过链表来实现搜索二叉树。实现的操作有&#xff1a;建二叉树、前序遍历、中序遍历、后序遍历、求树的节点个数、求…...

nginx代理gitee

背景 若干台agv设备&#xff0c;这些设备都是没有公网的(无法访问百度等)。 一台服务器(ubuntu20.04)有线可以公网&#xff0c;无线可以实现内部通信(agv&#xff0c;plc等设备)。 目的 agv每一次更新代码&#xff0c;拉取代码等都需要切换到有公网的网络&#xff0c;多台agv设…...

一款IM即时通讯聊天系统源码,包含app和后台源码

一款IM即时通讯聊天系统源码 聊天APP 附APP&#xff0c;后端是基于spring boot开发的。 这是一款独立服务器部署的即时通讯解决方案&#xff0c;可以帮助你快速拥有一套自己的移动社交、 企业办公、多功能业务产品。可以 独立部署&#xff01;加密通道&#xff01;牢牢掌握通…...

Camunda如何通过外部任务与其他系统自动交互

文章目录 简介流程图外部系统pom.xmllogback.xml监听类 启动流程实例常见问题Public Key Retrieval is not allowed的解决方法java.lang.reflect.InaccessibleObjectException 流程图xml 简介 前面我们已经介绍了Camunda的基本操作、任务、表&#xff1a; Camunda组件与服务与…...

Django ORM中ExpressionWrapper的用途

ExpressionWrapper 在 Django ORM 中&#xff0c;直接在 filter 方法中进行字段间的比较时&#xff0c;不能直接使用算术运算符&#xff08;如 、-、*、/&#xff09;来操作 F 对象&#xff0c;需要使用 ExpressionWrapper 来包装表达式并指定输出字段类型。 使用Q对象&#…...

什么软件修复视频画质比较好,视频画质修复工具

有些视频中可能会出现噪点、残影、颜色失真等问题&#xff0c;导致观看时体验感不太好&#xff0c;修复视频画质可以去除这些问题&#xff0c;使视频更加干净、清晰和真实。 高质量的视频画质能够提高观众的观看体验&#xff0c;让观众更加享受观看视频的过程。特别是在需要展示…...