配置了内存上限,压力测试后内存不释放
在一台机械硬盘的机器上部署的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
请问楼主,内存不释放这个问题,你后面怎么解决的?
请问楼主,内存不释放这个问题,你后面怎么解决的?
还没解决
哎,腾讯的开发反馈太慢了。
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 的用法, 发一下 具体的内存占用大小。
把一些数据缓存到内存,是能够提高效率,当不用的时候,内存是不是应该释放出来呢?
从系统开发的角度来看 确实应该。 比如 block cache 缓存一些 block, 当 block 对应的 SST 删除时, 这个 block 不会被使用, 就应该 被释放出来, RocksDB 也是这么实现的。 你的意思是现在 Tendis 存在 缓存的数据, 不在释放的问题, 或者说内存泄漏的问题 ? 能具体说下在哪里, 我看下
嗯就是楼主说的问题,当压测完毕后,比如内存使用了15G,压测完毕后,如果没有继续调用的话,应该逐步释放内存。这个问题很好复现的,把master代码编译一把,随便压测一下,就可以看到这个现象。 不是内存泄漏。
今上午又压测了一遍,内存维持在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
从 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 导致的。

建议确认一下 max_write_buffer_number max_write_buffer_number_to_maintain write_buffer_size 这几个参数, 后面这里显示的问题会修复。
@jingjunLi
建议确认一下 max_write_buffer_number max_write_buffer_number_to_maintain write_buffer_size 这几个参数, 后面这里显示的问题会修复。
这些参数都是默认值, 没有修改
数据库内存永远应该释放、减少物理IO、
数据库内存永远应该释放、减少物理IO、 物理IO太慢了、不用的概念不同、什么叫不用、 这部分数据页和块永远不用叫不用,下次再用就必须从内存里直接拿不要从磁盘拿、 从磁盘拿就慢、相当慢、非常慢、慢到想骂娘、慢到感觉tendis不行。 其实不是tendis不行、不行的是老想着释放内存、不行的是数据结构 有续集。 在tendis处理有续集是比较慢的。
@luxinle 你想说的意思是 '数据库内存应该永远 不 释放吧' 我想要的效果是我可以控制一个内存缓存的上限,比如最多只有1G的内存缓存,超过这个值后就应该使用淘汰算法,把老数据置换出去。而不是无限制的内存增长。至于不在内存中,在硬盘的数据,读取数据时的延迟,我是可以接收的
这个内存占用是正常的哦,也不能释放的。 内存占用: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几个值。
这个内存占用是正常的哦,也不能释放的。 内存占用: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几个值。
这都快一年了,我早就不用这个玩意了,内存占用大小,有没有释放都不重要了
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里面去。
所以按照这个逻辑 tendis 的内存占用最小也要1280M 也就是1.2G (在rocks.blockcachemb配置很小 1M)
对的。可以配置rocks.write_buffer_size 8MB,这样内存就大幅度减少了,大约就是200MB了。
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的值
takenliu
@takenliu 我按照公式里面计算tendis使用的内存,比used_memory_rss的值刚好少一半,rocks.blockcachemb我配置的是8G,used_memory_rss的值是22G,我比较担心内存会不会一直增加上去,麻烦帮忙解答一下。
我提到的几个参数,你分别配的多少
@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"
跟进程发一个jeprof dump命令,会生成一个类似jeprof.26397.4.m4.heap文件。再转一下pdf,把pdf发来看看: jeprof --show_bytes --pdf ./tendisplus jeprof.26397.4.m4.heap >test.pdf
@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
直接退出了
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,网上有很多资料,建议学一学。
另外,可以编译tendisplus二进制的时候,去掉jemalloc试试,jemalloc里面可能会有一些内存的开销。 cmake .. -DENABLE_JEMALLOC=OFF ....... 再make
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,网上有很多资料,建议学一学。
生成了
另外,可以编译的时候,去掉jemalloc试试,jemalloc里面可能会有一些内存的开销。 cmake .. -DENABLE_JEMALLOC=OFF .......
这个指的是编译tendis的时候吧。
对
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 这个有帮忙分析出问题来吗?
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大小的控制之下。