几道常见面试问题总结(二)

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 几道常见面试问题总结(二)

1:oltp与olap的区别?

1、数据主要应用2、数据内容3、性能要求总结:

2:数据湖、数据仓库、数据中台、湖仓一体、混合架构之间的区别?

3:routing load 怎么调优?怎么降低磁盘io?

1) 任务调度周期

max_batch_interval
通过缩短任务调度周期加速数据消费。但是,更小的任务调度周期可能会带来更多的CPU资源消耗。
需要注意的是,任务调度周期最小值为5s。

2)任务并行度

max_routine_load_task_concurrent_num
desired_concurrent_number
在partition数量和BE数量较多时,可以通过设置较大的该参数来加速任务执行。但是,更大的并行度可能会带来更多的CPU资源消耗。
单个 routine load 任务会根据kafka topic partition数、BE数等被拆分为若干个子任务,分发至多个BE执行。这里的任务并行度,实际上是指单个routine load拆分成的子任务个数。
任务并行度取决于 Job 配置 desired_concurrent_num、可用 BE 数、 FE 配置、topic partition数和 max_routine_load_task_concurrent_num 的最小值,具体的计算方式如下:
concurrent_num = Min(partition_num, desired_concurrent_num, alive_be_num, Config.max_routine_load_task_concurrent_num)
因此,在调整该参数时需要综合考虑BE数量和partition数量。

3)任务批量大小

routine_load_task_consume_second
通过增大单次读取持续时间加速数据消费。
max_routine_load_batch_size
通过增大单次读取的数据量加速数据消费。
I0325 20:27:50.410579 15259 data_consumer_group.cpp:131] consumer group done: 41448fb1a0ca59ad-30e34dabfa7e47a0. consume time(ms)=3261, received rows=179190, received bytes=9855450, eos: 1, left_time: -261, left_bytes: 514432550, blocking get time(us): 3065086, blocking put time(us): 24855
可以根据如上的日志来判定当前的批量参数设置是否过小。正常情况下,该日志的 left_bytes 字段应该 >= 0,表示一次读取的数据量还未超过 max_routine_load_batch_size上限 。否则,说明 max_routine_load_batch_size 过小。

4:Flink cdc1.x mysql和cdc2.x 有啥区别?

Flink cdc1.x的缺点

一致性通过加全局锁保证:全量 + 增量读取的过程需要保证所有数据的一致性,因此需要通过加锁保证,但是加锁在数据库层面上是一个十分高危的操作。底层 Debezium 在保证数据一致性时,需要对读取的库或表加锁,全局锁可能导致数据库锁住,表级锁会锁住表的读,DBA 一般不给锁权限。
单并发任务同步,不支持水平扩展:因为 Flink CDC 底层是基于 Debezium,起架构是单节点,所以Flink CDC 只支持单并发。在全量阶段读取阶段,如果表非常大 (亿级别),读取时间在小时甚至天级别,用户不能通过增加资源去提升作业速度。
不支持断点续传,全量读取阶段不支持 checkpoint:CDC 读取分为两个阶段,全量读取和增量读取,目前全量读取阶段是不支持 checkpoint 的,因此会存在一个问题:当我们同步全量数据时,假设需要 5 个小时,当我们同步了 4 小时的时候作业失败,这时候就需要重新开始,再读取 5 个小时。

Flink cdc2.x的改进

并发读取,全量数据的读取性能可以水平扩展;
全程无锁,不对线上业务产生锁的风险;(全局锁退化为表级锁)
断点续传,支持全量阶段的 checkpoint。
MySQL CDC 支持动态加表
分片算法优化

全量 + 增量读取的过程需要保证所有数据的一致性,因此需要通过加锁保证。debezium 在 snapshot 阶段的一致性通过对表加锁来实现,全局锁可能导致数据库被 hang 住,debezium 需要锁权限。这是个高危操作

表锁是全局锁的退化版,因为全局锁的权限会比较高,因此在某些场景,用户只有表锁。表锁锁的时间会更长,因为表锁有个特征:锁提前释放了可重复读的事务默认会提交,所以锁需要等到全量数据读完后才能释

cdc2.0 无全局锁怎么保证一致性?

一个SourceReader包含多个chunk
        一致性包括:
            一个chunk内部的一致性
            一个SourceReader里,多个chunk的一致性
    chunk读取:  记录binlog(低水位)
                =》 开始读取,得到数据 =》 放到一个buffer里(等待修正)
                =》 再次查看binlog(高水位)
                =》 如果 高水位 > 低水位,说明读取期间,有变化
                =》 获取变化的binlog,修正读取的数据
        =》单个Chunk中的数据一致性
    SourceReader内部多个Chunk的一致性:
        取多个chunk之间最大的 高水位 
        每个chunk去补足,自己的高水位到 最大高水位之间的数据
        ==》所有的chunk,都同步到了同一个进度


关于serverId?

配置 server-id 在 MySQL 服务器中,每个 slave 都有一个唯一的 server-id,其作用是用于区分来自不同的 slave 的 MySQL binlog。因此,在需要进行 CDC 操作时,需要为 MySQL 服务器配置 server-id。通常来说,对于一个 MySQL 实例而言,只需要配置一个全局唯一的 server-id 即可。

配置 job 每个 job 都需要配置一个独立的 replication slot,该 slot 用于表示连接到 master 的客户端。当订阅某个表时,可以为该表创建一个新的 replication slot。这意味着每个 job 都需要配备独立的 replication slot 来管理 CDC 流程。具体而言:通过使用 CREATE_REPLICATION_SLOT() SQL 命令,可以为每个要订阅的表配置一个独立的 replication slot。

在Flink CDC中,如果两个任务(source和sink)监控同一个MySQL表,并且MySQL的server-id(也称为数据库ID)发生了变化,那么可能会导致一些问题。
当server-id发生变化时,MySQL会重新分配一个新的server-id给连接。如果源任务和目标任务使用相同的server-id连接到MySQL数据库,那么它们之间的通信将会失败。因此,您需要确保源任务和目标任务使用的MySQL server-id是不同的。
如果您已经确认了MySQL server-id没有变化,但仍然遇到重启问题,那么可能是由于其他原因导致的。例如,可能存在以下情况:
    数据源或目标出现了故障或异常,导致任务无法正常运行。您可以检查任务的日志文件或监控指标来确定是否存在此类问题。
    Flink CDC插件版本不兼容或存在bug,导致任务无法正常工作。您可以尝试升级或降级Flink CDC插件版本,并重新启动任务以查看是否解决了问题。
    数据库连接池配置不正确,导致连接超时或断开。您可以检查数据库连接池的配置参数,并根据需要进行调整。
综上所述,如果您遇到了Flink CDC任务重启的问题,建议您先检查MySQL server-id是否正确设置,并检查任务的日志文件和监控指标以确定是否存在其他故障或异常。如果问题仍然存在,请尝试升级或降级Flink CDC插件版本,并检查数据库连接池的配置参数。

5: presto 和 clickhouse有什么缺点?

presto缺点:

没有容错性:不支持单个query内部执行容错(query 中包含多个 Task,如果某个Task 失败了,会导致整个Query 失败,而不会进行把 task 在移动到其他工作节点处理重试)
不支持事务:不是数据库,不进行数据存储,不支持在线事务
内存限制: 基于内存计算,当内存空间不足时,不会将一部分结果保存到磁盘上,直接就查询失败,不适合大表的join操作。虽然能够处理 PB 级别的海量数据分析,但不是代表 Presto 把 PB 级别都放在内存中计算的。而是根据场景,如 count,avg 等聚合运算,是边读数据边计算,再清内存,再读数据再计算,这种耗的内存并不高。但是连表查询,就可能产生大量的临时数据,因此速度会变慢,反而 Hive此时会更擅长。
并行限制:多个task 并行在worker节点进行计算,当其中一台worker计算缓慢,会让整个query流程效率变慢
并发限制:因为全内存操作+内存限制,能同时处理的数据量有限,因而导致并发能力不足。高并发支持不够,coordinator 容易成为瓶颈。
维护性:数据关联组件多、维护成本高。
查询性能:相较于doris、starrocks等MPP数据库,查询性能一般,无法满足业务方希望能快速获取数据的需求。
缺少 Bitmap 数据类型,在标签计算方面存在一些不足。

clickhouse缺点:

1、不支持事务,事务可以是一条SQL语句或一组SQL语言或者整个程序,只要中间有任何错误这个事务的所有操作都要撤销。
2、缺少完整的UPDATE DELETE操作, 对于工具自动生成的语句不支持,必须通过变通的方式来完成这两类操作,仅能用于批量删除或者修改数据。
3、部分技术支持待完善,支持有限的操作系统,驱动程序不够完善,市面主流工具对其支持不全。
4、不支持BIOB DOCUMENT 类型数据,聚合结果必须小于一台机器的内存大小。
5、不支持高并发,官方建议qps为100,可以通过修改config.xml的max_concurrent_queries配置。
6:不支持二级索引
7:有限的SQL支持,join实现与众不同
8:不支持窗口功能
9:元数据管理需要人工干预维护,运维起来比较麻烦。
10:多表join效率性能比较低

6:starrocks/doris bitmap索引和Bloom filter 索引使用场景和限制?

bitmap索引

适应场景:
1 非前缀过滤
StarRocks对于建表中的前置列可以通过shortkey索引快速过滤,但是对于非前置列, 无法利用shortkey索引快速过滤,如果需要对非前置列进行快速过滤,就可以对这些列建立Bitmap索引。
2 多列过滤Filter
由于Bitmap可以快速的进行bitwise运算。所以在多列过滤的场景中,也可以考虑对每列分别建立Bitmap索引。
3:人群圈选,精确去重...等
优点
对于基数较低,值大量重复,例如 ENUM 类型的列,使用 Bitmap 索引能够减少查询的响应时间。如列基数较高,推荐使用 Bloom filter 索引。
Bitmap 索引所占的存储空间通常只有索引数据的一小部分,与其他索引技术相比,更节省存储空间。
支持为多个列创建 Bitmap 索引,提高多列查询的效率,具体参见多列查询。
限制:
Bitmap 索引适用于可使用等值条件 (=) 查询或 [NOT] IN 范围查询的列。
主键模型和明细模型中所有列都可以创建 Bitmap 索引;聚合模型和更新模型中,只有维度列(即 Key 列)支持创建 bitmap 索引。
Bitmap索引适用于一些特定类型的查询, 应该在取值为枚举型, 取值大量重复, 较低基数, 并且用作等值条件查询或者可转化为等值条件查询的列上创建.
bitmap索引不适用更新频繁的列。不适合列基数较高的场景。
不支持对Float、Double、Decimal 类型的列建Bitmap 索引。
如果要查看某个查询是否命中了Bitmap索引,可以通过查询的Profile信息中的 BitmapIndexFilterRows 字段查看

Bloom filter 索引

适应场景:
1)非前缀列过滤;
2)高基数列;
3)查询需对某列高频过滤,且查询条件是in和=(Bloom Filter索引只对in和=过滤查询有加速效果);
4)非Tinyint、Float、Double、DECIMAL类型的列(这些类型暂不支持)。
5)对于明细模型,所有列都可以创建Bloom Filter索引。聚合模型和更新模型,只有Key列可以建Bloom Filter索引。主键模型允许为主键列创建Bloom Filter索引,可在建表时创建,也可以建表后添加。不支持非主键列创建Bloom Filter索引。
优点:
Bloom filter 索引可以快速判断表的数据文件中是否可能包含要查询的数据,如果不包含就跳过,从而减少扫描的数据量。
Bloom filter 底层实现是通过bitmap+多个hash函数来实现的,空间效率和时间效率都比较高,但是有一定的误判率。
限制:
主键模型和明细模型中所有列都可以创建 Bloom filter 索引;聚合模型和更新模型中,只有维度列(即 Key 列)支持创建 Bloom filter 索引。
不支持为 TINYINT、FLOAT、DOUBLE 和 DECIMAL 类型的列创建 Bloom filter 索引。
Bloom filter 索引只能提高包含 in 和 = 过滤条件的查询效率,例如 Select xxx from table where xxx in () 和 Select xxx from table where column = xxx。
如要了解一个查询是否命中了 Bloom filter 索引,可查看该查询的 Profile 中的 BloomFilterFilterRows 字段。

7:doris/starrocks的几种join的场景和限制?

Bucket Shuffle Join

Bucket Shuffle Join有着较为明显的性能优势。减少数据在节点间的传输耗时和Join时的内存开销。相对于Doris原有的Join方式,它有着下面的优点

首先,Bucket-Shuffle-Join降低了网络与内存开销,使一些Join查询具有了更好的性能。尤其是当FE能够执行左表的分区裁剪与桶裁剪时。
其次,同时与Colocate Join不同,它对于表的数据分布方式并没有侵入性,这对于用户来说是透明的。对于表的数据分布没有强制性的要求,不容易导致数据倾斜的问题。
最后,它可以为Join Reorder提供更多可能的优化空间。

Bucket Shuffle Join的规划规则

在绝大多数场景之中,用户只需要默认打开session变量的开关就可以透明的使用这种Join方式带来的性能提升,但是如果了解Bucket Shuffle Join的规划规则,可以帮助我们利用它写出更加高效的SQL。

Bucket Shuffle Join只生效于Join条件为等值的场景,原因与Colocate Join类似,它们都依赖hash来计算确定的数据分布。
在等值Join条件之中包含两张表的分桶列,当左表的分桶列为等值的Join条件时,它有很大概率会被规划为Bucket Shuffle Join。
由于不同的数据类型的hash值计算结果不同,所以Bucket Shuffle Join要求左表的分桶列的类型与右表等值join列的类型需要保持一致,否则无法进行对应的规划。
Bucket Shuffle Join只作用于Doris原生的OLAP表,对于ODBC,MySQL,ES等外表,当其作为左表时是无法规划生效的。
对于分区表,由于每一个分区的数据分布规则可能不同,所以Bucket Shuffle Join只能保证左表为单分区时生效。所以在SQL执行之中,需要尽量使用where条件使分区裁剪的策略能够生效。
假如左表为Colocate的表,那么它每个分区的数据分布规则是确定的,Bucket Shuffle Join能在Colocate表上表现更好。

Colocation Join

Colocation Join 功能,是将一组拥有相同 CGS 的 Table 组成一个 CG。并保证这些 Table 对应的数据分片会落在同一个 BE 节点上。使得当 CG 内的表进行分桶列上的 Join 操作时,可以通过直接进行本地数据 Join,减少数据在节点间的传输耗时。

Colocate Join 十分适合几张表按照相同字段分桶,并高频根据相同字段 Join 的场景,比如电商的不少应用都按照商家 Id 分桶,并高频按照商家 Id 进行 Join。

Colocation Join限制条件

为了使得表能够有相同的数据分布,同一 CG 内的表必须满足下列约束:
      Colocate Table 必须是 OLAP 类型的表
      同一 CG 内的表的分桶键的类型、数量和顺序完全一致,并且桶数一致,从而保证多张表的数据分片能够一一对应地进行分布控制。分桶键,即在建表语句中 DISTRIBUTED BY HASH(col1, col2, ...) 中指定一组列。分桶键决定了一张表的数据通过哪些列的值进行 Hash 划分到不同的 Bucket Seq 下。同 CG 的表的分桶键的名字可以不相同,分桶列的定义在建表语句中的出现次序可以不一致,但是在 DISTRIBUTED BY HASH(col1, col2, ...) 的对应数据类型的顺序要完全一致。
      同一个 CG 内所有表的所有分区的副本数必须一致。如果不一致,可能出现某一个子表的某一个副本,在同一个 BE 上没有其他的表分片的副本对应。
      同一个 CG 内所有表的分区键,分区数量,分区列的类型可以不同。
同一个 CG 中的所有表的副本放置必须满足下列约束:
     CG 中所有表的 Bucket Seq 和 BE 节点的映射关系和 Parent Table 一致。
     Parent Table 中所有分区的 Bucket Seq 和 BE 节点的映射关系和第一个分区一致。
     Parent Table 第一个分区的 Bucket Seq 和 BE 节点的映射关系利用原生的 Round Robin 算法决定。
     CG 内表的一致的数据分布定义和子表副本映射,能够保证分桶键取值相同的数据行一定在相同 BE 节点上,因此当分桶键做 Join 列时,只需本地 Join 即可。

Runtime Filter

旨在为某些 Join 查询在运行时动态生成过滤条件,来减少扫描的数据量,避免不必要的I/O和网络传输,从而加速查询。

Runtime Filter主要用于大表join小表的优化,如果左表的数据量太小,或者右表的数据量太大,则Runtime Filter可能不会取得预期效果

Runtime Filter查询选项

与Runtime Filter相关的查询选项信息,请参阅以下部分:

第一个查询选项是调整使用的Runtime Filter类型,大多数情况下,您只需要调整这一个选项,其他选项保持默认即可。
       runtime_filter_type: 包括Bloom Filter、MinMax Filter、IN predicate、IN Or Bloom Filter、Bitmap Filter,默认会使用IN Or Bloom Filter,部分情况下同时使用Bloom Filter、MinMax Filter、IN predicate时性能更高。
其他查询选项通常仅在某些特定场景下,才需进一步调整以达到最优效果。通常只在性能测试后,针对资源密集型、运行耗时足够长且频率足够高的查询进行优化。
        runtime_filter_mode: 用于调整Runtime Filter的下推策略,包括OFF、LOCAL、GLOBAL三种策略,默认设置为GLOBAL策略
        runtime_filter_wait_time_ms: 左表的ScanNode等待每个Runtime Filter的时间,默认1000ms
        runtime_filters_max_num: 每个查询可应用的Runtime Filter中Bloom Filter的最大数量,默认10
        runtime_bloom_filter_min_size: Runtime Filter中Bloom Filter的最小长度,默认1048576(1M)
        runtime_bloom_filter_max_size: Runtime Filter中Bloom Filter的最大长度,默认16777216(16M)
        runtime_bloom_filter_size: Runtime Filter中Bloom Filter的默认长度,默认2097152(2M)
        runtime_filter_max_in_num: 如果join右表数据行数大于这个值,我们将不生成IN predicate,默认1024

runtime_filter_type:

IN or Bloom Filter
Bloom Filter
MinMax Filter
IN predicate
Bitmap Filter
https://doris.apache.org/zh-CN/docs/dev/query-acceleration/join-optimization/runtime-filter#runtime-filter%E6%9F%A5%E8%AF%A2%E9%80%89%E9%A1%B9

Runtime Filter的规划规则

1:只支持对join on clause中的等值条件生成Runtime Filter,不包括Null-safe条件,因为其可能会过滤掉join左表的null值。
2:不支持将Runtime Filter下推到left outer、full outer、anti join的左表;
3:不支持src expr或target expr是常量;
4:不支持src expr和target expr相等;
5:不支持src expr的类型等于HLL或者BITMAP;
6:目前仅支持将Runtime Filter下推给OlapScanNode;
7:不支持target expr包含NULL-checking表达式,比如COALESCE/IFNULL/CASE,因为当outer join上层其他join的join on clause包含NULL-checking表达式并生成Runtime Filter时,将这个Runtime Filter下推到outer join的左表时可能导致结果不正确;
8:不支持target expr中的列(slot)无法在原始表中找到某个等价列;
9:不支持列传导,这包含两种情况:
    一是例如join on clause包含A.k = B.k and B.k = C.k时,目前C.k只可以下推给B.k,而不可以下推给A.k;
    二是例如join on clause包含A.a + B.b = C.c,如果A.a可以列传导到B.a,即A.a和B.a是等价的列,那么可以用B.a替换A.a,然后可以尝试将Runtime Filter下推给B(如果A.a和B.a不是等价列,则不能下推给B,因为target expr必须与唯一一个join左表绑定);
10:Target expr和src expr的类型必须相等,因为Bloom Filter基于hash,若类型不等则会尝试将target expr的类型转换为src expr的类型;
11:不支持PlanNode.Conjuncts生成的Runtime Filter下推,与HashJoinNode的eqJoinConjuncts和otherJoinConjuncts不同,PlanNode.Conjuncts生成的Runtime Filter在测试中发现可能会导致错误的结果,例如IN子查询转换为join时,自动生成的join on clause将保存在PlanNode.Conjuncts中,此时应用Runtime Filter可能会导致结果缺少一些行。

Doris Join 调优建议

最后我们总结 Doris Join 优化调优的四点建议:

第一点:在做 Join 的时候,要尽量选择同类型或者简单类型的列,同类型的话就减少它的数据 Cast,简单类型本身 Join 计算就很快。
第二点:尽量选择 Key 列进行 Join, 原因前面在 Runtime Filter 的时候也介绍了,Key 列在延迟物化上能起到一个比较好的效果。
第三点:大表之间的 Join ,尽量让它 Colocation ,因为大表之间的网络开销是很大的,如果需要去做 Shuffle 的话,代价是很高的。
第四点:合理的使用 Runtime Filter,它在 Join 过滤率高的场景下效果是非常显著的。但是它并不是万灵药,而是有一定副作用的,所以需要根据具体的 SQL 的粒度做开关。
最后:要涉及到多表 Join 的时候,需要去判断 Join 的合理性。尽量保证左表为大表,右表为小表,然后 Hash Join 会优于 Nest Loop Join。必要的时可以通过 SQL Rewrite,利用 Hint 去调整 Join 的顺序。

8:几款数据湖产品选型对比?

相关实践学习
AnalyticDB MySQL海量数据秒级分析体验
快速上手AnalyticDB MySQL,玩转SQL开发等功能!本教程介绍如何在AnalyticDB MySQL中,一键加载内置数据集,并基于自动生成的查询脚本,运行复杂查询语句,秒级生成查询结果。
阿里云云原生数据仓库AnalyticDB MySQL版 使用教程
云原生数据仓库AnalyticDB MySQL版是一种支持高并发低延时查询的新一代云原生数据仓库,高度兼容MySQL协议以及SQL:92、SQL:99、SQL:2003标准,可以对海量数据进行即时的多维分析透视和业务探索,快速构建企业云上数据仓库。 了解产品 https://www.aliyun.com/product/ApsaraDB/ads
相关文章
|
3月前
|
算法
分享几道大厂面试算法题
分享几道大厂面试算法题
|
XML Java 程序员
跟面试官刚聊几句,被发现连这几道都不会,便被请了出去
跟面试官刚聊几句,被发现连这几道都不会,便被请了出去
76 0
|
6月前
|
算法 前端开发 JavaScript
面试必会的几道算法
面试必会的几道算法
|
算法 程序员
程序员可能越来越排斥面试时做题的原因
程序员可能越来越排斥面试时做题的原因
88 1
|
存储 分布式计算 Java
几道面试题
几道面试题
几道面试题
|
存储 算法 索引
面试被问到线段树,已经这么卷了吗?
面试被问到线段树,已经这么卷了吗?
150 0
面试被问到线段树,已经这么卷了吗?
|
存储 自然语言处理 前端开发
【牛客刷题】大厂真题 | 前端面试篇(一)
【牛客刷题】大厂真题 | 前端面试篇(一)
196 0
|
存储 JavaScript 算法
【程序员刷题必备 | 《剑指offer》】(三)
【程序员刷题必备 | 《剑指offer》】(三)
134 0