37DATA

关于直写Hologres的一些总结

如果您的项目是与HOLO直接相关(绕开Mysql等上游组件直接对HOLO进行写入\更新),那么本文可能可以给到您一些帮助,避开一些曾经走过的弯路。

关于思维的转换

  1. 单SQL处理写改造成攒批写。这个主要是对Holo的写入性能进行优化,提高单一时间写入数据量性能,降低对HOLO写实例的性能消耗。

    (要有一个意识:Holo写实例的资源非常宝贵,只读实例可以有3个,但目前写实例资源仅能有一个)。

Image

于是,我们需要由从前Mysql 的单条数据insert into,调整成攒批copy to.

Image

并且由此也会带来一些细节问题 :

在MYSQL上,我们对SQL INSERT、UPDATE时序性,可能因为迁移到HOLO 攒批的改造,而对结果数据有所影响。

即Update发生时,可能insert数据尚在攒批落盘中。处理不当可能会引起数据更新失败。

2.单更新语句也是跟INSERT INTO类似,需要改造成批量更新或基于FixedPlan的全pk/部分pk/冲突更新,否则你会发现Update语句的性能比MYSQL还要糟糕(Holo:400ms vs Mysql:10ms)。


而查询耗时增高,从结果看,可能还只是影响业务功能模块的体验,有的业务可能觉得400ms单语句的更新能接受。


但实际上该状况反映出来的是SQL语句不够高效,浪费了宝贵的写实例的内存或CPU或IO等资源,从而可能拖慢整个Holo写实例,这个才是最为致命,迫切需要解决的。


至于最终是采用中间表连表更新方案,还是调整PrimaryKey达到更新语句的全PrimaryKey命中、部分PrimaryKey命中的FixedPlan冲突更新方案,这个则需要根据业务场景定制,

关于写入

原则:Holo比Mysql更加严谨


解读:Mysql时代,开发可能只需要关注写入的数据有否转义,防注入等即可。以下若干情况Mysql多少会根据配置项自行处理,或截取,或自动转义,或自动转换类型。
但是在Holo的写入上,抱歉这些是需要开发前置处理干净,否则会触发致命错误。

  • 异常ASCII字符 
    Image

  • 写入字段超出预设字段长度

  • 往int类型写入String数据等写入数据与预设类型不一致

  •  '单引号的处理,需要用双单引号进行转义

Image

Image

Image

Image

Image

Image

关于更新

Mysql时代,有些更新场景会从DB load 数据到服务器本地,在内存进行计算。等计算结束后再回更至Mysql。 

Holo中,沿用此方案只要更新语句能命中FixedPlan,原则上没有太大问题,但并不是方案的最优解:一、Load明细即全量列,对列存的Holo会造成一定的内存压力,同时这样的计算方式也徒增了网络开销、受服务器环境等变量影响。


以前在Mysql时代因为性能的取舍,这个方案比较合适,但在Holo的结构中可以考虑以下方案:

  1. 建议:

    1. 如果对实时性要求较高,可直接在holo上进行连表计算更新(但需要顾及写实例资源、线上锁表,oom等情况,同时此方案对于业务逻辑过于复杂的情况也不太适用。)

    2. 如果对实时性要求不搞,可转至MC上进行连表计算更新

关于写实例性能与锁表

holo写实例性能,统一组件的优势不用赘述,但凡是总有两面,统一组件所带来的缺点会在使用过程中慢慢凸显,而以下这个算是其中一个

跟MysqlMaster一样,我们需要密切关注写入性能,一旦写实例的holo出现问题,会对业务线的其他业务数据造成广泛的影响。因为统计的写入语句写的不好,而影响了广告的事件模块,这个不是我们能接受的。

解法:

  • 密切关注写实例的运行状态,提高敏感度和监控级别(与Mysql Master一致)

  • 尽管目前我们已经采用了一写两读的读写隔离,来区分写实例、统计读实例、广告读实例
    但仍可以进阶试用Holo写写隔离,通过业务拆分若干资源组,各自负责各自资源组的消耗占用(各资源组均有写/读资源和权限)

当你业务深度使用Holo的直写数据的时候,可能会发现,某些表的吞吐性能,跟整体实例的性能监控,不一定是一致的。
写实例的资源足够下,某些表还是产生了写入/更新的堆积,这个时候可能是遇到了锁表的情况了。

-- 查看所有在等的锁,持有的锁,及持有/等待的进程等信息select * from pg_locks where granted = 'f';

下图所示为:tj_sy_crontab里面对于user_activites_for_game的活跃表的计算程序(Base on Holo, insert into ua select from  login_logs),

会影响到SCF中对login_logs数据的攒批写入性能,严重可能会引起数据堆积。

Image

关于失败

Mysql:除了明显语法错误的状况,大部分正式上线的产品功能,比较少会出现mysql语句执行失败。
一个INSERT/UPDATE/DELETE语句,普遍认为在Mysql侧是会执行成功的。
(某些数据库引擎,在内存资源不足时会采用磁盘缓存的方式进行算子降级(Spill to Disk))

然而在Holo侧,为了保障查询的效率,默认所有算子都采用内存资源进行计算,因此会存在内存不足导致OOM的问题。


OOM的问题,会存在写实例、读实例中,换言之,它会影响查询、或者写入、更新。
再进一步说,在业务数据处理过程中,不能完全信任HOLO的execute/query是100%成功的。

因此,代码框架中,对于语句执行的容错、重试、业务幂等等设计必须比Mysql处理更加重视。

Image

总结

    • 攒批写、攒批更

    • 语句要走FixedPlan

    • 字段定义和内容要严谨

    • 优先考虑直接Holo/MC计算

    • 密切关注写实例性能

    • 完善SQL失败的容错和重试机制

实践过程中,我们小伙伴们还踩过了以下的坑,这里就不再一一赘述,有兴趣的小伙伴欢迎私下沟通分享:

    • timestamptz转date的官方BUG

    • Holo原生不支持改表结构,业务上确实要改的解决方案(新旧表停写重导rename)

    • 小范围数据连表更新100% OOM错误,但大范围数据更新却不会OOM(关闭Broadcast)

    • 1.3以下非法json字符串转json致命错误

    • Update/Insert性能低下(全PrimaryKey命中且需要开启)

    • 有Bitmap和无Bitmap的大表性能差异

关于Holo写/读的调优,要学习的东西还是非常多,2023年Holo小组会促进推动阿里云Holo支撑团队到现场进行更深入、更具实践意义的交流学习。

https://help.aliyun.com/document_detail/461881.html

https://help.aliyun.com/document_detail/183398.html