美文网首页
朴实无华的后端缓存, 单实例百万+并发, 解决缓存击穿丶缓存雪崩

朴实无华的后端缓存, 单实例百万+并发, 解决缓存击穿丶缓存雪崩

作者: zlyuan | 来源:发表于2020-02-13 11:56 被阅读0次

    https://github.com/zlyuancn/zbec


    获得

    go get -u github.com/zlyuancn/zbec

    解决缓存击穿

    当有多个进程同时获取一个key时, 只有一个进程会真的去缓存db读取或从db加载并返回结果, 其他的进程会等待该进程结束直接收到结果. 实现方式请转到 github.com/zlyuancn/zsingleflight

    解决缓存雪崩

    • 设置随机的TTL, 可以有效减小缓存雪崩的风险

    解决缓存穿透

    • 可以通过 zbec.WithCacheNoEntry 开启缓存空条目(默认开启), db加载函数在没有数据时应该返回 zbec.ErrNoEntry 错误
    • 可以通过 zbec.WithLocalCache 设置本地缓存, 本地缓存一定会缓存空条目
    • 在用户请求key的时候判断它是否可能不存在, 比如判断id长度不等于32(uuid去掉横杠的长度)直接返回错误

    db数据库

    • 支持任何数据库, 本模块不关心用户如何加载数据

    缓存数据库

    • [任何实现 cachedb.ICacheDB 的结构]
    • [redis]
    • [go-cache]

    编解码器

    开发过程中不需要考虑每个对象的编解码, 可以在初始化时为缓存数据库时选择一个编解码器, 默认是MsgPack

    • [任何实现 codec.ICodec 的结构]
    • Byte
    • JSON
    • JsonIterator
    • MsgPack
    • ProtoBuffer
    • Thrift

    以下是性能测试数据

    未模拟用户请求和db加载, 直接测试本模块本身的性能

    # 性能测试命令
    go test -v -bench "^Benchmark_.+$" -run ^$ -cpu 20,50,100,1000,10000 .
    # 下面这个是用户没有go环境但是有docker的情况下
    docker run --rm -v ${PWD}/../..:/src/app -v /src/gopath:/src/gopath -v /src/gocache:/src/gocache -w /src/app/zbec/test zlyuan/golang:1.13 go test -v -bench "^Benchmark_.+$" -run ^$ -cpu 20,50,100,1000,10000 .
    

    1000 个key, 每个key 512字节随机数据, 请求key顺序随机

    # go-cache
    Benchmark_GoCache1e3-20                          1885130           730 ns/op
    Benchmark_GoCache1e3-50                          1568814           777 ns/op
    Benchmark_GoCache1e3-100                         2048479           744 ns/op
    Benchmark_GoCache1e3-1000                        2303812           642 ns/op
    Benchmark_GoCache1e3-10000                       1705032           716 ns/op
    
    # redis
    Benchmark_Redis1e3-20                              88453         12643 ns/op
    Benchmark_Redis1e3-50                             229730          4961 ns/op
    Benchmark_Redis1e3-100                            459921          2482 ns/op
    Benchmark_Redis1e3-1000                          2120120           555 ns/op
    Benchmark_Redis1e3-10000                         1548505           722 ns/op
    
    # redis and LocalCache
    Benchmark_RedisAndLocalCache1e3-20               1948473           704 ns/op
    Benchmark_RedisAndLocalCache1e3-50               1781548           697 ns/op
    Benchmark_RedisAndLocalCache1e3-100              1971524           697 ns/op
    Benchmark_RedisAndLocalCache1e3-1000             2467428           567 ns/op
    Benchmark_RedisAndLocalCache1e3-10000            2359215           539 ns/op
    

    10 000 个key, 每个key 512字节随机数据, 请求key顺序随机

    <details>
    <summary>点击展开</summary>
    <pre><code>

    go-cache

    Benchmark_GoCache1e4-20 2310266 495 ns/op
    Benchmark_GoCache1e4-50 1808149 734 ns/op
    Benchmark_GoCache1e4-100 1820456 646 ns/op
    Benchmark_GoCache1e4-1000 2386491 639 ns/op
    Benchmark_GoCache1e4-10000 2307810 490 ns/op

    redis

    Benchmark_Redis1e4-20 102188 11582 ns/op
    Benchmark_Redis1e4-50 229939 4651 ns/op
    Benchmark_Redis1e4-100 518737 2286 ns/op
    Benchmark_Redis1e4-1000 2165594 576 ns/op
    Benchmark_Redis1e4-10000 1486389 753 ns/op

    redis and LocalCache

    Benchmark_RedisAndLocalCache1e4-20 141720 8330 ns/op
    Benchmark_RedisAndLocalCache1e4-50 386697 2975 ns/op
    Benchmark_RedisAndLocalCache1e4-100 595728 1722 ns/op
    Benchmark_RedisAndLocalCache1e4-1000 2459406 516 ns/op
    Benchmark_RedisAndLocalCache1e4-10000 2012082 606 ns/op
    </code></pre>
    </details>

    100 000 个key, 每个key 512字节随机数据, 请求key顺序随机

    <details>
    <summary>点击展开</summary>
    <pre><code>

    go-cache

    Benchmark_GoCache1e5-20 1325640 873 ns/op
    Benchmark_GoCache1e5-50 2432680 625 ns/op
    Benchmark_GoCache1e5-100 2065634 737 ns/op
    Benchmark_GoCache1e5-1000 2319595 657 ns/op
    Benchmark_GoCache1e5-10000 2056987 602 ns/op

    redis

    Benchmark_Redis1e5-20 96511 12034 ns/op
    Benchmark_Redis1e5-50 220322 5035 ns/op
    Benchmark_Redis1e5-100 461415 2308 ns/op
    Benchmark_Redis1e5-1000 2163451 615 ns/op
    Benchmark_Redis1e5-10000 1538402 710 ns/op

    redis and LocalCache

    Benchmark_RedisAndLocalCache1e5-20 99225 11235 ns/op
    Benchmark_RedisAndLocalCache1e5-50 248864 4999 ns/op
    Benchmark_RedisAndLocalCache1e5-100 427542 2480 ns/op
    Benchmark_RedisAndLocalCache1e5-1000 2517938 566 ns/op
    Benchmark_RedisAndLocalCache1e5-10000 1857760 562 ns/op
    </code></pre>
    </details>

    开发注意事项

    • 获取值时保存结果的变量必须是一个指针
    • 从数据库加载条目为空时应该返回zbec.ErrNoEntry错误
    • 如果你可能对结果进行修改, 为了不产生并发写错误, 你应该设置 zbec.WithDeepcopyResult(true) , 代价是性能有所降低

    示例代码

    [传送门]

    相关文章

      网友评论

          本文标题:朴实无华的后端缓存, 单实例百万+并发, 解决缓存击穿丶缓存雪崩

          本文链接:https://www.haomeiwen.com/subject/kfpkfhtx.html