oceanbase每日合并

来源:互联网 发布:共产主义社会 知乎 编辑:程序博客网 时间:2024/05/19 17:27

oceanbase本质上是基于lsm-tree的方式实现每日合并的,简单来说就是将数据的更改hold内存中,当达到指定的阈值后,再批量写到磁盘与已有的数据做合并。

这个设计基于的假设是:写入远远大于读取,insert量大,update量小,这种方法可以优化写,但没有显著降低读,因为大部分最新的数据都在内存里面,读取速度会非常快。

1、基础架构
1.0之前的oceanbase架构,都是分为4个server,chunkserver(存储静态数据),updateserver(存储动态数据), mergeserver(sql处理,并发查询), rootserver(元数据管理),这个4歌server都可以分别部署在不同的机器上,写入时一个单点。

每日合并的过程实际上就是chunkserver(简写为cs)的老版本的静态数据与updateserver(简写为ups)的动态数据进行合并,生成新版本的静态数据,写到cs。

2、ups内存不足
ob所有的数据的更改都是要写到ups的,所以ups的内存一旦用完,则会阻塞应用的写入,这是不可以接受的。所以当ups内存到达一定程度后,就要触发每日合并,将动态数据与静态数据进行合并,合并完成后将相应的内存释放。

3、合并速度慢,内存无法及时释放
上面理论上解决了内存不足的问题,但是由于静态数据与动态数据合并,要涉及cs读写磁盘,以及cs与ups之间的网络交互,静态数据动态数据的合并逻辑速度比较慢,这就有可能导致合并没有完成,所以内存无法及时释放,内存用光,无法写入。
解决这个问题的方法是每个ups都配置了几块ssd组成的raid,当内存到达阈值时,先将动态数据dump到ssd,这样内存不足时,可以马上释放相应的内存。每日合并时,静态数据++ssd上的数据+内存中的数据进行合并。

4、数据dump到ssd后,读取相应数据,相应时间变长
dump到ssd的数据,实际上还是最近的比较热的数据,在每日合并完成之前,还会对它进行访问,访问频度仍然很高,读ssd的速度还是要小于读内存的数据,导致大量请求相应时间变长;

解决这个问题的一个方法是,dump完成后,并不马上释放内存,而是逐步切一部分流量到SSD上的dump数据,读取dump数据,要经过一层cache,这样就可以使cache先热起来,一段时间后再将动态数据内存释放。当然这个cache占用的内存要配置一个限制。

5、每日合并占用大量网络带宽的问题
上面的方法,解决的是ups的内存问题;然后,每日合并,涉及cs,ups之间的大量数据交互,主要是cs从ups拉取数据,而1.0之前的ups都是单点,大量的合并请求会导致ups网络占用过大;

ups一般使用万兆网卡,在一定程度上会缓解这个问题,但是不能根本上解决。

合并一般在业务低峰进行,也可以缓解这个问题,但是对于一些24小事都很忙的业务就无能为力了。
所以ups都会配置一个合并请求与正常情况带宽的百分比,对合并流量做一个限制。
但是这些方法对一些应用还是毫无办法,线上的一个OLAP的应用数据量特别大,每天写入也很多,如果做了限流,会导致每日合并非常慢,合并无法完成,又会导致dump ssd盘用完,无法及时释放内存。
针对这个应用,专门开发了一个小版本冻结,数据分发机制,将一个大版本拆成多个小版本,每个小版本都会将数据推送到各个cs,从而将每日合并的过程所用时间平摊到日常时间,而且合并时,cs从本地读,也会加快合并速度,一举两得。

6、每日合并对单个ups压力过大的问题

对于QPS要求很高的集群,即使对每日合并的流量做了限制,也会对前台请求有影响;因为每日合并实际上读取的是一个快照数据,没有一致性问题,所以每日合并的请求配置尽量读取被ups。

7、每日合并对集群的影响
ob一般有三个集群,如果三个集群都同时进行合并的话;会带来两个问题,一个是产生大量的集群网络流量,另一个一旦因为程序bug,导致合并失败、会很难验证回滚;所以提出了错峰合并的概念,当合并某个集群时,先把这个集群上的前台访问的流量切走,或是切走一部分,然后进行合并,这个集群合并完成后,再合并另一个集群,这样就最大可能减少了对前台应用的影响,也可以预防因为某个bug,导致所有集群挂掉的情况。

8、重写数据百分比的问题
每日合并,既然是动态数据与静态数据进行合并,那么久涉及一个更改数据百分比的问题。当然,我们无法做到仅仅读写更改的那行,因为这样需要大量的元数据,不可能做到。0.3 0.4这个判断更改的单位是256M(一个table的大小),只要这一个tablet中有一行数据发生了变化,就要重新读写整个tablet,这样对cs的读写压力会很大;但是如果将这个tablet的单位设置太小,又会导致文件太多,文件系统的管理开销很大;0.5使用了blocksstable,整个磁盘就是一个大文件,判断更改的单位是2M,这样就将更改比例优化了很多,增加了合并速度。

9.合并导致的大量小文件问题
既然是静态数据与动态数据合并,就要涉及一个tablet分裂的问题,在老版本的分裂算法,是只要大于256M,就要分裂,这样很可能就会产生一个大文件(256M),一个小文件(1M),一断时间后,会导致小tablet非常多,而rs管理元数据的开销非常大。

解决这个问题的方法是:当文件到达256M+128M时才分裂,这样就不会产生大量小文件。

10.表schema变化对每日合并的影响
数据不仅有数据的增删查改,还有表的结构的变化,比如增加一列,删除一列等;如果做了这种操作,这张表的数据都要重写,导致每日合并要重新读写所有数据,这会导致单次每日合并的时间过长。
解决这个问题的方法有两个,一个是只合并有数据更改的tablet,将schema变化持久化到本地,这样合并不会重写所有数据,但是影响读的速度。
另一种方法,将这次全量读写,分多次合并完,也就是最终采用的渐近合并方案。

11.单个cs合并速度的问题
上面都是整体上的一些问题,优化单个cs同样重要。以前,线上经常出现,只有几个盘在读写,其它盘空闲的情况,导致总体合并时间比较长;所以要对tablet的磁盘均衡算法做一些设计,综合考虑table_id,range,tablet数据,tablet大小等因素,这里不做细讲,其实这个与tablet在cs间的分布的优化原理是一样的。

12.合并失败的问题上面说的都是理想情况下的问题,但是也会遇到一些比如硬件错误,网络阻塞,程序bug导致的合并单个tablet失败的问题,这样有可能导致某个cs永远无法合并完成;所以当出现重试多次还失败的情况,就会查询rs,其它cs是否已经有合并完成的副本,直接迁移过来就可以;当然迁移,一旦与渐近合并,默认值等功能结合在一起,会特别复杂,实际上在测试阶段也出现了很多问题,特别是schema这一块,这也导致了1.0的静态数据schema管理的重构。13.合并对cache的影响合并一般涉及的是一次性的读写,所以不允许他读写cache。14.合并中过期数据删除的问题一些应用的过期数据,为了性能的考虑,是在合并过程中顺便删除的;但是对于过期条件的判断,会非常耗性能,特别是时间类型的转换,开销特别大,针对这个问题,也做了很多优化,这里不详解15.合并中对行迭代的要求合并一般是整行的读取,而正常请求一般是读取几列,所以针对合并,不需要进行一些类型列索引的迭代逻辑,优化单行的迭代速度16.合并中使用AIO合并一般是2M块的读写,在AIO层也做了相应的优化
0 0
原创粉丝点击