Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
lqxhub opened this issue Oct 25, 2021 · 34 comments
Open

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

lqxhub opened this issue Oct 25, 2021 · 34 comments
Assignees
Labels
bug Something isn't working

Comments

@lqxhub
Copy link

lqxhub commented Oct 25, 2021

在一台机械硬盘的机器上部署的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
@xjj210130
Copy link

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

@lqxhub
Copy link
Author

lqxhub commented Nov 1, 2021

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

还没解决

@xjj210130
Copy link

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

@jingjunLi
Copy link
Collaborator

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 jingjunLi self-assigned this Nov 2, 2021
@jingjunLi jingjunLi added the bug Something isn't working label Nov 2, 2021
@xjj210130
Copy link

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

@jingjunLi
Copy link
Collaborator

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

@xjj210130
Copy link

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

@lqxhub
Copy link
Author

lqxhub commented Nov 2, 2021

今上午又压测了一遍,内存维持在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

@jingjunLi
Copy link
Collaborator

从 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 这几个参数, 后面这里显示的问题会修复。

@lqxhub
Copy link
Author

lqxhub commented Nov 2, 2021

@jingjunLi

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

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

@luxinle
Copy link

luxinle commented Jul 22, 2022

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

@lqxhub
Copy link
Author

lqxhub commented Jul 22, 2022

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

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

@takenliu
Copy link
Collaborator

这个内存占用是正常的哦,也不能释放的。
内存占用: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
Copy link
Author

lqxhub commented Jul 22, 2022

这个内存占用是正常的哦,也不能释放的。 内存占用: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
Copy link
Collaborator

takenliu commented Jul 22, 2022

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里面去。

@MollyBa
Copy link

MollyBa commented Jul 26, 2022

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

@takenliu
Copy link
Collaborator

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

@welliamcao
Copy link

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
Copy link

takenliu

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

@takenliu
Copy link
Collaborator

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

@welliamcao
Copy link

@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"

@takenliu
Copy link
Collaborator

takenliu commented Oct 27, 2022

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

@welliamcao
Copy link

welliamcao commented Oct 29, 2022

@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

直接退出了

@takenliu
Copy link
Collaborator

takenliu commented Oct 31, 2022

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
Copy link
Collaborator

takenliu commented Oct 31, 2022

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

@welliamcao
Copy link

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
Copy link

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

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

@takenliu
Copy link
Collaborator

@welliamcao
Copy link

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 这个有帮忙分析出问题来吗?

@takenliu
Copy link
Collaborator

takenliu commented Nov 9, 2022

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
Copy link
Collaborator

takenliu commented Nov 9, 2022

加你qq了,方便沟通一点

@Monesph
Copy link

Monesph commented Jul 17, 2023

加你qq了,方便沟通一点

你好,请问一下这个问题解决了吗

@welliamcao
Copy link

rocks.cache_index_and_filter_blocks=1
rocks.pin_l0_filter_and_index_blocks_in_cache=1
设置这两个参数

@wrizyy450
Copy link

wrizyy450 commented Sep 8, 2023

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 如果根据这个公式调整参数适当的提高内存占用,能否提升一定的性能呢

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

9 participants