性能提升3-4倍!贝壳基于Flink + OceanBase的实时维表服务
作者介绍:肖赞,贝壳找房(北京)科技有限公司 OLAP 平台负责人,基础研发线大数据平台部架构师。
贝壳找房是中国最大的居住服务平台。作为居住产业数字化服务平台,贝壳致力于推进居住服务的产业数字化、智能化进程,通过聚合、助力优质服务者,为中国家庭提供包括二手房交易、新房交易、租赁、家装、家居、家服等一站式、高品质、高效率服务。
前几天,我们在《贝壳降本提效实践:基于 OceanBase 的实时字典服务》中,介绍了实时字典服务的应用场景,在上线 OceanBase 后,贝壳获得了更高的查询性能和稳定性。今天为大家介绍 OceanBase 在贝壳的第二个应用场景——实时维表服务,通过替代原有的 HBase 维表服务,让贝壳的性能提升了 3-4 倍,硬件成本节省了一半,与此同时,运维成本获得了极大降低。
在典型的实时数仓或实时业务场景里,Flink 实时流处理过程中,经常需要将事实表与外部维度表进行关联,查询维度表,补全事实表中的信息。例如,在贝壳家居等业务场景中,需要在用户下单后将订单信息与维度表中商品信息的相关信息进行实时关联。考虑到维表数据量较大,并且 Flink 实时查询 QPS 较高,传统数据库 MySQL 等难以支撑,因此,贝壳采用 HBase 作为维表。HBase 是一个分布式列存储 NoSQL 数据库,具有较好地查询性能,但是也存在一些痛点。
痛点 1:HBase 不支持二级索引
在许多应用场景中,Flink 任务关联维度表时,除了需要基于主键字段进行关联外,还需要其他非主键字段进行关联。但是,HBase 只支持行键(Row Key)作为单一索引,本身并不直接支持二级索引。Apache Phoenix 等项目对 HBase 的基础上进行扩展,能够实现类似于二级索引的功能,但是需要更多的开发和维护成本。
痛点 2:HBase 依赖较多,部署复杂,成本高
HBase 是构建在 Hadoop 生态系统之上的,它依赖于分布式文件系统 HDFS 用于数据的持久化存储,依赖 ZooKeeper 来完成选举、节点管理、集群元数据维护等,因此,在生产环境中部署 HBase 之前,需要先部署和配置 Hadoop、ZooKeeper 等组件,涉及组件多,部署较复杂,运维成本较高,硬件成本也较高,特别是在一些特殊场景下需要分别为其部署独立的 HBase 集群。
基于上述背景,贝壳将目光投向分布式数据库,并锁定具备高性能、高可靠性和可扩展性的 OceanBase。同时,OceanBase 能够很好地解决贝壳业务痛点。
首先,OceanBase 原生支持二级索引功能,可以直接在维表上创建额外的索引,提升维表的查询性能。其次,OceanBase 只有 OBServer 一个角色,不依赖任何外部组件,天然具备高可用能力,部署非常简单。同时,其自带的周边工具也可以快速安装,比如通过 OCP(OceanBase Cloud Platform)白屏化安装或通过 OBD(OceanBase Deployer)命令行安装集群,运维很方便。
在部署资源消耗方面,HBase 方案机器成本大概是 OceanBase 的 2 倍。因为 HBase 为了保证高可用, 采用了双 HRegionServer,而 HBase 又是基于三副本的 Hadoop 存储数据, 所以,一份数据通常需要六副本。在集群规模不大时,使用 Zookeeper、Hadoop 会带来大量额外的机器冗余。但是,使用 OceanBase 存储数据只需要三副本,成本降低一半。
因此,贝壳决定在实时计算平台中引入 OceanBase 作为实时维表存储,在此之前,对 OceanBase 和 HBase 在实时维表 1 对 N 关联和维表 1 对 N 关联场景进行了全面的性能测试对比。
第一,环境准备
OceanBase 和 HBase 测试集群均采用 3 台 Dell EMC PowerEdge R740 服务器节点组成,节点配置规格为:80C/188G/2.9T Nvme SSD,所有的测试任务均运行在同一个 Hadoop 实时集群。HBase 版本为 1.4.9,HBase 集群由 HBase DBA 协助部署和配置,OceanBase 版本为 3.1.2,使用默认配置。
第二,测试方案
首先,为验证维表数据量对于查询性能影响,分别准备了 1 亿、2000 万、10 万的随机测试数据插入 OceanBase 及 HBase,其中主键(HBase为 rowKey)为从 1 至测试数据量的顺序值,OceanBase 建表 DDL 及样例数据如下:
show create table tb_dim_benchmark_range_partitioned;
create table `tb_dim_benchmark_range_partitioned`
(
t1 bigint(20) NOT NULL,
t2 varchar(200) DEFAULT NULL,
……
t30 varchar(200) DEFAULT NULL,
)
PRIMARY KEY (`t1`)
) DEFAULT CHARSET = utf8mb4
ROW_FORMAT = COMPACT
COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 3 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE =
134217728 PCTFREE = 0
partition by range(t1)
(partition PT1 values less than (10000000),
partition PT2 values less than (20000000),
partition PT3 values less than (30000000),
partition PT4 values less than (40000000),
partition PT5 values less than (50000000),
partition PT6 values less than (60000000),
partition PT7 values less than (70000000),
partition PT8 values less than (80000000),
partition PT9 values less than (90000000),
partition PT10 values less than (100000000));
select * from tb_dim_benchmark_range_partitioned limit 1;
# 10000000,c5181f1335efd950960f41cbecb1ab0ed97c43502252b99834f4b6905ea7f7490ca72e1d676bbe9b77016d23e52ada249f2c,
2b5480769a360133d57f09cba16d1c449cc06b42b614bcfa3f9db6bbf7a04bac2be1d373d11c63a77676daf53111c2321b32,
db88f926925d87175aa4be6740f6f2f49d8f8b38f0d0efff2e5e832f3c1aec21e06cc4f2f0b5053e0b9fbab8a16cce80b9ff,
9c0b94cdde25b68264704c890d141444d28544a7ce4955856b3115f913442ec4bc741f033477e366005c927e41842a7cd9be,
4d69eedaae9e42b4ab7388e66992efddfa39cbb6802cf69b97c5892070a68e6eed51f823770587771a49cbbd1b7be1f2e024,
c60b30f6c4e1b3c02d6fb2de58badf8097f782a8534e0c9dc78497ede12b2573e2d9441e0596f37739d26f0830918fb03ff5,
a8a01cbe3bd44e6d52b7e83bd020a23ae305713fd376a0627f610302018c39ec3aa540519dccceb764324282dfbf0bdda6cc,
fd358773a94c1770980e92e66fcd9e4f70d6f3ef35dff86c65a97826698c750489682c2d1d36ab75ddb588da65b61cd6fc63,
cb8a60222389c9ff9ff4e4e492a4f16ed7ea0e6b781379afc7fad78539fbf8da54b0ef8ea7ef9680543ebc0c18a908092bd1,
9cdbf58a3d454d2b14ebf17167d045887ab5eb3a21d3916acc393475011a079c350295fa8b4b324dab63a00f1fbadfb22edb,
cda510824ef5bc82cd4e014c851ed367dbd6da8828cc261070a0db9cc9341764baf445506a12a7eb7265434f29d63c65b3a1,
8d7c4bbcd42364b93b8cae11eff8f50115e36f1f4f4e6a492687bc2374444c4eaf80e1903eb13fcdfbea6f00de999e0f0587,
107b23e4b7e5a16149a8ea7f75c45c607bb5974cbbdf36077615d92591f4830ec5b2b33945d82e8e526f92cb0072cbf8a260,
cda4ab39b6f2b67d1d283077a1beb01771639eff1ae371372bb2555de594699821d43509fdd7014bcf3e5098bd13c30c8199,
a330f59ee2e48051362241f9a24ba1adad4b61fdd18676cd209799bbec6775dc01120abb0e157589d3f594051b5ae2dd6572,
b8e98c3979610c67ea65433a560ab6cf8663c9de201ae1051a14034b317f90aaa1085b49eba3d86748677f4e0575169fb76c,
6753542147a9cf38f4d040f205483a798d1d2a2c0cf2283ec98c735bf82422a8ecdea432cee8c76a00917b8add7eac5aa0b4,
8d8e0c2caeed82f21ddb288affe2fb567c008e8982cb5a4d07343dc4fd6679f550856649fe4bd40eec9747485c660b01e55e,,
c261014cf13c462815e0afece1512409d2549a699e33eaf8cb23b0b23719c870c83817fcaa7466d5d88a1ae240458ba0201a,
2ac55e6bc39eb79694bf00c2b69768365b7833d9f0cb7df078525d9ab98eba5ce2bfc3cc1fb9f4398c49c16073fb5d863172,
77ab6010d7bc664b6861927322276b2d35d4f5ff2d6bc2eec3da9ef936ae836dfbed6783a8c7f9970e19d46e43b52e49a0f6,
4109f993c94f8ca40c6932d01a726fb173beb60e34b57bf488f86fe9e6c12f7f7497c720fa95099c6a43cb3442444b367ea4,
7891bdf8a52dc19d311f392fa5f34509c6dcb33b8b8e291131ca5d46c517ea0933868874244aff1b3345ea5279fe0c659709,
200e69e8ec8e6104834596c2fefe8ed772ba9b7de4f1287c91c3b91469dd985fbb93d55a9497b2606ae9003975458b6b054b,
a2de28933b2cf1f9166cf3aab732f5c6b68967eddef0472a8577a82f37e77bcfc45a5e0adc11d382160d3c84ec14e0e75b5d,
1fa6bcf4d9ef2076aa016e78db575595a9155dfe6484a9812ae690fc20c244bf2d09355ba7dbc32495330a21b6e3c893ba6b,
b01a0b4ba3d8ae159d330720bb8baffe3ad2504b221151b8f68304ed7c14a03d21f75a4e6ad16873ea0c8904717478d3f7c4,
a00ae3e9a8c89f5a0f0fae92934d23adeb9117ef7c91f80f0d5306eca558b77422f273283e867a6b7320e91895087e652ed7
其次,为避免测试流程中其他依赖组件(例如物理 Source、Sink)对维表关联性能造成影响,对 SQL 的测试数据源使用 DataGen SQL Connector (支持在内存中随机或顺序 生成记录)及 BlackHole SQL Connector(吞掉所有输入数据,用于性能测试)。
CREATE TABLE `data_gen_source` (`t1` BIGINT, `t2` VARCHAR, `proctime` AS PROCTIME()) WITH (
'connector' = 'datagen',
'fields.t1.kind' = 'random',
'fields.t1.min' = '1',
'fields.t1.max' = '100000',
'rows-per-second' = '100000000'
);
CREATE TABLE `tb_dim_benchmark_1`(
`t1` BIGINT,
`t2` VARCHAR,
……
`t30` VARCHAR,
PRIMARY KEY (`t1`) NOT ENFORCED
) WITH (
'connector' = 'jdbc',
'url' = '',
'driver' = 'com.mysql.jdbc.Driver',
'sink.buffer-flush.max-rows' = '500',
'table-name' = 'tb_dim_benchmark_range_partitioned_10w'
);
CREATE TABLE blackhole_table (
`t1` BIGINT,
`t2` VARCHAR,
……
`t30` VARCHAR
) WITH ('connector' = 'blackhole');
INSERT INTO blackhole_table
SELECT tb1.`t1`,tb2.`t2`,tb2.`t3`,tb2.`t4`,tb2.`t5`,tb2.`t6`,tb2.`t7`,tb2.`t8`,tb2.`t9`,tb2.`t10`,tb2.`t11`,tb2.
`t12`,tb2.`t13`,tb2.`t14`,tb2.`t15`,tb2.`t16`,tb2.`t17`,tb2.`t18`,tb2.`t19`,tb2.`t21`,tb2.`t22`,tb2.`t23`,tb2.
`t24`,tb2.`t25`,tb2.`t26`,tb2.`t27`,tb2.`t28`,tb2.`t29`,tb2.`t30`
FROM `data_gen_source` tb1
LEFT JOIN `tb_dim_benchmark_1` FOR SYSTEM_TIME as of tb1.`proctime` as tb2 ON tb1.`t1` = tb2.`t1`;
第三,测试结果
-
维表 1 对 1 关联,即 DataGen 生成随机值与 OceanBase(索引字段)和HBase(RowKey)关联,测试数据如下表所示。
-
维表 1 对 N 关联,即 DataGen 生成随机值与 OceanBase(二级索引列)关联, 测试那颗数据如下表所示。
基于测试结果,可以得到四个结论:
-
维表数据量在 2000 万及 1 亿条(大数据量)时,低任务并行度下的 OceanBase QPS 优于 HBase,高任务并行度下 OceanBase 相比 HBase 有 3-4 倍性能提升,优势明显。
-
维表数据量在 10w(小数据量)时,低任务并行度下 HBase QPS 略高于 OceanBase,高并行度下 OceanBase 优势明显。
-
对 OceanBase 使用非索引列关联性能较差,后续使用需注意大维表关联时关联字段加索引,实时计算平台可从平台功能角度优化,例如用户关联了非索引列则在 SQL 校验阶段提示用户创建索引。
-
对 OceanBase 使用二级索引列关联(1 对 N 关联)性能良好,可满足较高 QPS 业务场景需求。
从以上测试结果来看,在相同环境下,OceanBase 综合性能要优于 HBase,并且原生支持二级索引能力,部署简单,具有更低的硬件成本和运维成本,因此,贝壳选择使用 OceanBase 替换 HBase,作为实时计算平台的实时维表存储。
在 OceanBase 的应用过程中,贝壳也提出了一些建议:比如,发现普通的关系表不支持 TTL(当前使用的是 OceanBase 3.1.2 社区版本),经与社区沟通,OceanBase 的 3.1.4 版本已经支持 table API 或 Hbase API 等 API 模型,OceanBase 4.0 版本已经支持全局二级索引。
另外,贝壳建议 OceanBase 在与大数据生态打通(例如导入导出、计算等)方面可以进一步加强,更好地支持大数据到 OceanBase 的导入导出等。
相关文章:

性能提升3-4倍!贝壳基于Flink + OceanBase的实时维表服务
作者介绍:肖赞,贝壳找房(北京)科技有限公司 OLAP 平台负责人,基础研发线大数据平台部架构师。 贝壳找房是中国最大的居住服务平台。作为居住产业数字化服务平台,贝壳致力于推进居住服务的产业数字化、智能…...

取数组中每个元素的最高位
1 题目 /*程序将一维数组a中N个元素的最高位取出,保存在一维数组b的对应位置。 程序运行结果为: a:82 756 71629 5 2034 b: 8 7 7 5 2 */ 2 思考 简单来说就是取一个数据的最高位。 一开始的笨方法没有办法判断数据的长度,后来…...
Docker一键部署Nacos
官方参考文档: https://nacos.io/zh-cn/docs/quick-start-docker.html 本人实践 一、创建数据库&数据表 使用sql脚本创建:https://github.com/alibaba/nacos/blob/master/config/src/main/resources/META-INF/nacos-db.sql 二、新建文件夹并赋权…...

【数学建模】-- 模糊综合评价
模糊综合评价(Fuzzy Comprehensive Evaluation)是一种用于处理不确定性和模糊性信息的决策分析方法。它通常用于解决复杂的多指标决策问题,其中各指标之间可能存在交叉影响和模糊性的情况。模糊综合评价通过将不确定性和模糊性量化࿰…...

Java 数据库改了一个字段, 前端传值后端接收为null问题解决
前端传值后端为null的原因可能有很多种,我遇到一个问题是,数据库修改了一个字段,前端传值了,但是后台一直接收为null值, 原因排查: 1、字段没有匹配上,数据库字段和前端字段传值不一致 2、大…...

lnmp架构-mysql1
1.MySQL数据库编译 make完之后是这样的 mysql 初始化 所有这种默认不在系统环境中的路径里 就这样加 这样就可以直接调用 不用输入路径调用 2.初始化 重置密码 3.mysql主从复制 配置master 配置slave 当master 端中还没有插入数据时 在server2 上配slave 此时master 还没进…...
Threadlocal在项目中的应用
ThreadLocal为每一线程提供一份单独的存储空间,具有线程隔离的作用 PageHelper.startPage()方法使用ThreadLocal来保存分页参数,保证线程安全性。PageHelper通过集成MyBatis的拦截器机制来实现对SQL语句的拦截和修改 项目中使用了ThreadLocal保存每个线程…...

个性化定制你的AI助手,AI指令提示词专家
『个性化定制你的AI助手』围观不如下场!需要学习AI指令提升能力的,精准输出想要内容的,快来订阅 javastarboy『AI指令保姆级拆解』合集! ▶️你是否尚未挖掘到 AI 的潜力? ▶️你是否经常遇到“答非所问”的“人工智障…...

mongodb聚合排序的一个巨坑
现象: mongodb cpu动不动要100%,如下图 分析原因: 查看慢日志发现,很多条这样的查询,一直未执行行完成,占用大量的CPU [{$match: {"tags.taskId": "64dae0a9deb52d2f9a1bd71e",grnty: …...

无涯教程-分类算法 - 随机森林
随机森林是一种监督学习算法,可用于分类和回归,但是,它主要用于分类问题,众所周知,森林由树木组成,更多树木意味着更坚固的森林。同样,随机森林算法在数据样本上创建决策树,然后从每…...
c#常见的排序算法
在C#中,常见的排序算法包括以下几种: 1. 冒泡排序(Bubble Sort):比较相邻的元素,如果顺序不对就交换它们,重复多次直到排序完成。 2. 插入排序(Insertion Sort)…...

Redis 持久化和发布订阅
一、持久化 Redis 是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失。所以 Redis 提供了持久化功能! 1.1、RDB(Redis DataBase) 1.1.1 …...

k8s使用ECK(2.4)形式部署elasticsearch+kibana-http协议
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、准备elasticsearch-cluster.yaml二、部署并测试总结 前言 之前写了eck2.4部署eskibana,默认的话是https协议的,这里写一个使用http…...

[maven]关于pom文件中的<relativePath>标签
关于pom文件中的<relativePath>标签 为什么子工程要使用relativePath准确的找到父工程pom.xml.因为本质继承就是pom的继承。父工程pom文件被子工程复用了标签。(可以说只要我在父工程定义了标签,子工程就可以没有,因为他继承过来了&…...

11. 网络模型保存与读取
11.1 网络模型保存(方式一) import torchvision import torch vgg16 torchvision.models.vgg16(pretrainedFalse) torch.save(vgg16,"./model/vgg16_method1.pth") # 保存方式一:模型结构 模型参数 print(vgg16) 结果: VGG((feature…...

新SDK平台下载开源全志V853的SDK
获取SDK SDK 使用 Repo 工具管理,拉取 SDK 需要配置安装 Repo 工具。 Repo is a tool built on top of Git. Repo helps manage many Git repositories, does the uploads to revision control systems, and automates parts of the development workflow. Repo is…...

多图详解VSCode搭建Java开发环境
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

基于JavaWeb和mysql实现网上书城前后端管理系统(源码+数据库+开题报告+论文+答辩技巧+项目功能文档说明+项目运行指导)
一、项目简介 本项目是一套基于JavaWeb和mysql实现网上书城前后端管理系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含:项目源码、项目文档、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都…...
Swift创建单例
Objective-C使用GCD 中的dispatch_once_t 可以保证里面的代码只被调用一次,以此保证单例在线程上的安全。 但是在Swift 中由于废弃了原有的Dispatch once方法,因此无法使用once 进行单例的创建。 我们可以使用struct 存储类型变量,并且使用…...

问道管理:市盈率怎么计算?
市盈率是衡量一家公司股票价格是否合理的重要目标之一,核算市盈率的公式是将一家公司的股票价格除以每股收益,也便是市盈率 股票价格 每股收益。市盈率能够告诉你一个公司的股票价格是否高估或轻视,是投资者在买入或卖出一家公司股票时需求…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...

GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
微服务通信安全:深入解析mTLS的原理与实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...

云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...