PostgreSQL 单库对象过多,触发Linux系统限制 (ext4_dx_add_entry: Directory index full!) (could not create file "xx/xx/xxxxxx": No space left on device)

本文涉及的产品
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
云原生数据库 PolarDB 分布式版,标准版 2核8GB
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介:

标签

PostgreSQL , Linux , 对象 , inode 限制 , 目录数限制


背景

PostgreSQL 里面创建的表,序列,索引,物化视图等带有存储的对象,每个对象的数据文件都是独立的,较依赖文件系统的管理能力。并不像Oracle那样把对象放到表空间中管理,表空间又由若干的数据文件组成。(ASM的话则接管更多的操作。)

所以,当创建了很多个有实际存储的对象时,文件数就会很多:

通常一个表包含数据文件(若干,单个默认1G),fsm文件一个, vm文件一个,如果是unlogged table则还有_init文件一个。

文件数过多,可能触发文件系统的一些限制。

ext4_dx_add_entry: Directory index full!  

举例

某个系统,在创建新的对象时,报这样的错误。

ERROR:  could not create file "base/16392/166637613": No space left on device  
digoal=# do language plpgsql $$  
declare  
begin  
for i in 1..1000 loop  
execute 'create table test'||i||'(id int primary key, c1 int unique, c2 int unique)';  
end loop;  
end;  
$$;  
ERROR:  53100: could not create file "base/16392/166691646": No space left on device  
CONTEXT:  SQL statement "create table test43(id int primary key, c1 int unique, c2 int unique)"  
PL/pgSQL function inline_code_block line 5 at EXECUTE statement  
LOCATION:  mdcreate, md.c:304  

报错的PG源码文件如下

/*  
 *      mdcreate() -- Create a new relation on magnetic disk.  
 *  
 * If isRedo is true, it's okay for the relation to exist already.  
 */  
void  
mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)  
{  
        MdfdVec    *mdfd;  
        char       *path;  
        File            fd;  
  
        if (isRedo && reln->md_num_open_segs[forkNum] > 0)  
                return;                      /* created and opened already... */  
  
        Assert(reln->md_num_open_segs[forkNum] == 0);  
  
        path = relpath(reln->smgr_rnode, forkNum);  
  
        fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600);  
  
        if (fd < 0)  
        {  
                int                     save_errno = errno;  
  
                /*  
                 * During bootstrap, there are cases where a system relation will be  
                 * accessed (by internal backend processes) before the bootstrap  
                 * script nominally creates it.  Therefore, allow the file to exist  
                 * already, even if isRedo is not set.  (See also mdopen)  
                 */  
                if (isRedo || IsBootstrapProcessingMode())  
                        fd = PathNameOpenFile(path, O_RDWR | PG_BINARY, 0600);  
                if (fd < 0)  
                {  
                        /* be sure to report the error reported by create, not open */  
                        errno = save_errno;  
                        ereport(ERROR,  
                                        (errcode_for_file_access(),  
                                         errmsg("could not create file \"%s\": %m", path)));  
                }  
        }  
  
        pfree(path);  
  
        _fdvec_resize(reln, forkNum, 1);  
        mdfd = &reln->md_seg_fds[forkNum][0];  
        mdfd->mdfd_vfd = fd;  
        mdfd->mdfd_segno = 0;  
}  

实际上就是创建文件出错,但并不是真的没有空间了"No space left on device"。

在系统中可以看到dmesg的消息如下

[14372230.975489] EXT4-fs warning (device dm-0): ext4_dx_add_entry: Directory index full!  
[14372230.984268] EXT4-fs warning (device dm-0): ext4_dx_add_entry: Directory index full!  
[14372230.992913] EXT4-fs warning (device dm-0): ext4_dx_add_entry: Directory index full!  

这个错误与某个目录下的文件数有关。文件数与INODE有关,同时EXT4中为了提高检索文件的性能,有index的优化开关。

man mkfs.ext4  
  
dir_index  
  Use hashed b-trees to speed up lookups in large directories.  

看起来像是这个超了。

和数据库进程的ulimit并无关系:

#cd /proc/17128  
  
#cat limits   
Limit                     Soft Limit           Hard Limit           Units       
Max cpu time              unlimited            unlimited            seconds     
Max file size             unlimited            unlimited            bytes       
Max data size             unlimited            unlimited            bytes       
Max stack size            unlimited            unlimited            bytes       
Max core file size        unlimited            unlimited            bytes       
Max resident set          unlimited            unlimited            bytes       
Max processes             655360               655360               processes   
Max open files            655360               655360               files       
Max locked memory         unlimited            unlimited            bytes       
Max address space         unlimited            unlimited            bytes       
Max file locks            unlimited            unlimited            locks       
Max pending signals       4133740              4133740              signals     
Max msgqueue size         819200               819200               bytes       
Max nice priority         0                    0                      
Max realtime priority     0                    0                      
Max realtime timeout      unlimited            unlimited            us    

分析原因

这个数据库居然创建了2万多个schema。

......  .....  
 repo_20171106_1034_2877694 | digoal  
 repo_20171106_1034_2877696 | digoal  
 repo_20171106_1034_2877697 | digoal  
 repo_20171106_1034_2877699 | digoal  
 repo_20171106_1034_2877700 | digoal  
 repo_20171106_1034_2877701 | digoal  
 repo_20171106_1034_2877703 | digoal  
digoal=# select count(*) from pg_namespace;  
 count   
-------  
 27151  
(1 row)  

每个schema的内容都差不多,有600多个对象。

digoal=# select count(*) from pg_class where relnamespace=(select oid from pg_namespace where nspname='repo_20171106_1034_2877737');  
 count   
-------  
   616  
(1 row)  

这个数据库中一共有2068万个对象。

digoal=# select count(*) from pg_class;  
  count     
----------  
 20680394  
(1 row)  

PG数据文件的存放规则

表空间目录/数据库目录/对象文件

目录结构

表空间/数据库/对象  
表空间/数据库/对象.1  
...  
表空间/数据库/对象.n  
表空间/数据库/对象_fsm  
表空间/数据库/对象_vm  
表空间/数据库/对象_init  

如果这些对象都在一个表空间里面,那么这个表空间下对应数据库OID的目录中,将有至少2000多万个文件。

$ cd $PGDATA/base/16392  
  
$ ll|wc -l  
  
21637521  

果然,有2163万个文件,看样子和它有莫大关系。

开启ext4的dir_index,对单个目录中文件数会有限制。

解决方法

1、删除不必要的schema

2、创建多个表空间,因为每个表空间是一个单独的目录。

3、将对象分配到不同的表空间中,这样的话就可以避免开启ext4的dir_index后,当有很多个对象时,单个目录中文件数超出限制的问题。

小结

由于目前PG的不同对象,存放在不同的数据文件中,当有多个对象时,会创建多个数据文件。

目前PG对象的数据文件存在目录结构如下:

表空间/数据库/对象  
表空间/数据库/对象.1  
...  
表空间/数据库/对象.n  
表空间/数据库/对象_fsm  
表空间/数据库/对象_vm  
表空间/数据库/对象_init  

如果将单个库的所有对象存放在一个表空间中,这个表空间/数据库目录下会有很多个文件,那么可能遇到开启ext4的dir_index后,当有很多个对象时,单个目录中文件数超出限制的问题。

比如本例,一个表空间/数据库目录下,有2000多万个文件。导致了ext4_dx_add_entry: Directory index full!的问题。

为了避免这个问题,建议在单个库的单个表空间中,不要超过500万个对象。如果有更多的对象要在一个库中创建,那么可以创建多个表空间。

当然,我们这里还没有提到文件系统的其他限制,比如一个文件系统INODE的限制。与位数,以及文件系统有关。

参考

《PostgreSQL DaaS设计注意 - schema与database的抉择》

《PostgreSQL 备库apply延迟(delay)原理分析与诊断》

《PostgreSQL 流复制延迟的测试方法》

《PostgreSQL standby 在万兆网环境中缘何 延迟? 如何解决?》

https://serverfault.com/questions/104986/what-is-the-maximum-number-of-files-a-file-system-can-contain

https://ext4.wiki.kernel.org/index.php/Ext4_Howto#Bigger_File_System_and_File_Sizes

https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout

https://stackoverflow.com/questions/466521/how-many-files-can-i-put-in-a-directory

https://serverfault.com/questions/482998/how-can-i-fix-it-ext4-fs-warning-device-sda3-ext4-dx-add-entry-directory-in

https://access.redhat.com/solutions/29894

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
15天前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
57 3
|
15天前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
47 2
|
9天前
|
Ubuntu Linux 网络安全
linux系统ubuntu中在命令行中打开图形界面的文件夹
在Ubuntu系统中,通过命令行打开图形界面的文件夹是一个高效且实用的操作。无论是使用Nautilus、Dolphin还是Thunar,都可以根据具体桌面环境选择合适的文件管理器。通过上述命令和方法,可以简化日常工作,提高效率。同时,解决权限问题和图形界面问题也能确保操作的顺利进行。掌握这些技巧,可以使Linux操作更加便捷和灵活。
15 3
|
15天前
|
安全 网络协议 Linux
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。通过掌握 ping 命令,读者可以轻松测试网络连通性、诊断网络问题并提升网络管理能力。
52 3
|
18天前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
36 6
|
SQL Cloud Native 关系型数据库
ADBPG(AnalyticDB for PostgreSQL)是阿里云提供的一种云原生的大数据分析型数据库
ADBPG(AnalyticDB for PostgreSQL)是阿里云提供的一种云原生的大数据分析型数据库
1280 1
|
数据可视化 关系型数据库 MySQL
将 PostgreSQL 迁移到 MySQL 数据库
将 PostgreSQL 迁移到 MySQL 数据库
1762 2
|
SQL 关系型数据库 Linux
【PostgreSQL】基于CentOS系统安装PostgreSQL数据库
【PostgreSQL】基于CentOS系统安装PostgreSQL数据库
961 0
|
SQL 存储 自然语言处理
玩转阿里云RDS PostgreSQL数据库通过pg_jieba插件进行分词
在当今社交媒体的时代,人们通过各种平台分享自己的生活、观点和情感。然而,对于平台管理员和品牌经营者来说,了解用户的情感和意见变得至关重要。为了帮助他们更好地了解用户的情感倾向,我们可以使用PostgreSQL中的pg_jieba插件对这些发帖进行分词和情感分析,来构建一个社交媒体情感分析系统,系统将根据用户的发帖内容,自动判断其情感倾向是积极、消极还是中性,并将结果存储在数据库中。
玩转阿里云RDS PostgreSQL数据库通过pg_jieba插件进行分词

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版