ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

GlusterFS Statedump 完全指南:生成、解读与内存泄漏/挂起问题排查

GlusterFS Statedump 完全指南:生成、解读与内存泄漏/挂起问题排查 存储网络【免费下载链接】glusterfsGluster Filesystem : Build your distributed storage in minutes项目地址https://gitcode.com/gh_mirrors/gl/glusterfs点击查看免费下载Statedump 是 GlusterFS 进程在运行时导出的内部数据结构快照文件覆盖活动 inode、fd、内存池mempool、iobuf、各 xlator 的数据结构内存分配统计等关键状态。本文以 doc/debugging/statedump.md 为主线结合仓库源码libglusterfs/src/statedump.c、cli/src/cli-cmd-volume.c 等深入讲解如何对 glusterd/glusterfs/glusterfsd 进程生成 statedump、如何逐段解读每一类输出以及如何利用它定位内存泄漏和由 frame 丢失引起的挂起问题。什么是 StatedumpStatedump 是 GlusterFS 进程生成的、记录其内部各种数据结构状态的文本文件。文件中可能包含当前活动的 inode、fd文件描述符内存池mempool、iobuf 池的状态每个 xlator 各类数据结构的内存分配统计挂起的 call-stack / call-frame用于排查 fop 挂起fuse 层的操作历史、xlator 私有配置、inode table 状态等在 libglusterfs/src/statedump.c 中gf_proc_dump_info()是生成 statedump 的核心入口它通过gf_proc_dump_add_section()/gf_proc_dump_write()两个工具函数以[section]与keyvalue的键值对格式逐段写入 dump 文件见 libglusterfs/src/statedump.c。也就是说statedump 的所有区块本质上都来自各模块主动注册的 dump 回调通过统一的键值文本格式输出。如何生成 Statedump1. 确认 statedump 目录使用gluster --print-statedumpdir命令查询 statedump 文件的默认存放目录gluster --print-statedumpdir在源码中该命令直接打印DEFAULT_VAR_RUN_DIRECTORY见 cli/src/cli.c通常对应/var/run/gluster一类路径。如果该目录在当前安装类型下尚不存在请先手动创建。下文将该目录统称为statedump-directory。2. 使用 SIGUSR1 信号触发对任意 GlusterFS 进程glusterd / glusterfs / glusterfsd发送 SIGUSR1 即可触发kill -USR1 pid-of-gluster-process从源码看gf_proc_dump_info()就运行在信号处理上下文gf_msg_trace(dump, 0, received statedump request (sig:USR1))见 libglusterfs/src/statedump.c并受gf_proc_dump_mutex保护防止多次触发相互干扰。值得注意的是statedump 落在信号处理器内执行因此实现中特意避免在该路径上使用可能阻塞锁的gf_log见 libglusterfs/src/statedump.c。3. 针对 brick / NFS / quotad 进程Gluster 提供了专门的 CLI 命令来为不同类型进程生成 statedumpgluster volume statedump volname gluster volume statedump volname nfs gluster volume statedump volname quotad其中第一条为brick 进程brick 模式第二条为NFS 服务器进程nfs 模式第三条为quotad 进程quotad 模式。该命令的 CLI 侧实现为cli_cmd_volume_statedump_cbk()见 cli/src/cli-cmd-volume.c其完整的命令语法在命令注册表中定义如下见 cli/src/cli-cmd-volume.cvolume statedump VOLNAME [[nfs|quotad] [all|mem|iobuf|callpool|priv|fd|inode|history]... | [client hostname:process-id]]也就是说除nfs、quotad外还支持all、mem、iobuf、callpool、priv、fd、inode、history等细分选项inodectx、fdctx亦被cli_cmd_validate_dumpoption()接受完整选项表见 cli/src/cli-cmd-parser.c。这些选项决定了 dump 文件中包含哪些区块对应源码中的gf_dump_options_t结构libglusterfs/src/glusterfs/statedump.h。4. 针对使用 libgfapi 的应用进程对于通过 libgfapi 接入 Gluster 的应用如 smbd、libvirtd不能直接使用SIGUSR1——这类进程可能早已把SIGUSR1用于其他用途。此时可在 Gluster 集群中该 libgfapi 应用所连接的任一节点上执行gluster volume statedump volname client hostname:process idCLI 解析器会校验hostname:pid格式其中 IP 必须是合法地址、pid 必须为正整数见 cli/src/cli-cmd-parser.c。5. 生成文件的命名规则brick 进程文件名为hyphenated-brick-path.pid.dump.timestampbrick 路径中的/会替换为-见 libglusterfs/src/statedump.c其他所有进程文件名为glusterdump.pid.dump.timestamp。文件最终路径的构造逻辑见 libglusterfs/src/statedump.c依次取glusterdump.options文件中的path配置 → 进程自身的ctx-statedump_path→ 默认目录DEFAULT_VAR_RUN_DIRECTORY。写入时先通过mkstemp创建临时文件dumpXXXXXX全部写完后再rename为最终文件名保证 dump 文件内容完整见 libglusterfs/src/statedump.c。对使用 libgfapi 的应用进程dump 文件同样位于statedump-directory命名为glusterdump.pid.dump.timestamp。由于一个应用可能多次调用glfs_init()访问多个卷同一个 pid 可能对应多个这样的文件。6. 通过 glusterdump.options 控制 dump 内容直接发送SIGUSR1时没有命令行选项机制。为了让 CLI 命令和 SIGUSR1 两种方式都能配置 dump 内容进程会优先读取statedump-directory/glusterdump.options全局配置其次读取statedump-directory/glusterdump.pid.options按进程配置具体逻辑见 libglusterfs/src/statedump.c两个文件都不存在时默认开启全部选项gf_proc_dump_enable_all_options()存在文件时先关闭全部选项再按文件中keyvalue逐行解析value以yes开头即为开启如memyes、iobufyes若解析后所有选项都被禁用则回退到默认选项mem与callpoolgf_proc_dump_enable_default_options()。如何阅读 Statedump下面按区块逐一解读各类输出的含义。文件首尾时间戳dump 文件第一行和最后一行分别记录了开始与结束写入 statedump 的时间格式为DUMP-START-TIME/DUMP-END-TIME时区为UTC实现见 libglusterfs/src/statedump.c。两端时间差可粗略衡量 dump 写入耗时。Mallinfoglibc 堆内存统计mallinfo区块来自 glibc 的mallinfo()/mallinfo2()源码根据HAVE_MALLINFO2宏选择调用见 libglusterfs/src/statedump.c反映进程堆的总体分配状况[mallinfo] mallinfo_arena100020224 /* Non-mmapped space allocated (bytes) */ mallinfo_ordblks69467 /* Number of free chunks */ mallinfo_smblks449 /* Number of free fastbin blocks */ mallinfo_hblks13 /* Number of mmapped regions */ mallinfo_hblkhd20144128 /* Space allocated in mmapped regions (bytes) */ mallinfo_usmblks0 /* Maximum total allocated space (bytes) */ mallinfo_fsmblks39264 /* Space in freed fastbin blocks (bytes) */ mallinfo_uordblks96710112 /* Total allocated space (bytes) */ mallinfo_fordblks3310112 /* Total free space (bytes) */ mallinfo_keepcost133712 /* Top-most, releasable space (bytes) */各字段的详细语义请参考man mallinfo。简单来说mallinfo_uordblks是已分配空间mallinfo_fordblks是空闲空间mallinfo_arena是非 mmap 区域的分配量mallinfo_hblkhd是 mmap 区域的分配量。它是判断进程整体内存增长趋势的起点但要定位具体是哪类数据结构在增长还需要结合下面两个区块。数据结构分配统计Data structure allocation stats对调用图call-graph中加载的每个 xlatorstatedump 会按数据结构类型打印内存记账memory accounting信息。先给出汇总头[global.glusterfs - Memory usage] #[global.xlator-name - Memory usage] num_types119 #It shows the number of data types it is using其中num_types是该 xlator 使用的数据类型数量。随后对每一种有活动分配的数据类型打印明细格式如下[global.glusterfs - usage-type gf_common_mt_gf_timer_t memusage] #[global.xlator-name - usage-type tag associated with the>[mempool] #Section name ---------- pool-namefuse:fd_t #pool-namexlator-name:data-type hot-count1 #number of mempool elements that are in active use. i.e. for this pool it is the number of fd_t s in active use. cold-count1023 #number of mempool elements that are not in use. If a new allocation is required it will be served from here until all the elements in the pool are in use i.e. cold-count becomes 0. padded_sizeof108 #Each mempool element is padded with a doubly-linked-list ptr of mempool is-in-use info to operate the pool of elements, this size is the element-size after padding pool-misses0 #Number of times the element had to be allocated from heap because all elements from the pool are in active use. alloc-count314 #Number of times this type of data is allocated through out the life of this process. This may include pool-misses as well. max-alloc3 #Maximum number of elements from the pool in active use at any point in the life of the process. This does *not* include pool-misses. cur-stdalloc0 #Denotes the number of allocations made from heap once cold-count reaches 0, that are yet to be released via mem_put(). max-stdalloc0 #Maximum number of allocations from heap that are in active use at any point in the life of the process.各字段含义字段含义pool-name池名称格式为xlator-name:data-typehot-count池中处于活动使用状态的元素数如该池即当前活动的fd_t数cold-count池中空闲未使用元素数新分配优先从这里取直到池元素全部被占用cold-count 为 0padded_sizeof每个元素经过填充后的实际大小含双向链表、池指针、是否在用标记等池管理开销pool-misses因池元素全部在用而从堆分配的次数alloc-count进程生命周期内该类型数据的总分配次数含 pool-missesmax-alloc进程生命周期内池元素活动使用数的历史峰值不含pool-missescur-stdalloccold-count 归零后从堆分配、且尚未通过mem_put()归还的分配数max-stdalloc任意时刻从堆分配且处于活动使用的最大数量cold-count长期为 0 且pool-misses持续增长通常意味着内存池被打穿、系统频繁走堆分配cur-stdalloc持续增长则说明有分配没有归还是内存泄漏的强信号。IobufsI/O 缓冲池iobuf 是 GlusterFS 为 I/O 数据准备的缓冲池其全局统计格式如下[iobuf.global] iobuf_pool0x1f0d970 #The memory pool for iobufs iobuf_pool.default_page_size131072 #The default size of iobuf (if no iobuf size is specified the default size is allocated) #iobuf_arena: One arena represents a group of iobufs of a particular size iobuf_pool.arena_size12976128 # The initial size of the iobuf pool (doesnt include the stdallocd memory or the newly added arenas) iobuf_pool.arena_cnt8 #Total number of arenas in the pool iobuf_pool.request_misses0 #The number of iobufs that were stdallocd (as they exceeded the default max page size provided by iobuf_pool).iobuf_pool.request_misses表示因为请求尺寸超过池默认最大页大小而走 stdalloc 的次数。这些字段与 libglusterfs/src/iobuf.c 中iobuf_stats_dump()的输出一一对应。iobuf 池中存在3 种 arena 列表Arena 列表池创建时分配的 arena以及正在使用active_cnt ! 0的 arenaPurge 列表可以被回收的 arena无活动 iobufactive_cnt 0Filled 列表没有空闲 iobuf 的 arena。每个 arena 的明细如下[purge.1] #purge.S.No. purge.1.mem_base0x7fc47b35f000 #The address of the arena structure purge.1.active_cnt0 #The number of iobufs active in that arena purge.1.passive_cnt1024 #The number of unused iobufs in the arena purge.1.alloc_cnt22853 #Total allocs in this pool(number of times the iobuf was allocated from this arena) purge.1.max_active7 #Max active iobufs from this arena, at any point in the life of this process. purge.1.page_size128 #Size of all the iobufs in this arena. [arena.5] #arena.S.No. arena.5.mem_base0x7fc47af1f000 arena.5.active_cnt0 arena.5.passive_cnt64 arena.5.alloc_cnt0 arena.5.max_active0 arena.5.page_size32768如果某个 arena 的active_cnt非零statedump 还会额外打印该 arena 的活动 iobuf 列表[arena.6.active_iobuf.1] #arena.S.No.active_iobuf.iobuf.S.No. arena.6.active_iobuf.1.ref1 #refcount of the iobuf arena.6.active_iobuf.1.ptr0x7fdb921a9000 #address of the iobuf [arena.6.active_iobuf.2] arena.6.active_iobuf.2.ref1 arena.6.active_iobuf.2.ptr0x7fdb92189000在任意时刻如果存在大量filled arena无空闲 iobuf则可能是iobuf 泄漏的迹象值得结合活动 iobuf 列表与调用栈进一步分析。Call stack调用栈GlusterFS 收到的所有 fop 都通过 call-stack 处理。call-stack 中包含执行该 fop 的进程的 uid/gid/pid 等信息每个 call-stack 由多个 call-frame 组成——每个 frame 对应处理该 fop 路径上的一个 xlator。格式如下[global.callpool.stack.3] #global.callpool.stack.Serial-Number stack0x7fc47a44bbe0 #Stack address uid0 #Uid of the process which is executing the fop gid0 #Gid of the process which is executing the fop pid6223 #Pid of the process which is executing the fop unique2778 #Xlators like afr do copy_frame and perform the operation in a different stack, this id is useful to find out the stacks that are inter-related because of copy-frame lk-owner0000000000000000 #Some of the fuse fops have lk-owner. opLOOKUP #Fop type1 #Type of the op i.e. FOP/MGMT-OP cnt9 #Number of frames in this stack.其中unique尤其值得注意像 afr 这类 xlator 会通过copy_frame在新栈中执行操作unique用于关联因 copy-frame 而相互关联的多个栈。Call-frame调用帧每个 frame 记录其所属 xlator、从哪个函数 wind、向哪个函数 unwind以及是否已完成 unwind。当系统出现挂起时取一个 statedump找到最后一个尚未 unwind 的 xlator就能定位挂起发生的层[global.callpool.stack.3.frame.2]#global.callpool.stack.stack-serial-number.frame.frame-serial-number frame0x7fc47a611dbc #Frame address ref_count0 #Incremented at the time of wind and decremented at the time of unwind. translatorr2-client-1 #Xlator this frame belongs to complete0 #if this value is 1 that means this frame is already unwound. 0 if it is yet to unwind. parentr2-replicate-0 #Parent xlator of this frame wind_fromafr_lookup #Parent xlator function from which the wind happened wind_topriv-children[i]-fops-lookup unwind_toafr_lookup_cbk #Parent xlator function to which unwind happened关键字段字段含义ref_countwind 时递增、unwind 时递减的引用计数translator该 frame 所属的 xlatorcomplete1 表示该 frame 已 unwind0 表示尚未 unwindparent该 frame 的父 xlatorwind_from父 xlator 中发起 wind 的函数wind_towind 目标下一层 xlator 的 fopunwind_to父 xlator 中接收 unwind 的回调函数如果栈中靠前接近客户端的 framecomplete1而靠后的 framecomplete0说明调用在某个 xlator 处“丢失”了具体排查流程见文末 FAQ。Fuse 操作历史History of operations in Fusefuse xlator 会维护在 fuse 层发生过的操作历史输出格式如下[xlator.mount.fuse.history] TIME2014-07-09 16:44:57.523364 message[0] fuse_release: RELEASE(): 4590:, fd: 0x1fef0d8, gfid: 3afb4968-5100-478d-91e9-76264e634c9f TIME2014-07-09 16:44:57.523373 message[0] send_fuse_err: Sending Success for operation 18 on inode 3afb4968-5100-478d-91e9-76264e634c9f TIME2014-07-09 16:44:57.523394 message[0] fuse_getattr_resume: 4591, STAT, path: (/iozone.tmp), gfid: (3afb4968-5100-478d-91e9-76264e634c9f)历史记录由 fuse xlator 的fuse_history_dump()回调输出且受event-history选项控制见 xlators/mount/fuse/src/fuse-bridge.c。挂起发生时这段历史能帮你判断最后一个成功处理的操作是什么。Xlator 配置Xlator configuration每个 xlator 的私有配置priv也会被 dump格式如下[cluster/replicate.r2-replicate-0] #Xlator type, name information child_count2 #Number of children to the xlator #Xlator specific configuration below child_up[0]1 pending_key[0]trusted.afr.r2-client-0 child_up[1]1 pending_key[1]trusted.afr.r2-client-1 data_self_healon metadata_self_heal1 entry_self_heal1 data_change_log1 metadata_change_log1 entry-change_log1 read_child1 favorite_child-1 wait_count1区块标题格式为[xlator-type.xlator-name]随后是child_count与 xlator 特有的配置项此处为 replicate/afr 的 child 状态、self-heal 开关、pending key 等。这部分通过各 xlator 注册的dumpops-priv回调输出见 libglusterfs/src/statedump.c。Graph / inode table当前活动 graph 与 inode table 的统计如下[active graph - 1] conn.1.bound_xl./data/brick01a/homegfs.hashsize14057 conn.1.bound_xl./data/brick01a/homegfs.name/data/brick01a/homegfs/inode conn.1.bound_xl./data/brick01a/homegfs.lru_limit16384 #Least recently used size limit conn.1.bound_xl./data/brick01a/homegfs.active_size690 #Number of inodes undergoing some kind of fop to be precise on which there is at least one ref. conn.1.bound_xl./data/brick01a/homegfs.lru_size183 #Number of inodes present in lru list conn.1.bound_xl./data/brick01a/homegfs.purge_size0 #Number of inodes present in purge list关键统计active_size正在参与某种 fop、至少持有一个引用的 inode 数lru_size处于 LRU 列表中的 inode 数purge_size处于 purge 列表中的 inode 数lru_limitLRU 大小的上限。若active_size异常偏高且持续不降说明 inode 引用未被正确释放。Inode 明细inode table 中的每个 inode 也会被打印格式如下[conn.1.bound_xl./data/brick01a/homegfs.active.324] #324th inode in active inode list gfide6d337cf-97eb-44b3-9492-379ba3f6ad42 #Gfid of the inode nlookup13 #Number of times lookups happened from the client or from fuse kernel fd-count4 #Number of fds opened on the inode ref11 #Number of refs taken on the inode ia_type1 #Type of the inode. This should be changed to some string :-( Ref by xl:.patchy-md-cache11 #Further this there will be a list of xlators, and the ref count taken by each of them on this inode at the time of statedump [conn.1.bound_xl./data/brick01a/homegfs.lru.1] #1st inode in lru list. Note that ref count is zero for these inodes. gfid5114574e-69bc-412b-9e52-f13ff087c6fc nlookup5 fd-count0 ref0 ia_type2 Ref by xl:.fuse1 Ref by xl:.patchy-client-0-1要点active 列表中的 inoderef非零lru 列表中的 inode ref 为 0如上面的ref0所示Ref by xl:xlator名ref数逐条列出每个 xlator 对当前 inode 持有的引用数用于判断是谁“拖住”了 inode 没有释放fd-count为 on inode 上打开的文件描述符数长期不为 0 的 inode 可能与 fd 泄漏相关。Inode context含锁信息每个 xlator 还可能为 inode 保存上下文例如 locks xlator 的 inode 上下文会输出锁域与锁明细[xlator.features.locks.homegfs-locks.inode] path/homegfs/users/dfrobins/gfstest/r4/SCRATCH/fort.5102 - path of the file mandatory0 inodelk-count5 #Number of inode locks lock-dump.domain.domainhomegfs-replicate-0:self-heal #Domain name where self-heals take locks to prevent more than one heal on the same file inodelk.inodelk0typeWRITE, whence0, start0, len0, pid 18446744073709551615, owner080b1ada117f0000, client0xb7fc30, connection-idcompute-30-029.com-3505-2014/06/29-14:46:12:477358-homegfs-client-0-0-1, granted at Sun Jun 29 11:01:00 2014 #Active lock information inodelk.inodelk1typeWRITE, whence0, start0, len0, pid 18446744073709551615, ownerc0cb091a277f0000, client0xad4f10, connection-idgfs01a.com-4080-2014/06/29-14:41:36:917768-homegfs-client-0-0-0, blocked at Sun Jun 29 11:04:44 2014 #Blocked lock information lock-dump.domain.domainhomegfs-replicate-0:metadata #Domain name where metadata operations take locks to maintain replication consistency lock-dump.domain.domainhomegfs-replicate-0 #Domain name where entry/data operations take locks to maintain replication consistency inodelk.inodelk0typeWRITE, whence0, start11141120, len131072, pid 18446744073709551615, owner080b1ada117f0000, client0xb7fc30, connection-idcompute-30-029.com-3505-2014/06/29-14:46:12:477358-homegfs-client-0-0-1, granted at Sun Jun 29 11:10:36 2014 #Active lock information锁信息按锁域domain分组self-heal、metadata、entry/data 等每个锁条目标注了类型ACTIVE/BLOCKED、锁类型READ/WRITE、起始偏移与长度、owner、client、连接 ID 以及加锁/阻塞时间。当怀疑锁导致 I/O 挂起时这份数据可以直接给出“谁在等谁”的证据。实战 FAQ用 Statedump 排查典型问题如何用 Statedump 调试内存泄漏方法一利用内存记账memory accounting特性一个真实案例对应 Bugzilla 1120151在 replicate 卷中擦除一个 brick 并触发fullself-heal 后进程内存持续增长。对 self-heal 守护进程执行kill -USR1 pid-of-gluster-self-heal-daemon抓取 statedump然后grep -w num_allocs glusterdump.5225.dump.1405493251 num_allocs77078 num_allocs87070 num_allocs117376 .... grep hot-count glusterdump.5225.dump.1405493251 hot-count16384 hot-count16384 hot-count4095 ....在 statedump 文件中定位这些高数值对应的数据类型 tag。该案例中grep 结果显示 replicate 下以下数据类型的分配异常偏高gf_common_mt_asprintfgf_common_mt_chargf_common_mt_mem_pool随后排查 afr 源码中带gf_common_mt_chartag 的分配发现data-self-heal代码路径有一处内存没有释放gf_common_mt_mem_pool则提示池内存存在泄漏——replicate-0:dict_t、glusterfs:data_t、glusterfs:data_pair_t这些池的cold_count为 0 且分配过多。检查 libglusterfs/src/dict.c 源码后发现dict中的key使用gf_common_mt_char分配对应第 2 个 tagvalue 通过gf_asprintf创建内部使用gf_common_mt_asprintf对应第 1 个 tag。继续在 self-heal 代码路径中排查定位到一行代码在变量已持有某个字典引用的情况下又用新字典覆盖了它旧引用丢失。修复泄漏后在同一测试heal 包含 10,000 个文件的目录层级中验证self-heal 守护进程 statedump 里所有num_allocs不再增长。排查思路小结num_allocs反映“当前活动分配数”若某 tag 的num_allocs随测试推进持续上升就说明该类型数据结构只增不减顺着 tag 反查源码中对应分配点即可锁定泄漏位置。方法二排查内存池泄漏借助 -DDEBUG 构建另一个案例对应 Bugzilla 1134221代码分析发现 name self-heal 过程中dict_t对象被反复创建而未被充分 unref。验证步骤如下用-DDEBUG编译 glusterfs使cold count默认为 0即内存池默认不预分配让堆分配情况完全暴露在cur-stdalloc中在 plain replicate 卷上创建 100 个文件从其中一个 brick 的后端删除它们从挂载点对这些路径触发 lookup测试前后分别对 fuse 挂载进程取 statedump。测试前的 statedumpfuse mount 进程pool-nameglusterfs:dict_t hot-count0 cold-count0 padded_sizeof140 alloc-count33 max-alloc0 pool-misses33 cur-stdalloc14 max-stdalloc18测试后的 statedumppool-nameglusterfs:dict_t hot-count0 cold-count0 padded_sizeof140 alloc-count2841 max-alloc0 pool-misses2841 cur-stdalloc214 max-stdalloc220在cold count为 0 的前提下cur-stdalloc表示通过mem_get()从堆分配、尚未用mem_put()归还的dict_t对象数。测试100 个文件的 name self-heal之后dict_t的cur-stdalloc从 14 涨到 214泄漏被证实。mempool 工作机制的更多细节可参考 datastructure-mem-pool.md。修复泄漏后再次以-DDEBUG编译并重复相同步骤测试前后的结果如下——修复前pool-nameglusterfs:dict_t hot-count0 cold-count0 padded_sizeof140 alloc-count33 max-alloc0 pool-misses33 cur-stdalloc14 max-stdalloc18修复后测试后pool-nameglusterfs:dict_t hot-count0 cold-count0 padded_sizeof140 alloc-count2837 max-alloc0 pool-misses2837 cur-stdalloc14 max-stdalloc119cur-stdalloc在测试前后保持 14 不变分配峰值max-stdalloc也明显回落说明修复确实生效。排查思路小结cur-stdalloc是堆上“已分配未归还”对象的实时计数测试前后对比该值即可判断是否有对象被分配后从未释放。如何用 Statedump 调试因 frame 丢失导致的挂起真实案例对应 Bugzilla 994959中挂起发生时对所有进程抓取 statedump。mount 进程的 statedump 中出现了如下调用栈[global.callpool.stack.1.frame.1] ref_count1 translatorfuse complete0 [global.callpool.stack.1.frame.2] ref_count0 translatorr2-client-1 complete1 ----- Client xlator completed the readdirp call and unwound to afr parentr2-replicate-0 wind_fromafr_do_readdir wind_tochildren[call_child]-fops-readdirp unwind_fromclient3_3_readdirp_cbk unwind_toafr_readdirp_cbk [global.callpool.stack.1.frame.3] ref_count0 translatorr2-replicate-0 complete0 ---- Afr xlator is not unwinding for some reason. parentr2-dht wind_fromdht_do_readdir wind_toxvol-fops-readdirp unwind_todht_readdirp_cbk [global.callpool.stack.1.frame.4] ref_count1 translatorr2-dht complete0 parentr2-io-cache wind_fromioc_readdirp wind_toFIRST_CHILD(this)-fops-readdirp unwind_toioc_readdirp_cbk [global.callpool.stack.1.frame.5] ref_count1 translatorr2-io-cache complete0 parentr2-quick-read wind_fromqr_readdirp wind_toFIRST_CHILD (this)-fops-readdirp unwind_toqr_readdirp_cbk分析要点frame.2r2-client-1complete1说明 client xlator 已完成readdirp调用并 unwind 回 afr其unwind_toafr_readdirp_cbkframe.3r2-replicate-0complete0说明afr xlator 没有继续 unwind其下的 frame.4、frame.5dht、io-cache、quick-read自然全部处于complete0的挂起状态。顺着unwind_toafr_readdirp_cbk检查 afr 源码中该回调的实现发现当 fop 失败时afr 没有对栈执行 unwind导致整个调用链悬挂。找到根因并修复后挂起消失。排查思路小结在栈中寻找“上方 frame 已 complete、但本 frame 仍未 complete”的断层点——那个 frame 所属的 xlator 就是 fop 被卡住的地方。unwind_to字段直接指明了应当被调用却没有被调用的回调函数据此即可精确定位源码位置。附相关源码路径速查关注点文件statedump 核心实现信号处理、文件生成、选项解析libglusterfs/src/statedump.cstatedump 选项结构定义与对外 APIlibglusterfs/src/glusterfs/statedump.hiobuf 池状态 dumparena/purge/filled 列表libglusterfs/src/iobuf.cgluster volume statedumpCLI 命令回调cli/src/cli-cmd-volume.cstatedump 选项校验与client hostname:pid解析cli/src/cli-cmd-parser.cgluster --print-statedumpdir实现cli/src/cli.cfuse 操作历史 dump 回调xlators/mount/fuse/src/fuse-bridge.cmempool 数据结构设计说明datastructure-mem-pool.md总结Statedump 是 GlusterFS 运维与开发调试中最高效的“现场快照”工具kill -USR1与gluster volume statedump两条路径覆盖 glusterd、brick、NFS、quotad 以及 libgfapi 应用进程输出中的 mallinfo、数据结构分配统计、mempool、iobuf、call-stack/call-frame、fuse 历史、锁上下文等区块分别服务于内存泄漏定位、iobuf 泄漏判断、fop 挂起归因等典型故障场景。掌握“先抓 dump、再按区块交叉印证、最后反查源码”的方法论就能把一次莫名的内存增长或 I/O 挂起快速收敛到具体的 xlator、数据结构和代码路径。赞分享存储网络【免费下载链接】glusterfsGluster Filesystem : Build your distributed storage in minutes项目地址https://gitcode.com/gh_mirrors/gl/glusterfs点击查看免费下载相关推荐CodeForge内存泄漏问题排查方法CodeForge内存泄漏问题排查方法 引言为什么内存泄漏是CodeForge的关键问题 作为一款多语言代码执行器CodeForge面临着独特的内存管理挑开发工具代码编辑器桌面应用数据库客户端数据可视化MimicKit深度解析轻量级运动模仿框架如何彻底改变控制器训练MimicKit深度解析轻量级运动模仿框架如何彻底改变控制器训练 MimicKit是一款轻量级运动模仿框架专为训练控制器提供一套全面的运动模仿方法。该框架告别内存噩梦前端内存泄漏完全排查指南告别内存噩梦前端内存泄漏完全排查指南 你是否遇到过网页越用越卡甚至崩溃的情况用户投诉页面操作卡顿却找不到明确报错这很可能是内存泄漏在作祟。本文将带你从文档技术博客教程上一篇完整指南How to Train Your GPT 详解 LLM 推理加速与采样参数设置KV Cache、Temperature、Top-k/Top-P 一次讲透下一篇Laya-CoreML W8 调色板压缩实战K-means 权重量化带来3.19倍能效的完整过程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表