Golang中如何压缩内存缓存?

Golang中如何压缩内存缓存? 你好,我有一份文本文件中的数据,我想将这些数据缓存在内存中。使用这个库是可以的。

GitHub

allegro/bigcache

头像

allegro/bigcache

用 Go 编写的高效缓存,适用于千兆字节级别的数据。 - allegro/bigcache

这个过程会消耗大量内存。我的文本文件是 1.5GB,在内存中占用情况是:Linux 下 8GB,Windows 下 7GB。我该如何压缩这些数据或减少内存消耗?


更多关于Golang中如何压缩内存缓存?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

为什么需要将其存储在内存中?

更多关于Golang中如何压缩内存缓存?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


数据文件中有八千万行数据,我希望将这些数据存储在内存中,而不是存储在数据库里(出于性能、速度,最重要的是成本的考虑)。

我会将文件存储在磁盘上,但为了获得更好的性能,会使用固态硬盘。

在Golang中压缩内存缓存可以通过多种方式实现。对于bigcache这类缓存库,你可以考虑以下方案:

1. 使用压缩包装器

在存储数据前进行压缩,读取时解压:

import (
    "bytes"
    "compress/gzip"
    "github.com/allegro/bigcache"
)

type CompressedCache struct {
    cache *bigcache.BigCache
}

func NewCompressedCache() (*CompressedCache, error) {
    config := bigcache.DefaultConfig(10 * time.Minute)
    cache, err := bigcache.NewBigCache(config)
    if err != nil {
        return nil, err
    }
    return &CompressedCache{cache: cache}, nil
}

func (c *CompressedCache) Set(key string, data []byte) error {
    compressed, err := compressData(data)
    if err != nil {
        return err
    }
    return c.cache.Set(key, compressed)
}

func (c *CompressedCache) Get(key string) ([]byte, error) {
    compressed, err := c.cache.Get(key)
    if err != nil {
        return nil, err
    }
    return decompressData(compressed)
}

func compressData(data []byte) ([]byte, error) {
    var buf bytes.Buffer
    gz := gzip.NewWriter(&buf)
    if _, err := gz.Write(data); err != nil {
        return nil, err
    }
    if err := gz.Close(); err != nil {
        return nil, err
    }
    return buf.Bytes(), nil
}

func decompressData(data []byte) ([]byte, error) {
    buf := bytes.NewBuffer(data)
    gz, err := gzip.NewReader(buf)
    if err != nil {
        return nil, err
    }
    defer gz.Close()
    
    var result bytes.Buffer
    if _, err := result.ReadFrom(gz); err != nil {
        return nil, err
    }
    return result.Bytes(), nil
}

2. 使用更高效的序列化格式

考虑使用二进制格式而非文本:

import (
    "encoding/gob"
    "bytes"
)

// 使用gob序列化,通常比JSON/文本更紧凑
func serializeData(data YourStruct) ([]byte, error) {
    var buf bytes.Buffer
    encoder := gob.NewEncoder(&buf)
    if err := encoder.Encode(data); err != nil {
        return nil, err
    }
    return buf.Bytes(), nil
}

func deserializeData(data []byte, result *YourStruct) error {
    buf := bytes.NewBuffer(data)
    decoder := gob.NewDecoder(buf)
    return decoder.Decode(result)
}

3. 配置bigcache优化内存

调整bigcache配置减少内存开销:

import (
    "time"
    "github.com/allegro/bigcache"
)

config := bigcache.Config{
    Shards:             1024,           // 增加分片数减少锁竞争
    LifeWindow:         10 * time.Minute,
    CleanWindow:        5 * time.Minute,
    MaxEntriesInWindow: 1000 * 10 * 60,
    MaxEntrySize:       500,            // 限制单个条目大小
    Verbose:            true,
    HardMaxCacheSize:   4096,           // 设置最大缓存大小(MB)
    OnRemove:           nil,
    OnRemoveWithReason: nil,
}

cache, err := bigcache.NewBigCache(config)

4. 使用专用压缩缓存库

考虑使用支持透明压缩的缓存库:

import "github.com/coocood/freecache"

// freecache支持自动内存管理
cacheSize := 100 * 1024 * 1024 // 100MB
cache := freecache.NewCache(cacheSize)

// 存储时使用压缩
compressed := snappy.Encode(nil, data)
cache.Set([]byte(key), compressed, 0)

// 读取时解压
cached, err := cache.Get([]byte(key))
if err == nil {
    data, err = snappy.Decode(nil, cached)
}

5. 分块处理大文件

对于1.5GB的文本文件,分块加载和处理:

func processFileInChunks(filename string, chunkSize int) error {
    file, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer file.Close()
    
    scanner := bufio.NewScanner(file)
    buffer := make([]byte, 0, chunkSize)
    
    chunkNum := 0
    for scanner.Scan() {
        line := scanner.Bytes()
        if len(buffer)+len(line) > chunkSize {
            // 处理当前块
            processChunk(chunkNum, buffer)
            chunkNum++
            buffer = buffer[:0]
        }
        buffer = append(buffer, line...)
        buffer = append(buffer, '\n')
    }
    
    if len(buffer) > 0 {
        processChunk(chunkNum, buffer)
    }
    
    return scanner.Err()
}

func processChunk(chunkNum int, data []byte) {
    compressed, _ := compressData(data)
    key := fmt.Sprintf("chunk_%d", chunkNum)
    cache.Set(key, compressed)
}

这些方法可以显著减少内存使用。对于1.5GB文本文件,压缩后通常可以降至原始大小的20-40%,具体取决于文本的重复性和压缩算法选择。

回到顶部