Tendis icon indicating copy to clipboard operation
Tendis copied to clipboard

配置了内存上限,压力测试后内存不释放

Open lqxhub opened this issue 4 years ago • 34 comments

在一台机械硬盘的机器上部署的tendisplus-2.4.2,单实例部署,进行压测测试。配置了内存上限, 但是内存没有被限制住,一路涨到了1.7G,而且长时间没有释放

应用场景,是因为redis 数据做实时落地不方便,想要用tendis替换redis,对延迟要求不是特别高,但是想限制内存使用。现在是在内网测试,线上会部署到云上,硬盘会使用高性能云盘。压力测试期间 只有一个client连接。

所以想请问一下 怎样限制内存使用,或者如何释放内存

配置文件

bind 0.0.0.0
port 22182
daemon on
cluster-enabled false
loglevel notice
logdir ./home/log
dumpdir ./home/dump
dir ./home/db
pidfile ./home/tendisplus.pid
slowlog ./home/log/slowlog

#线程
executorWorkPoolSize 2
executorthreadnum 4
netiothreadnum 2
keysDefaultLimit 1000000

rocks.blockcachemb 512
rocks.cache_index_and_filter_blocks 1
rocks.blockcache_strict_capacity_limit true

incrPushThreadnum 1
fullPushThreadnum 1
fullReceiveThreadnum 1

info 信息

# Memory
used_memory:-1
used_memory_human:-1
used_memory_rss:1847549952
used_memory_rss_human:1804248kB
used_memory_peak:-1
used_memory_peak_human:-1
total_system_memory:-1
total_system_memory_human:-1
used_memory_lua:-1
used_memory_vir:2609618944
used_memory_vir_human:2548456kB
used_memory_vir_peak_human:2548456kB
used_memory_rss_peak_human:1845952kB

# Dataset
rocksdb.kvstore-count:10
rocksdb.total-sst-files-size:252446362
rocksdb.binlogcf-sst-files-size:1405801669
rocksdb.live-sst-files-size:252446362
rocksdb.estimate-live-data-size:220959602
rocksdb.estimate-num-keys:5087613
rocksdb.total-memory:622448092
rocksdb.cur-size-all-mem-tables:86528432
rocksdb.estimate-table-readers-mem:0
rocksdb.blockcache.capacity:536870912
rocksdb.blockcache.usage:535919660
rocksdb.blockcache.pinnedusage:0
rocksdb.mem-table-flush-pending:0
rocksdb.estimate-pending-compaction-bytes:0
rocksdb.compaction-pending:0
rocksdb.number.iter.skip:541136
rocksdb.compaction-filter-count:3716847
rocksdb.compaction-kv-expired-count:0

lqxhub avatar Oct 25 '21 01:10 lqxhub

请问楼主,内存不释放这个问题,你后面怎么解决的?

xjj210130 avatar Nov 01 '21 10:11 xjj210130

请问楼主,内存不释放这个问题,你后面怎么解决的?

还没解决

lqxhub avatar Nov 01 '21 10:11 lqxhub

哎,腾讯的开发反馈太慢了。

xjj210130 avatar Nov 01 '21 10:11 xjj210130

Tendis 的内存占用 主要在 RocksDB 上, RocksDB 的内存 主要分为下面三大块:

  • Block cache
  • Indexes and bloom filters
  • Memtables

如果想减少内存占用, 就需要减少上面三快的内存开销:

  • 比如可以通过 减少 Block cache 的大小;
  • cache_index_and_filter_blocks 设置为 1, Indexes and bloom filters 就会保存到 Block cache 中, 内存占用 不会随着 数据量越来越大。
  • 减少 Memtables 的大小或者 个数;

  • 如何查看内存占用 ? 通过 jeprof 来生成调用关系图, 具体可以查看 哪个函数或者结构占用多少内存。 jeprof [on/off/dump]

目前从你给出的一些信息, 内存总共占用了 1.7GB, RocksDB 占用大概 600MB, 所以还有 1G 左右的内存开销 不清楚。 你可以参考 jeprof 的用法, 发一下 具体的内存占用大小。

jingjunLi avatar Nov 02 '21 02:11 jingjunLi

把一些数据缓存到内存,是能够提高效率,当不用的时候,内存是不是应该释放出来呢?

xjj210130 avatar Nov 02 '21 02:11 xjj210130

从系统开发的角度来看 确实应该。 比如 block cache 缓存一些 block, 当 block 对应的 SST 删除时, 这个 block 不会被使用, 就应该 被释放出来, RocksDB 也是这么实现的。 你的意思是现在 Tendis 存在 缓存的数据, 不在释放的问题, 或者说内存泄漏的问题 ? 能具体说下在哪里, 我看下

jingjunLi avatar Nov 02 '21 03:11 jingjunLi

嗯就是楼主说的问题,当压测完毕后,比如内存使用了15G,压测完毕后,如果没有继续调用的话,应该逐步释放内存。这个问题很好复现的,把master代码编译一把,随便压测一下,就可以看到这个现象。 不是内存泄漏。

xjj210130 avatar Nov 02 '21 03:11 xjj210130

今上午又压测了一遍,内存维持在1.6G 不释放

配置
#线程
executorWorkPoolSize 2
executorthreadnum 4
netiothreadnum 2

keysDefaultLimit 1000000

#
#kvstorecount 6

rocks.blockcachemb 512
rocks.cache_index_and_filter_blocks 0
rocks.blockcache_strict_capacity_limit true


incrPushThreadnum 1
fullPushThreadnum 1
fullReceiveThreadnum 1

---------------------------------------------

info命令

# Memory
used_memory:-1
used_memory_human:-1
used_memory_rss:1671127040
used_memory_rss_human:1631960kB
used_memory_peak:-1
used_memory_peak_human:-1
total_system_memory:-1
total_system_memory_human:-1
used_memory_lua:-1
used_memory_vir:3505102848
used_memory_vir_human:3422952kB
used_memory_vir_peak_human:3422952kB
used_memory_rss_peak_human:2063848kB

# Dataset
rocksdb.kvstore-count:10
rocksdb.total-sst-files-size:532370618
rocksdb.binlogcf-sst-files-size:327526731
rocksdb.live-sst-files-size:532370618
rocksdb.estimate-live-data-size:510262275
rocksdb.estimate-num-keys:12191343
rocksdb.total-memory:613946572
rocksdb.cur-size-all-mem-tables:75893376
rocksdb.estimate-table-readers-mem:1655692
rocksdb.blockcache.capacity:536870912
rocksdb.blockcache.usage:536397504
rocksdb.blockcache.pinnedusage:0
rocksdb.mem-table-flush-pending:0
rocksdb.estimate-pending-compaction-bytes:0
rocksdb.compaction-pending:0
rocksdb.number.iter.skip:3310586
rocksdb.compaction-filter-count:20479944
rocksdb.compaction-kv-expired-count:1789
jeprof top


Total: 1356.4 MB
   816.3  60.2%  60.2%    816.3  60.2% rocksdb::Arena::AllocateNewBlock
   520.1  38.3%  98.5%    520.1  38.3% rocksdb::BlockFetcher::PrepareBufferForBlockFromFile
     4.3   0.3%  98.8%      4.3   0.3% WritableFileWriter (inline)
     4.0   0.3%  99.1%      4.0   0.3% allocate (inline)
     4.0   0.3%  99.4%      4.5   0.3% rocksdb::LRUCacheShard::Insert
     2.1   0.2%  99.6%      2.1   0.2% rocksdb::CoreLocalArray::CoreLocalArray
     2.0   0.1%  99.7%    521.1  38.4% _ZN7rocksdb12_GLOBAL__N_117ReadBlockFromFileEPNS_22RandomAccessFileReaderEPNS_18FilePrefetchBufferERKNS_6FooterERKNS_11ReadOptionsERKNS_11BlockHandleEPSt10unique_ptrINS_5BlockESt14default_deleteISF_EERKNS_18ImmutableCFOptionsEbRKNS_5SliceERKNS_22PersistentCacheOptionsEmm.constprop.370
     1.0   0.1%  99.8%      1.0   0.1% operator new [] (inline)
     0.5   0.0%  99.9%      0.5   0.0% AllocateNewBuffer (inline)
     0.5   0.0%  99.9%      0.5   0.0% std::basic_filebuf::_M_allocate_internal_buffer

jeprof 导出的pdf文件 one.pdf

lqxhub avatar Nov 02 '21 05:11 lqxhub

从 jeprof 的 pdf 文件来看 内存占用还是在 RocksDB 内部, 其中 38.3% 是 block cache, 60.2% 是 Memtable。

之前对下面两个值误导, Tendis 内部有两个 column family, rocksdb.total-memory rocksdb.cur-size-all-mem-tables 都是 default column family 的占用, binlog column family 没有显示出来。 另外 1GB 的内存很可能是是 Memtable 没有 flush 导致的。 image

建议确认一下 max_write_buffer_number max_write_buffer_number_to_maintain write_buffer_size 这几个参数, 后面这里显示的问题会修复。

jingjunLi avatar Nov 02 '21 07:11 jingjunLi

@jingjunLi

建议确认一下 max_write_buffer_number max_write_buffer_number_to_maintain write_buffer_size 这几个参数, 后面这里显示的问题会修复。

这些参数都是默认值, 没有修改

lqxhub avatar Nov 02 '21 07:11 lqxhub

数据库内存永远应该释放、减少物理IO、

luxinle avatar Jul 22 '22 03:07 luxinle

数据库内存永远应该释放、减少物理IO、 物理IO太慢了、不用的概念不同、什么叫不用、 这部分数据页和块永远不用叫不用,下次再用就必须从内存里直接拿不要从磁盘拿、 从磁盘拿就慢、相当慢、非常慢、慢到想骂娘、慢到感觉tendis不行。 其实不是tendis不行、不行的是老想着释放内存、不行的是数据结构 有续集。 在tendis处理有续集是比较慢的。

@luxinle 你想说的意思是 '数据库内存应该永远 释放吧' 我想要的效果是我可以控制一个内存缓存的上限,比如最多只有1G的内存缓存,超过这个值后就应该使用淘汰算法,把老数据置换出去。而不是无限制的内存增长。至于不在内存中,在硬盘的数据,读取数据时的延迟,我是可以接收的

lqxhub avatar Jul 22 '22 03:07 lqxhub

这个内存占用是正常的哦,也不能释放的。 内存占用:rocks.blockcachemb 512MB,memtable占用rocks.write_buffer_size(64MB)* rocks.max_write_buffer_number(2)* kvStoreCount (10)=1.2GB。 所以总占用就是512MB+1.2GB=1.7GB,这些都是随着数据写入,内存很快就会达到1.7GB,在这之后是不会减少的。 如果想降低内存占用,就需要按照你的场景,调小rocks.blockcachemb和rocks.write_buffer_size和rocks.max_write_buffer_number和kvStoreCount几个值。

takenliu avatar Jul 22 '22 03:07 takenliu

这个内存占用是正常的哦,也不能释放的。 内存占用:rocks.blockcachemb 512MB,memtable占用rocks.write_buffer_size(64MB)* rocks.max_write_buffer_number(2)* kvStoreCount (10)=1.2GB。 所以总占用就是512MB+1.2GB=1.7GB,这些都是随着数据写入,内存很快就会达到1.7GB,在这之后是不会减少的。 如果想降低内存占用,就需要按照你的场景,调小rocks.blockcachemb和rocks.write_buffer_size和rocks.max_write_buffer_number和kvStoreCount几个值。

这都快一年了,我早就不用这个玩意了,内存占用大小,有没有释放都不重要了

lqxhub avatar Jul 22 '22 03:07 lqxhub

tendis节点内存占用最主要就是两块,blockcache和memtable,具体计算公式就是: rocks.blockcachemb + rocks.write_buffer_size(64MB)* rocks.max_write_buffer_number(2)* kvStoreCount (10)* columnFamilyNum(1 or 2) 说明:binlog-using-defaultCF=true,则columnFamilyNum=1;binlog-using-defaultCF=false,则columnFamilyNum=2

另外,如果配置rocks.cache_index_and_filter_blocks=false,则索引和布伦过滤器的内存消耗不在rocks.blockcachemb的控制之下,会有额外的内存占用。如果希望内存可控,可以配置rocks.cache_index_and_filter_blocks=true,将索引和布伦过滤器放到blockcache里面去。

takenliu avatar Jul 22 '22 03:07 takenliu

所以按照这个逻辑 tendis 的内存占用最小也要1280M 也就是1.2G (在rocks.blockcachemb配置很小 1M)

MollyBa avatar Jul 26 '22 03:07 MollyBa

对的。可以配置rocks.write_buffer_size 8MB,这样内存就大幅度减少了,大约就是200MB了。

takenliu avatar Jul 26 '22 03:07 takenliu

tendis节点内存占用最主要就是两块,blockcache和memtable,具体计算公式就是: rocks.blockcachemb + rocks.write_buffer_size(64MB)* rocks.max_write_buffer_number(2)* kvStoreCount (10)* columnFamilyNum(1 or 2) 说明:binlog-using-defaultCF=true,则columnFamilyNum=1;binlog-using-defaultCF=false,则columnFamilyNum=2

这个公式算出的值是不是约等于info memory看到的used_memory_rss的值

welliamcao avatar Oct 10 '22 03:10 welliamcao

takenliu

@takenliu 我按照公式里面计算tendis使用的内存,比used_memory_rss的值刚好少一半,rocks.blockcachemb我配置的是8G,used_memory_rss的值是22G,我比较担心内存会不会一直增加上去,麻烦帮忙解答一下。

welliamcao avatar Oct 26 '22 08:10 welliamcao

我提到的几个参数,你分别配的多少

takenliu avatar Oct 26 '22 08:10 takenliu

@takenliu

rocks.blockcachemb = 8192                  (获取方式:grep rocks.blockcachemb  tendisplus.conf)
rocks.write_buffer_size = 33554432  (获取方式:grep -i write_buffer_size /tendis/db/0/LOG)
rocks.max_write_buffer_number =2    (获取方式:grep -i max_write_buffer_number /tendis/db/0/LOG)

kvStoreCount = 10                                (默认配置没有修改)
127.0.0.1:6100> info Dataset
# Dataset
rocksdb.kvstore-count:10

columnFamilyNum = 2 
127.0.0.1:6100> config get binlog-using-defaultCF
1) "binlog-using-defaultcf"
2) "no"

welliamcao avatar Oct 27 '22 02:10 welliamcao

跟进程发一个jeprof dump命令,会生成一个类似jeprof.26397.4.m4.heap文件。再转一下pdf,把pdf发来看看: jeprof --show_bytes --pdf ./tendisplus jeprof.26397.4.m4.heap >test.pdf

takenliu avatar Oct 27 '22 02:10 takenliu

@luxinle

跟进程发一个jeprof dump命令,会生成一个类似jeprof.26397.4.m4.heap文件。再转一下pdf,把pdf发来看看: jeprof --show_bytes --pdf ./tendisplus jeprof.26397.4.m4.heap >test.pdf

(跟进程发一个jeprof dump命令,会生成一个类似jeprof.26397.4.m4.heap文件)没有使用过jeprof这个工具,没明白怎么操作,能麻烦给一个完整的例子吗?

[root@localhost ~]# jeprof /usr/bin/tendisplus /opt/apps/tendis/6100/conf/tendisplus.conf
Using local file /usr/bin/tendisplus.
Using local file /opt/apps/tendis/6100/conf/tendisplus.conf.
/opt/apps/tendis/6100/conf/tendisplus.conf: header size >= 2**16

直接退出了

welliamcao avatar Oct 29 '22 04:10 welliamcao

redis-cli -h * -s * -a * jeprof dump // 用客户端发一个jeprof dump命令到节点,会生成一个类似jeprof.26397.4.m4.heap文件 jeprof --show_bytes --pdf ./tendisplus jeprof.26397.4.m4.heap >test.pdf // 这个命令会生成一个pdf文件。里面会显示内存具体使用在哪里了。

关于jeprof,网上有很多资料,建议学一学。

takenliu avatar Oct 31 '22 03:10 takenliu

另外,可以编译tendisplus二进制的时候,去掉jemalloc试试,jemalloc里面可能会有一些内存的开销。 cmake .. -DENABLE_JEMALLOC=OFF ....... 再make

takenliu avatar Oct 31 '22 03:10 takenliu

test.pdf

redis-cli -h * -s * -a * jeprof dump // 用客户端发一个jeprof dump命令到节点,会生成一个类似jeprof.26397.4.m4.heap文件 jeprof --show_bytes --pdf ./tendisplus jeprof.26397.4.m4.heap >test.pdf // 这个命令会生成一个pdf文件。里面会显示内存具体使用在哪里了。

关于jeprof,网上有很多资料,建议学一学。

生成了

welliamcao avatar Oct 31 '22 04:10 welliamcao

另外,可以编译的时候,去掉jemalloc试试,jemalloc里面可能会有一些内存的开销。 cmake .. -DENABLE_JEMALLOC=OFF .......

这个指的是编译tendis的时候吧。

welliamcao avatar Oct 31 '22 04:10 welliamcao

takenliu avatar Oct 31 '22 06:10 takenliu

test.pdf

redis-cli -h * -s * -a * jeprof dump // 用客户端发一个jeprof dump命令到节点,会生成一个类似jeprof.26397.4.m4.heap文件 jeprof --show_bytes --pdf ./tendisplus jeprof.26397.4.m4.heap >test.pdf // 这个命令会生成一个pdf文件。里面会显示内存具体使用在哪里了。 关于jeprof,网上有很多资料,建议学一学。

生成了

@takenliu 这个有帮忙分析出问题来吗?

welliamcao avatar Nov 09 '22 08:11 welliamcao

test.pdf的统计结果: Total B: 22006166127 rocksdb UncompressBlockContentsForCompressionType 14533830551 (66.0%) rocksdb BlockFetcher PrepareBufferForBlockFromFile 6021520423 (27.4%) rocksdb Arena AllocateNewBlock 1201204538 (5.5%)

理论内存占用: 8GB+32MB210个kvstore*2个CF=9.2GB 所以比预期多了20GB-9.2GB=10.8GB左右。

rocks.cache_index_and_filter_blocks 改成 true 试试。怀疑是索引和过滤器的内存不在blockcache大小的控制之下。

takenliu avatar Nov 09 '22 08:11 takenliu