Skip to content

buffer 管理问题 #2

@dbgp

Description

@dbgp

设计说明

在数据库中用到 buffer 的地方很多(比如最常见的网络输入输出 buffer、redo log buffer),并且是高频使用,实现得不好也严重影响性能。lealone 直到今天才完美解决 buffer 管理的问题,前后用了4种方案:

  1. 最开始使用全局的 buffer pool,里面用一个支持多线程并发访问的队列实现,池里的 buffer 大小不是固定的,会先按需求的容量大小从队列里找到一个最适合的 buffer,用完后再放回池中。这个方案的缺点是多线程访问并不高效;另外 buffer 的大小不一样,有的 buffer 用不到,有的被拿去用了但是依然有空闲空间浪费了。

  2. 为了解决方案1的问题,每个调度线程使用自己的 buffer pool,这样就不需要做并发控制了,只有单个线程访问,队列可以用普通的链表来实现。这个方案虽然访问队列快了,但是依然有出队和入队的开销,并且 buffer 内存空间浪费的问题也没有解决。

  3. 不使用 buffer pool 了,给每条 tcp 连接分配两个专属 buffer,每个 buffer 默认是 4k,这样就没有访问队列的开销了,处理完一次请求后,两个 buffer 都能快速复位,所以也不浪费内存空间。这个方案的唯一缺点就是不能支持太多条 tcp 长连接,一旦数量多了依然很占用内存。

  4. 这是目前的终极方案,给每个调度线程各分配两个专属 buffer,不给每条 tcp 连接分配 buffer 了。调度线程负责的所有 tcp 连接都使用调度线程的 buffer,每条 tcp 连接的输入输出包按顺序存放到调度线程的 输入包 buffer 和 输出包 buffer 中,调度线程解析完这些输入包或把输出包写到 socket 后,只需要把 buffer 的 pos 和 limit 设置一下就能复用了。不但没有内存碎片,也没有方案1和方案2访问队列的开销,也不像方案3那样 tcp 连接多了浪费内存,真的就是完美的解决方案。

这里的理解还是针对旧方案。

新方案应该是真的11月4日的所有的tcp连接都共用调度器的全局buffer开始的一系列实现。这次的学习就从这里先开始吧。之前的思路依然可以借鉴——

  • lealone的启动过程,包含了server服务的启动
  • client端如何与server端建立连接
  • 连接创建之后如何传输数据

这三步完成,才可以看到buffer中网络传输中的使用场景。结果使用场景看buffer是如何管理的。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions