首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面试官上来就问:Java 进程中有哪些组件会占用内存?

面试官上来就问:Java 进程中有哪些组件会占用内存?

作者头像
Java_老男孩
发布2019-12-02 21:52:38
4790
发布2019-12-02 21:52:38
举报

不管是持久化的消息还是非持久化的消息都可以被写入到磁盘。持久化的消息在到达队列时就被写入到磁盘,并且如果可以,持久化的消息也会在内存中保存一份备份,这样可以提高一定的性能,当内存吃紧的时候会从内存中清除。 非持久化的消息一般只保存在内存中,在内存吃紧的时候会被换入到磁盘中,以节省内存空间。这两种类型的消息的落盘处理都在RabbitMQ的“持久层”中完成。

持久层是一个逻辑上的概念,实际包含两个部分:队列索引(rabbit_queue_index)消息存储(rabbit_msg_store)

rabbit_queue_index负责维护队列中落盘消息的信息,包括消息的存储地点、是否已被交付给消费者、是否已被消费者ack等。每个队列都有与之对应的一个rabbit_queue_index。rabbit_msg_store以键值对的形式存储消息,它被所有队列共享,在每个节点中有且只有一个。从技术层面上来说,rabbit_msg_store具体还可以分为msg_store_persistent和msg_store_transient,msg_store_persistent负责持久化消息的持久化,重启后消息不会丢失;msg_store_transient负责非持久化消息的持久化,重启后消息会丢失。通常情况下,习惯性的将msg_store_persistent和msg_store_transient看成rabbit_msg_store这样一个整体。

消息(包括消息体、属性以及headers)可以直接存储在rabbit_queue_index中,也可以被保存在rabbit_msg_store中。默认在

RABBITMQ_HOME/var/lib/mnesia/rabbit@
RABBITMQ_HOME/var/lib/mnesia/rabbit@

HOSTNAME/路径下包含queues、msg_store_persistent、msg_store_transient这3个文件夹(下面信息中加粗部分),其分别存储对应的信息。

[root@node1 rabbit@node1]# pwd
/opt/rabbitmq/var/lib/rabbitmq/mnesia/rabbit@node1
[root@node1 rabbit@node1]# ll
-rw-r--r-- 1  root root    33 Sep 7  20:03 cluster_nodes.config
-rw-r--r-- 1  root root   155 Sep 10  10:51 DECISION_TAB.LOG
-rw-r--r-- 1  root root    91 Sep 10  10:51 LATEST.LOG
drwxr-xr-x 2  root root  4096 Sep 7  20:03 msg_store_persistent
drwxr-xr-x 2  root root  4096 Sep 7  20:03 msg_store_transient
-rw-r--r-- 1  root root    16 Sep 7  20:03 nodes_running_at_shutdown
drwxr-xr-x 6  root root  4096 Sep 10  11:12 queues
-rw-r--r-- 1  root root  2301 Sep 10  10:51 rabbit_durable_exchange.DCD
-rw-r--r-- 1  root root   817 Sep 9  23:48 rabbit_durable_queue.DCD
-rw-r--r-- 1  root root  1705 Sep 10  10:51 rabbit_durable_queue.DCL
-rw-r--r-- 1  root root  1117 Sep 10  10:51 rabbit_durable_route.DCD
-rw-r--r-- 1  root root   153 Sep 10  10:51 rabbit_runtime_parameters.DCD
-rw-r--r-- 1  root root     4 Sep 7  20:03 rabbit_serial
-rw-r--r-- 1  root root   354 Sep 6  18:52 rabbit_user.DCD
-rw-r--r-- 1  root root   483 Sep 6  18:48 rabbit_user_permission.DCD
-rw-r--r-- 1  root root   169 Sep 6  18:37 rabbit_vhost.DCD
-rw-r--r-- 1  root root  5464 Sep 7  20:03 recovery.dets
-rw-r--r-- 1  root root 21205 Sep 6  18:32 schema.DAT
-rw-r--r-- 1  root root   285 Sep 6  18:31 schema_version

最佳的配备是较小的消息存储在rabbit_queue_index中而较大的消息存储在rabbit_msg_store中。这个消息大小的界定可以通过queue_index_embed_msgs_below来配置,默认大小为4096,单位为B。注意这里的消息大小是指消息体、属性以及headers整体的大小。当一个消息小于设定的大小阈值时就可以存储在rabbit_queue_index中,这样可以得到性能上的优化。

rabbit_queue_index中以顺序(文件名从0开始累加)的段文件来进行存储,后缀为“.idx”,每个段文件中包含固定的SEGMENT_ENTRY_COUNT条记录,SEGMENT_ENTRY_COUNT默认值为16384。每个rabbit_queue_index从磁盘中读取消息的时候至少要在内存中维护一个段文件,所以设置queue_index_embed_msgs_below值的时候要格外谨慎,一点点的增大也可能会引起内存爆炸式的增长。

经过rabbit_msg_store处理的所有的消息都会以追加的方式写入到文件中,当一个文件的大小超过指定的限制(file_size_limit)后,关闭这个文件再创建一个新的文件以供新的消息写入。文件名(文件后缀是“.rdq”)从0开始进行累加,因此文件名最小的文件也是最老的文件。在进行消息的存储时,RabbitMQ会在ETS(ErlangTerm Storage)表中记录消息在文件中的位置映射(Index)以及文件的相关信息(FileSummary)。

在读取消息的时候,先根据消息的ID(msg_id)找到对应存储的文件,如果文件存在并且未被锁住,则直接打开文件,从指定位置读取消息的内容。如果文件不存在或者被锁住了,则发送请求由rabbit_msg_store进行处理。

消息的删除只是从ETS表删除指定消息的相关信息,同时更新消息对应的存储文件的相关信息。执行消息删除操作时,并不立即对在文件中的消息进行删除,也就是说消息依然在文件中,仅仅是标记为垃圾数据而已。当一个文件中都是垃圾数据时可以将这个文件删除。当检测到前后两个文件中的有效数据可以合并在一个文件中,并且所有的垃圾数据的大小和所有文件(至少有3个文件存在的情况下)的数据大小的比值超过设置的阈值GARBAGE_FRACTION(默认值为0.5)时才会触发垃圾回收将两个文件合并。

执行合并的两个文件一定是逻辑上相邻的两个文件。如图所示,执行合并时首先锁定这两个文件,并先对前面文件中的有效数据进行整理,再将后面文件的有效数据写入到前面的文件,同时更新消息在ETS表中的记录,最后删除后面的文件。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档