clickhouse在实时大屏应用的一些思考

最近我们通过实时数仓+clickhouse的方式把我们的实时大屏进行了重构,在重构的过程中我们参考了网上很多的例子,基本上大体的思路就是flink做宽表,实时使用clickhouse进行数据存储,同时批处理写入到hive。

使用

在这里插入图片描述
基本的设计架构就是这样,

  • 通过flink把消息报进行分层,主要分为两到三层,dw层主要做维表的join和冗余。业务线dw做kafka业务的打散,分业务管理以及一些指标的微聚合。
  • 流批写入到clickhouse和hive中,并且同步hive到clickhouse进行数据补偿。
  • 对所有clickhouse和hive中的表进行事中的数据质量保证,在出现异常数据时候提前感知和补偿。

经验

一致性保证

主要包括flink端到端的一致性保证和流批存储的一致性保证。

  • flink端到端的一致性保证主要依赖flink自身的checkpoint机制,以及与高版本kafka事务性提交实现的exactly-once来实现。具体的实现原理可以参考我另外一篇文章,不过一般的场景下使用exactly-once代价太大,需要考虑kafka的版本和对flink的的压力。如果需要些到其他存储比如clickhouse还需要做两阶段提交。

  • 对于clickhouse而言,并没有严谨的事务性的保证。所以flink写hive并没有一致性保证,最好的解决方式flink在遇到失败的情况下进行重试,并且clickhouse的引擎设置为ReplacingMergeTree,即使有重复写,也可以保证最终一致性。

  • 如果是因为其他因素(异常数据)导致的数据缺失问题,并且无法解决,就需要通过离线hive去补偿clickhouse的数据,一般而言,flink批写入到hive需要高版本的flink的支持,对于事务性保证方面,了解不太深,我们使用的方式是通过重写InputFormat支持kafka数据写入到hive临时表中。由于记录了kafka的offset,即使在极端的情况下hive写成功,但是offset没有更新的情况下,也可以通过手工的方式去更新offset。保证最终一致性。其稳定性要比flink写clickhouse高的多。

  • 补偿的方式一般是通过数据同步来做,先删除对应的clickhouse的分区,然后再插入到对应的分区数据, 为了减少clickhouse数据缺失对线上的影响,一般需要把分区的粒度缩小。并且前端设置缓存。

遇到的一些问题

主要在于维表Join和消息去重。维表有很多不同的类型,kv, hbase, rpc服务,以及hive表等。对于rpc, hive来讲一般都是做维度表读的。kv,hbase的场景大部分需要读写,比如判断新老用户的情况,一般都需要保存value值为记录的操作时间,以解决在重刷数据场景下,不至于误判,不过对于消息乱序场景一般是解决不了的,需要上报,然后手工修复。

消息去重,分为消息按照唯一键去重,和消息整体作为唯一键去重。一般的场景下把唯一键直接存储到布隆过滤器或者set中。或者唯一键进行多次hash之后存储到布隆过滤器中。在使用flink之前,一般存储到redis,或者分片内存中,使用flink之后直接用valueState保存即可。

稳定性保证

影响稳定性的因素有很多,机器故障,磁盘损坏,并发度过高,慢sql等。

  • 对于机器故障,磁盘损坏等问题,基本上可以通过clickhouse的多副本搞定,不过会丢失部分正在在的数据,这些可以通过补偿的方式去追回,对查询而言并没有太大的影响。
  • 如果出现雪崩问题导致的服务挂掉,而且重启时间过长,对于线上应用而言,这个是不能接受的,最好的方案是有backup。对线上应用有单独的集群管理或者服务双跑的机制去实现。出现问题及时切换到backup服务上去。
  • 并发度过高 导致的稳定性问题,一般只能限流,并且及时监控机器的cpu,内存等指标。
  • 慢sql的问题,一般是通过物化视图来加速。

并发度

clickhouse在并发度上确实不是自己的强项,这个也是mpp架构的通病,基于并发度的优化上需要从几方面入手:

  • 前端需要做好并发度的控制,本地或者分布式缓存,以及熔断的处理。
  • 后端clickhouse
    • 读写上,读使用分布式表,写用本地表即可,可以大大降低zk的压力。
    • 创建表上,针对高/低基数的字段采用不同的类型和压缩方式,减少存储压力和提高读取速度。固定过滤的低基数字段加到分区中去。充分利用物化视图的加速功能,可以降低机器IO, 间接提高单机并发度。
    • 存储上,ttl尽量设置短一点,如果确实需要历史数据,再通过数据同步进行回刷,冷热分离的数据,可以提高查询的效率。

一些想法

  • 关于宽表模型上,在flink做宽表的时候,尤其是在大促的场景下,宽表的产出效率会很低,经常会出现kafka延迟比较严重的情况,其中的一些瓶颈点主要在维表的join上,虽然做了异步的查询操作,但是在流量很大的场景下,还是会很慢,所以针对一些实时比较严格的场景下,flink会阉割掉一些耗时且不重要的的操作,重新生成新的kafka topic。
  • clickhouse最大的问题还是join的性能不是太好,对于数仓的场景来说,在flink里面做宽表的代价还是太大,不过doris 做了一些优化,分库分桶表,可以大大的提升join的性能。
  • 对于流批一体,目flink高版本是支持的,对于流量日志来说,基本没有太大问题,但是对于binlog日志,如果没有做特殊的处理,如何在底层实现upsert操作其实也是挺麻烦的,虽然clickhouse可以基于版本GraphiteMergeTree引擎保存最后的更新版本,但是对于批的场景来说,需要对写入到hive的表重新进行版本折叠生成新的表才能和clickhouse保持对齐。其实是多走了一步,听说数据湖可以解决这些问题,后面可以看一下。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值