乐趣区

关于数据库:得物-×-StarRocks潮流网购社区的极速-OLAP-实践

#01

为什么是 StarRocks

  • 新一代极速全场景 MPP 数据库,能够用 StarRocks 来反对多种数据分析场景的极速剖析;
  • 架构简洁,采纳了全面向量化引擎,并装备全新设计的 CBO 优化器,查问极速(尤其是多表关联查问);
  • 很好地反对了实时数据分析,并能对实时更新数据进行高效查问,还反对现代化物化视图以进一步减速查问;
  • 用户能够灵便构建包含大宽表、星型模型、雪花模型在内的各类模型;
  • 兼容 MySQL 协定,反对规范 SQL 语法,易于对接应用,全零碎无内部依赖,高可用,易于运维治理。

#02

零碎架构

外围过程:FE(Frontend)、BE(Backend)。所有节点都是有状态的。

FE(Frontend)负责管理元数据,治理客户端连贯,进行查问布局、查问调度等工作。

  • Follower

Leader:Follower 会通过类 Paxos 的 BDBJE 协定选主出一个 Leader,所有事务的提交都是由 Leader 发动并实现;

Follower:进步查问并发,同时参加投票,参加选主操作。

  • Observer:不参加选主操作,只会异步同步并且回放日志,次要用于扩大集群的查问并发能力。

BE(Backend)负责数据存储以及 SQL 执行等工作。

#03

存储架构

在 StarRocks 里,一张表的数据会被拆分成多个 Tablet,而每个 Tablet 都会以多正本的模式存储在 BE 节点中,如下图:

 
Table 数据划分 + Tablet 三正本的数据分布:

StarRocks 反对 Hash 散布、Range-Hash 的组合数据分布(举荐)。

为了等到更高的性能,强烈建议应用 Range-Hash 的组合数据分布,即先分区后分桶的形式。

  • Range 分区可动静增加和删减;
  • Hash 分桶一旦确定,不能再进行调整,只有未创立的分区能力设置新的分桶数。

分区和分桶的抉择是十分要害的。在建表时抉择好的分辨别桶列,能够无效进步集群整体性能。

以下是针对非凡利用场景下,对分区和分桶抉择的一些倡议:

  • 数据歪斜:业务方如果确定数据有很大水平的歪斜,那么倡议采纳多列组合的形式进行数据分桶,而不是只独自采纳倾斜度大的列做分桶。
  • 高并发:分区和分桶应该尽量笼罩查问语句所带的条件,这样能够无效缩小扫描数据,进步并发。
  • 高吞吐:尽量把数据打散,让集群以更高的并发扫描数据,实现相应计算。

1、表的存储

对表进行存储时,会对表进行分区和分桶两层解决,将表的数据扩散到多台机器进行存储和治理。

  • 分区机制:高效过滤,晋升查问性能。

分区相似分表,是对一个表依照分区键进行宰割,能够依照工夫分区,依据数据量依照天 / 月 / 年划分。在查问过程中,能够利用分区裁剪升高数据扫描量晋升查问效率,也能够依据数据的冷热水平把数据分到不同介质上。

  • 分桶机制:充分发挥集群性能,防止热点问题。

应用分桶键 Hash 当前,把数据均匀分布到所有 BE 上,不要呈现 bucket 数据歪斜的状况。分桶键的抉择准则就是分桶列(一个或多个分桶列)的基数要足够高能够将数据充沛打散。

Bucket 数量须要适中,如果心愿充分发挥性能,能够设置为:BE 数量 * CPU core/2,tablet 最好管制在 1GB-10GB 左右,新版本曾经实现 tablet 外部的并行 scan,tablet 数量和 SQL 并行度曾经不齐全绑定,即便在 Tablet 数量较少的状况下,仍然可能充分利用 CPU 资源来并行计算。

  • Tablet:最小的数据逻辑单元,能够灵便设置并行计算资源。

一张表被切分成了多个 Tablet,StarRocks 在执行 SQL 语句时,能够对所有 Tablet 实现并发解决,从而充分利用多机、多核提供的计算能力。

表在创立的时候能够指定正本数,多正本够保证数据存储的高牢靠、服务的高可用。

  • Rowset:每一次数据导入都会生成一个新的数据版本,保留在一个 rowset 中。

一个 tablet 可能有 N(N>=0)个 rowset,一个 rowset 对应 M(M>=0)个理论数据文件。

每次写入都会减少一个版本,无论是单条、还是 stream load 几个 G 的文件。

  • Segment:如果一个 Rowset 数据量比拟大,则拆分成多个 Segment 数据落盘。

#04

案例一:指标工厂服务

1、业务背景

指标工厂服务次要面向业务人员,通过对业务指标的采集和解决,实时反映产品状态,为经营提供数据撑持、检测产品破绽或服务异样、提供指标异样告警性能等。

2、业务场景剖析

业务指标埋点形式多样,并不局限于某种形式,只有合乎埋点标识明确、业务参数丰盛、数据满足可解析的根本要求皆可作为数据源,大抵能够分为:SDK、MySQL BinLog、业务日志、阿里云 ODPS 数据分析。

各种业务场景众口难调,演绎数据特色如下:

  1. 须要全量日志明细;
  2. 须要数据始终是最新的,即满足实时更新场景;
  3. 须要对数据做层级聚合的,即可能是月、周、日、小时等;
  4. 须要能够承载更大的写入量;
  5. 每个业务数据都要灵便配置数据的保留工夫;
  6. 数据源起源多,报表定制化比拟高,有多个数据源合并成一个大宽表的场景、也有多表连贯的的需要;
  7. 各种监控图、报表展现、业务实时查问等,即较高的并非查问。

3、引入 StarRocks

侥幸的是,StarRocks 有比拟丰盛的数据模型,笼罩了下面的所有业务场景的需要,即明细模型、更新模型、聚合模型、主键模型。同时,抉择更为灵便的星型模型代替大宽表的形式,即间接应用多表关联来查问。

  • 明细模型:
  1. 埋点数据通过结构化解决后按明细全量存储;
  2. 该场景对 DB 在亿级数据量下查问性能有较高的要求;
  3. 数据能够通过配置动静分区来配置过期策略;
  4. 场景应用时从结构化数据抉择个别字段维度在线聚合查问。
  • 聚合模型:
  1. 埋点数据数据量微小,且对明细数据不要求溯源,间接做聚合计算,比方计算 PV、UV 场景;
  2. 数据能够通过配置动静分区来配置过期策略。
  • 更新模型:
  1. 埋点数据状态会产生变动,且须要实时更新数据,更新数据范畴不会跨度多个分区的,比方:订单、优惠券状态等;
  2. 数据能够通过配置动静分区来配置过期策略。

基于以上业务场景的剖析,这三种模型能够完满解决数据的问题。

须要实时的数据写入场景,我也沿用了业内风行的解决方案,应用 Flink 实时生产 Kafka 的数据,再以微批的形式(十秒一批)写入到 StarRocks。并且 StarRocks 提供了十分好用的 Flink-connector 插件,能够通过多种形式控制数据的写入频率,在满足数据时效性的要求的同时,也能够升高集群的导入压力。

小 tips:

  1. 尽管 StarRocks 曾经很好地优化了写入性能,当写入压力大,仍会呈现写入回绝,倡议可适当增大单次导入数据量、升高频率。不过这也会导致数据落库提早减少,所以须要做好肯定的取舍,做到收益最大化。
  2. Flink 的 sink 端不倡议配置过大,会引起并发事务过多报错,倡议每个 flink 工作 source 能够配置多些,sink 的连接数不能过大。

4、小结

目前该计划已反对数百个业务指标的接入,波及几十个大盘的指标展现和告警,数据存储 TB 级,每日净增长上百 G,总体运行稳固。

#05

案例二:外部零碎业务看板

1、业务背景

外部零碎业务看板,次要服务于全公司员工,提供我的项目及工作跟踪等性能。

2、业务场景剖析

剖析业务特点:

  1. 数据变更频繁 (更新),变更时间跨度长
  2. 查问时间跨度多
  3. 报表需准实时更新
  4. 关联维表查问多,部门 / 业务线 / 资源域等
  5. 冷热数据,最近数据查问频繁

3、历史架构与痛点

当初数据库选型时,联合业务特点,用户须要动静、灵便的增删记录本人的工作,因此抉择了 JOSN 模型缩小了利用程序代码和存储层之间的阻抗,抉择 MongoDB 作为数据存储。

随同着公司疾速倒退,当须要报表展现,特地是时间跨度比拟大,波及到多部门、多维度、细粒度等报表展现时,MongoDB 的查问须要执行 10s 甚至更久。

4、引入 StarRocks

咱们调研了 StarRocks、ClickHouse 这两款十分优良的剖析型数据库,在选型时,剖析了业务利用场景,次要需要集中在单表聚合查问、多表关联查问、实时更新读写查问。因为维度表更新频繁,适宜存储在 TP 库 MySQL 中,StarRocks 存储不变的事实表。外部表和表面间接做关联查问,即解决了 AP 库不适宜数据频繁变更的问题,又能够晋升多表关联的性能。这个计划在很大水平上升高了开发难度,又能充分利用 StarRocks 的剖析性能,所以最终决定选用 StarRocks 作为存储引擎。

革新阶段,将原先 MongoDB 中的一个汇合拆分成 3 张表。应用明细模型,记录每天对应人员的工作信息,按天分区,由之前的每人每天一条记录改为以事件为单位,每人每天能够多条记录。须要实时频繁更新的维表,则应用 MySQL 存储,通过内部表的形式进行查问,缩小维度数据同步到 StarRocks 的复杂度。

5、小结

革新前,MongoDB 查问,写法简单,需屡次查问。


db.time_note_new.aggregate(
    [{'$unwind': '$depart'},
       {'$match': {'depart': {'$in': ['部门 id']},
           'workday': {'$gte': 1609430400, '$lt': 1646064000},
           'content.id': {'$in': ['事项 id']}, 
           'vacate_state': {'$in': [0, 1]}}
       }, 
       {'$group': { 
           '_id': '$depart', 
           'write_hour': {'$sum': '$write_hour'}, 
           'code_count': {'$sum': '$code_count'}, 
           'all_hour': {'$sum': '$all_hour'}, 
           'count_day_user': {'$sum': {'$cond': [{'$eq': ['$vacate_state', 0]}, 1, 0]}}, 
           'vacate_hour': {'$sum': {'$cond': [{'$eq': ['$vacate_state', 0]}, '$all_hour', 0]}}, 
           'vacate_write_hour': {'$sum': {'$cond': [{'$eq': ['$vacate_state', 0]}, '$write_hour', 0]}}}
           -- ... more field
       }, 
       {'$project': {
           '_id': 1, 
           'write_hour': {'$cond': [{'$eq': ['$count_day_user', 0]}, 0, {'$divide': ['$vacate_write_hour', '$count_day_user']}]}, 
           'count_day_user': 1, 
           'vacate_hour': 1, 
           'vacate_write_hour': 1, 
           'code_count': {'$cond': [{'$eq': ['$count_day_user', 0]}, 0, {'$divide': ['$code_count', '$count_day_user']}]}, 
           'all_hour': {'$cond': [{'$eq': ['$count_day_user', 0]}, 0, {'$divide': ['$vacate_hour', '$count_day_user']}]}}
           -- ... more field
       }
    ]
)

革新后,间接兼容 SQL,单次聚合。


WITH cont_time as (
    SELECT b.depart_id, a.user_id, a.workday, a.content_id, a.vacate_state
        min(a.content_second)/3600 AS content_hour,
        min(a.write_second)/3600 AS write_hour,
        min(a.all_second)/3600 AS all_hour
    FROM time_note_report AS a
    JOIN user_department AS b ON a.user_id = b.user_id
    -- 更多维表关联
    WHERE b.depart_id IN (?)  AND a.content_id IN (?) 
      AND a.workday >= '2021-01-01' AND a.workday < '2022-03-31' 
      AND a.vacate_state IN (0, 1)
    GROUP BY b.depart_id, a.user_id, a.workday, a.content_id,a.vacate_state
)
SELECT M.*, N.*
FROM ( 
    SELECT t.depart_id,
         SUM(IF(t.content_id = 14, t.content_hour, 0))   AS content_hour_14,
         SUM(IF(t.content_id = 46, t.content_hour, 0))   AS content_hour_46,
         -- ...more
    FROM cont_time t
    GROUP BY t.depart_id
) M
JOIN ( 
    SELECT depart_id                                  AS join_depart_id,
      SUM(write_hour)                                 AS write_hour,
      SUM(all_hour)                                   AS all_hour
      -- 更多指标
    FROM cont_time
    GROUP BY depart_id
) N ON M.depart_id = N.join_depart_id
ORDER BY depart_id ASC

以查问报表 2021/01/01~2022/03/01 之间数据比照:

  • StarRocks: 1 次查问聚合,可齐全通过简单 SQL 聚合函数计算,耗时 295ms
  • MongoDB: 需分 2 次查问 + 计算,共耗时 3s+9s=12s

#06

教训分享

在应用 StarRocks 时遇到的一些报错和解决方案(网上材料较少的报错信息):

 a. 数据导入 Stream Load 报错:“current running txns on db 13003 is 100, larger than limit 100”

起因:超过了每个数据库中正在运行的导入作业的最大个数,默认值为 100。能够通过调整 max_running_txn_num_per_db 参数来减少每次导入作业的个数,最好是通过调整作业提交批次。即攒批,缩小并发。

 b. FE 报错:“java.io.FileNotFoundException: /proc/net/snmp (Too many open files)”

起因:文件句柄有余,这里须要留神,如果是 supervisor 治理过程,则须要将文件句柄的配置加到 FE 的启动脚本中。


if [[$(ulimit -n) -lt 60000 ]]; then
  ulimit -n 65535
fi

c. StarRocks 反对应用 Java 语言编写用户定义函数 UDF,在执行函数报错:“rpc failed, host: x.x.x.x”,be.out 日志中报错:


start time: Tue Aug 9 19:05:14 CST 2022
Error occurred during initialization of VM
java/lang/NoClassDefFoundError: java/lang/Object

起因:在应用 supervisor 治理过程的时候,须要留神减少 JAVA_HOME 环境变量,即便是 BE 节点也须要调用 Java 的一些函数,也能够间接将 BE 启动脚本减少 JAVA_HOME 环境变量配置。

 d. 执行 Delete 操作报错如下:

SQL > delete from tableName partition (p20220809,p20220810) where `c_time` > '2022-08-09 15:20:00' and `c_time` < '2022-08-10 15:20:00';
ERROR 1064 (HY000): Where clause only supports compound predicate, binary predicate, is_null predicate and in predicate

起因:目前 delete 后的 where 条件不反对 between and 操作,目前只反对 =、>、>=、<、<=、!=、IN、NOT IN e. 应用 Routine Load 生产 Kakfa 数据的时候产生了大量随机 group_id

倡议:建 Routine Load 的时候指定一下 group name。

 e. 应用 Routine Load 生产 Kakfa 数据的时候产生了大量随机 group_id 

倡议:建 Routine Load 的时候指定一下 group name。

f. StarRocks 连贯超时,查问语句报错:“ERROR 1064(HY000):there is no scanNode Backend”,当重新启动 BE 节点后,短暂复原。日志报错如下:

kafka log-4-FAIL, event: [thrd:x.x.x.x:9092/bootstrap]: x.x.x.x:9092/1: ApiVersionRequest failed: Local: Timed out: probably due to broker version < 0.10 (see api.version.request configuration) (after 10009ms in state APIVERSION_QUERY)

起因:当 Routine Load 连贯 Kafka 有问题时,会导致 BrpcWorker 线程耗尽,影响失常拜访连贯 StarRocks。长期解决方案是找到问题工作,暂停工作,即可复原。

#07

将来布局

接下来咱们会有更多业务接入 StarRocks,替换原有 OLAP 查问引擎,使用更多的业务场景,以积攒教训、进步集群稳定性。

将来也会应用 StarRocks 的新版本,优化主键模型内存占用,以及 2.3 版本的主键模型局部列能力来给业务方提供更灵便的更新形式。

后续心愿 StarRocks 可能继续优化晋升 Bitmap 查问性能,同时提供更欠缺的多租户资源隔离性能。今后咱们也会持续积极参与 StarRocks 的社区探讨,反馈业务场景。

对于 StarRocks

面世两年多来,StarRocks 始终专一打造世界顶级的新一代极速全场景 MPP 数据库,帮忙企业建设“极速对立”的数据分析新范式,助力企业全面数字化经营。

以后曾经帮忙腾讯、携程、顺丰、Airbnb、滴滴、京东、众安保险等超过 170 家大型用户构建了全新的数据分析能力,生产环境中稳固运行的 StarRocks 服务器数目达数千台。

2021 年 9 月,StarRocks 源代码凋谢,在 GitHub 上的星数已超过 3200 个。StarRocks 的寰球社区飞速成长,至今已有超百位贡献者,社群用户冲破 7000 人,吸引几十家国内外行业头部企业参加共建。

退出移动版