<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Kudu on Memory</title>
    <link>https://blog.yandaojiang.com/tags/kudu/</link>
    <description>Recent content in Kudu on Memory</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Wed, 23 Oct 2024 20:17:08 +0800</lastBuildDate><atom:link href="https://blog.yandaojiang.com/tags/kudu/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>[笔记] Kudu 存储引擎 | Kudu 文件系统</title>
      <link>https://blog.yandaojiang.com/posts/tech/data-intensive/kudu-fs/</link>
      <pubDate>Wed, 23 Oct 2024 20:17:08 +0800</pubDate>
      
      <guid>https://blog.yandaojiang.com/posts/tech/data-intensive/kudu-fs/</guid>
      <description>&lt;h2 id=&#34;block-抽象接口&#34;&gt;Block 抽象接口&lt;/h2&gt;
&lt;p&gt;操作系统把磁盘抽象成文件，Kudu 则在文件之上再加了一层抽象——&lt;strong&gt;Block&lt;/strong&gt;。在 Kudu 中，一列数据、一个 BloomFilter、一份主键索引，最终都变成一个或多个 Block 写入磁盘。Block 是 Kudu 存储引擎与本地文件系统之间的分界线：上层组件只需面对 Block 接口的 &lt;code&gt;Append&lt;/code&gt; / &lt;code&gt;Read&lt;/code&gt;，不必关心底层是一个独立文件（FileBlockManager）还是日志容器中的一段字节区间（LogBlockManager）。&lt;/p&gt;
&lt;p&gt;这种隔离方式与 Unix 的设备抽象思路一致——Unix 内核用 &lt;code&gt;struct file&lt;/code&gt; 加上 &lt;code&gt;read&lt;/code&gt;/&lt;code&gt;write&lt;/code&gt; 函数指针屏蔽底层设备差异；Kudu 用 &lt;code&gt;Block&lt;/code&gt; 基类加上虚函数屏蔽底层文件系统的组织差异。&lt;/p&gt;
&lt;h3 id=&#34;blockidblock-的身份标识&#34;&gt;BlockId：Block 的身份标识&lt;/h3&gt;
&lt;p&gt;每个 Block 都有一个全局唯一的身份标识 &lt;code&gt;BlockId&lt;/code&gt;（&lt;code&gt;src/kudu/fs/block_id.h&lt;/code&gt;），本质上是一个 64 位无符号整数：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;BlockId&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;private&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;uint64_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;id_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;BlockId&lt;/code&gt; 可以序列化到 protobuf（&lt;code&gt;CopyToPB&lt;/code&gt; / &lt;code&gt;FromPB&lt;/code&gt;），也可以打印成 16 位十六进制字符串供调试。它是不透明的——上层代码不应假设 ID 的分配规则或数值含义，只需把它当作一把钥匙，用来在 BlockManager 中取回对应的数据。&lt;/p&gt;
&lt;h3 id=&#34;block-基类&#34;&gt;Block 基类&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Block&lt;/code&gt; 是所有 Block 的基类，接口极为简洁——只有一个方法：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Block&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;virtual&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;~&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Block&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;virtual&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;BlockId&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;id()&lt;/code&gt; 返回该 Block 的 &lt;code&gt;BlockId&lt;/code&gt;。这足以让上层代码通过 ID 引用任何 Block，而不必关心它是可读的还是可写的。Block 的两个子类——&lt;code&gt;WritableBlock&lt;/code&gt; 和 &lt;code&gt;ReadableBlock&lt;/code&gt;——分别定义了写路径和读路径的完整接口。&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>[笔记] Kudu 存储引擎 | memrowset 实现详解</title>
      <link>https://blog.yandaojiang.com/posts/tech/data-intensive/kudu-memrowset-internals/</link>
      <pubDate>Tue, 24 Sep 2024 20:17:08 +0800</pubDate>
      
      <guid>https://blog.yandaojiang.com/posts/tech/data-intensive/kudu-memrowset-internals/</guid>
      <description>&lt;h2 id=&#34;数据结构&#34;&gt;数据结构&lt;/h2&gt;
&lt;p&gt;MemRowSet 是 Kudu tablet 中用来暂存新写入数据的内存结构。它的底层存储是一棵并发 B-tree（CBTree），每个叶节点条目存放一个 key-value 对：key 是主键的编码形式（字典序 = 主键逻辑序），value 是一个 MRSRow。&lt;/p&gt;
&lt;p&gt;为了支持快照一致性，MemRowSet 从不原地更新已插入的行数据——所有后续变更都以 Mutation 节点的形式挂在行的 redo 链表上，相当于每行自带一条&amp;quot;redo log&amp;quot;。当 MemRowSet 被 flush 到磁盘时，所有内存——包括行数据、Mutation 节点、变长列数据——都从 Arena 中统一释放。&lt;/p&gt;
&lt;h3 id=&#34;mrsrow&#34;&gt;MRSRow&lt;/h3&gt;
&lt;p&gt;MRSRow 是行在 CBTree 中的存储表示。每个 MRSRow 占据一段连续内存，包含一个定长的 Header 和紧随其后的行数据。根据它的构造函数看出其内存布局如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;传入的 Slice s 指向的连续内存:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;|&amp;lt;---------- s.size() ----------&amp;gt;|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;|  Header (24B)  |   row_data   |
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   ↑                   ↑
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   header_              row_slice_ (remove_prefix 后)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Header 有三个字段：&lt;code&gt;insertion_timestamp&lt;/code&gt; 记录行的插入时间戳，供 MVCC 读取时判断可见性；&lt;code&gt;redo_head&lt;/code&gt; 和 &lt;code&gt;redo_tail&lt;/code&gt; 分别指向该行 Mutation 链表的头和尾。新插入的行 redo_head/redo_tail 均为 nullptr——它没有任何变更历史。每当一次 UPDATE 或 DELETE 到来，就会在链表尾部追加一个新的 Mutation 节点：&lt;/p&gt;</description>
    </item>
    
  </channel>
</rss>
