memcached的内存分配器是如何工作的?为什么不适用malloc/free!?为何要使用slabs?思维导图 代码示例(java 架构)

Memcached 内存分配器工作原理

Memcached 使用了一种称为 Slab Allocator 的内存分配机制,它与传统的 malloc/free 不同。以下是关于为什么 Memcached 选择使用 Slab Allocator 而不是标准的内存分配方式的原因,以及其工作原理的关键点:

1. Slab Allocator 的优点
  • 减少碎片化:Slab Allocator 通过预先分配固定大小的内存块(称为 slabs),并将相同大小的对象存储在一起,从而减少了内存碎片。
  • 提高效率:由于对象具有相同的大小,因此分配和释放内存的操作非常快速,不需要复杂的计算来确定合适的位置。
  • 简化管理:每个 slab class 只处理特定大小范围内的对象,这使得内存管理和垃圾回收更加简单。
2. Slab Allocator 工作流程
  • 初始化阶段:启动时,Memcached 根据配置的最大内存限制划分出多个 slab classes,每个 slab class 对应一系列具有相似大小的对象。
  • 分配过程:当有新的对象需要存储时,Memcached 会根据该对象的实际大小选择最合适的 slab class,并从中取出一个空闲 chunk 来存放数据。
  • 释放过程:当某个对象被删除后,其占用的 chunk 返回到对应的 slab class 中,等待下一次分配。
  • 动态调整:如果当前所有的 slab classes 都不足以满足新对象的需求,则可以创建新的 slab classes 或者扩展已有的 ones。
3. 为什么不适用 malloc/free
  • 性能瓶颈:在高并发环境下,频繁调用 mallocfree 会导致显著的性能开销,尤其是在大量小对象的情况下。
  • 内存碎片问题:传统内存分配方式容易产生外部碎片(即存在许多无法使用的零碎空间),而 Slab Allocator 则有效地避免了这个问题。
  • 复杂性增加:实现高效的 malloc/free 需要考虑很多细节,如线程安全、锁竞争等,相比之下,Slab Allocator 的设计更为简洁且易于维护。
4. 为何要使用 slabs
  • 优化缓存命中率:通过将相似大小的对象集中存储,Memcached 可以更好地利用 CPU 缓存行,进而提升读取速度。
  • 便于预分配:可以在系统初始化时就准备好一定数量的 slabs,避免运行期间频繁申请和释放大块内存。
  • 支持多租户场景:不同应用或服务可以根据自身需求选择不同的 slab classes,确保资源隔离和公平性。

思维导图 (简化的文本表示)

Memcached Slab Allocator
├── Slab Allocator 的优点
│   ├── 减少碎片化
│   ├── 提高效率
│   └── 简化管理
├── Slab Allocator 工作流程
│   ├── 初始化阶段
│   ├── 分配过程
│   ├── 释放过程
│   └── 动态调整
├── 为什么不适用 malloc/free
│   ├── 性能瓶颈
│   ├── 内存碎片问题
│   └── 复杂性增加
└── 为何要使用 slabs
    ├── 优化缓存命中率
    ├── 便于预分配
    └── 支持多租户场景

Java代码示例

虽然我们不能直接在Java中模拟Memcached内部的Slab Allocator,但可以通过Java客户端库来展示如何与启用了Slab Allocator的Memcached实例进行交互。此示例假设你已经在本地运行了一个Memcached实例,并且监听了默认端口11211。

首先添加依赖(如果你使用的是Maven项目):

<dependency>
    <groupId>cloud.xmemcachedgroupId>
    <artifactId>xmemcachedartifactId>
    <version>2.0.3version>
dependency>

然后是Java代码示例:

import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import java.util.concurrent.TimeoutException;
import java.io.IOException;

public class MemcachedSlabAllocatorExample {
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        // 创建Memcached客户端连接到本地运行的服务
        String server = "localhost:11211";

        try {
            // 构建Memcached客户端
            MemcachedClientBuilder builder = new XMemcachedClientBuilder(server);
            MemcachedClient memcachedClient = builder.build();

            // 测试设置一组键值对,这些值会有不同的大小
            String[] keys = {"small_key", "medium_key", "large_key"};
            String[] values = {"small", "this is a medium sized value", generateLargeString(1024 * 64)}; // 64KB左右的字符串

            for (int i = 0; i < keys.length; i++) {
                int ttlInSeconds = 3600; // TTL in seconds
                memcachedClient.set(keys[i], ttlInSeconds, values[i]);
                System.out.println("Stored key: " + keys[i] + " with value size: " + values[i].length());
            }

            // 获取之前设置的值
            for (String key : keys) {
                Object retrievedValue = memcachedClient.get(key);
                System.out.println("Retrieved value for key " + key + ": " + (retrievedValue != null ? retrievedValue.toString().length() : "null"));
            }

            // 关闭客户端连接
            memcachedClient.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 辅助方法:生成指定长度的字符串
    private static String generateLargeString(int length) {
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            sb.append('a'); // 使用'a'作为填充字符
        }
        return sb.toString();
    }
}

在这段代码中,我们向Memcached服务器存储了三个不同大小的值,它们会被自动分配到适当的slab classes中。通过这种方式,你可以看到即使在同一应用程序中也可以有效地利用Memcached的Slab Allocator特性,而不必担心内存碎片的问题。

此外,为了更深入地理解Slab Allocator的工作原理,还可以参考Memcached的日志输出或者使用工具(如stats slabs命令)来查看具体的slab统计信息,了解各个slab class的使用情况。例如,在命令行中执行以下命令可以获取有关slab的信息:

echo "stats slabs" | nc localhost 11211

这将返回一系列统计数据,包括每个slab class的数量、每个chunk的大小、已使用的chunk数目等,有助于进一步优化Memcached的配置和性能。

你可能感兴趣的:(memcached,java,架构)