More than code

More Than Code
The efficiency of your iteration of reading, practicing and thinking decides your understanding of the world.
  1. 首页
  2. 未分类
  3. 正文

WiredTiger ColumnStore

2024年3月2日 415点热度 0人点赞 0条评论

WiredTiger作为MongoDB的默认存储引擎,以B+树的方式来组织数据,其中BTree页内支持3种格式的数据,分别是RowStore,Fixed-Length ColumnStore,以及Variable-Length ColumnStore。这篇文章介绍一下WiredTiger的ColumnStore。主要关注下WiredTiger ColumnStore对外提供的接口,Btree内部数据的组织方式,以及数据的读写方式。

MongoDB的使用方式,用来存储时序数据。https://www.mongodb.com/docs/manual/core/timeseries-collections/

接口

WiredTiger在创建表的时候,可以指定表的Schema,包括声明每一列的类型,名称,以及创建二级索引等。和列存相关的则是Column Group。

这里以ex_col_store.c中的代码为例:

session->create(session, "weather",
      "key_format=r,value_format=HHHHBBBB5S5S,columns=(id,hour,pressure,loc_lat,"
                      "loc_long,temp,humidity,"
                      "wind,feels_like_temp,day,country),colgroups=(day_time,temperature,"
                      "humidity_pressure,"
                      "wind,feels_like_temp,location)")

上面这个创建table的含义是,创建一个名字为weather的表,其中key的类型为r,代表record id,value的类型为HHHHBBBB5S5S,分别是后面这些column的具体类型。这里H是uint16_t,B是uint8_t,S是Null结尾的string。

并且以ColumnGroup的方式来组织这些列,这里有6个Column Group

然后声明这些column group所包含的列

session->create(session, "colgroup:weather:day_time", "columns=(hour,day)")

这里表示的就是,在weather这个表中,day_time这个column group包含的列为hour和day

除此之外,我们还可以创建二级索引,比如:

session->create(session, "index:weather:hour", "columns=(hour)")

这里就是创建了排序键为hour的二级索引,在搜索的时候,可以打开对应索引的cursor上来读取索引,从而加速某类查询。

在写入的时候,对于列存来说,不需要指定key,只指定value即可,value就是schema中定义的所有列,按照定义的顺序排布即可。

session->open_cursor(session, TABLE_NAME, NULL, "append", &cursor)
cursor->set_value(cursor, weather_data[i].hour, weather_data[i].pressure,
          weather_data[i].loc_lat, weather_data[i].loc_long, weather_data[i].temp,
          weather_data[i].humidity, weather_data[i].wind, weather_data[i].feels_like_temp,
          weather_data[i].day, weather_data[i].country);
cursor->insert(cursor)

在读取的时候,我们在open cursor的时候默认读出来的数据是表中所有的列。

session->open_cursor(session, TABLE_NAME, NULL, NULL, &cursor)
cursor->get_key(cursor, &recno)
cursor->get_value(cursor, &hour, &pressure, &loc_lat, &loc_long, &temp,
          &humidity, &wind, &feels_like_temp, &day, &country)

这时候没有利用列存的优势来做skip io,为了能够利用column group的优势,WiredTiger的cursor提供了Projection的能力

session->open_cursor(session, "table:weather(hour, day)", NULL, NULL, &cursor);
cursor->get_value(cursor, &hour, &day)

这样在读取的时候,WiredTiger就会选择上面创建的day_time这个column group,读取的时候也就不需要读其他的列了。

上面这些就是WiredTiger中和Schema相关的概念,即Column,Column Group,Index以及Projection

WiredTiger对于变长的ColumnStore,还支持通过RLE进行压缩,来减少空间占用。

数据组织

WiredTiger的每一个ColumnGroup都对应了一个文件,也就是每一个ColumnGroup都对应一个Btree,其Eviction/Reconcile的逻辑和之前讲的RowStore Btree没有区别。

同一个ColumnGroup的列会被编码成一个string,以key为record id,value为string的形式存储到Btree中

WiredTiger的定长的ColumnStore最多只支持8bit的value,存储方式是把所有数据都存储到bitmap中,比较特化,这篇文章就不细关注他了。

对于变长的ColumnStore来说,有一点比较特殊的是,存储的每一行数据的record id都是连续递增的。比如有一个record id为10的数据,还有一个record id为100的数据,那么11到99也一定会被存下来,不过如果这些数据是空的话,会被RLE压缩掉。

之所以这样存,是因为这样可以减少Btree Key的存储,只存Value。在ColumnStore的Page中,每个Page都只会存这个page所对应的start record id,即所有包含的record id中最小的那个,剩下的数据的record id则通过offset来计算得到。

Page内的组织结构如图所示:

  • 每一个不同的Value都会作为一个Slot出现

  • 对于重复多次的Value,会有一个RLE Entry来维护他的数量

  • 通过RLE Entry中的信息,以及Slot的offset,可以计算出某一个Slot所对应的是那些record id的value。

  • 在更新的时候,通过上面的方法计算出当前需要更新的record id属于那个Slot。每一个Slot都对应一个Skiplist来存储更新,找到skiplist中的版本链,并追加新版本。

  • Page上有个特殊的append Skiplist用来存储越界的更新。比如上述例子中,Btree page负责的范围是10到正无穷,但是因为目前最大的value的record id是27,所以对于大于27的元素的更新,会保存到最右边的skiplist中。

  • 部分情况下用户不指定record id,是WiredTiger负责分配,并将新的写入追加到Btree中。此时就会在最右边的skiplist中上锁分配record id,并插入数据。

  • 读取的时候会遍历每个Slot,先看对应的skiplist中是否有版本链,如果有则读版本链,没有则读slot上的value,也就是磁盘上的值。直到最后遍历完append skiplist,就会切换到下一个Page。

  • 对于RLE来说会有一些buffer的逻辑,来保证RLE的优化不会因为代码链路的开销而被削弱。这里WiredTiger做的就是如果发现当前Slot为RLE Cell,并且满足一定条件后(得保证RLE都是globally visible的,否则随便复用可能导致破坏快照),会保存这个value,如果下次定位到还是这个Cell,就会直接复用上一次的value,避免重新读盘。

  • 在Reconcile的时候,会根据可见性判断规则把需要保存到磁盘上的版本拿出来,然后做RLE编码,得到新的磁盘上的数据,然后再基于此来重建内存中的Page。
标签: 暂无
最后更新:2024年3月2日

sheep

think again

点赞
< 上一篇
下一篇 >

文章评论

取消回复

COPYRIGHT © 2021 heavensheep.xyz. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS