重建群晖 pgsql 数据库

春节前,稳定许久的 NAS 给我送了一个意外惊吓,让我平淡的生活又多了点刺激。

前两天 btrfs 存储池忽然故障,变成了只读。更换内存后重启了几次存储池自动修复了。

似乎是 btrfs 存储池的一部分数据存放在内存中的,而我的群晖型号不支持 ECC 内存。如果内存出现问题,存储池就有可能发生故障。

尽管自动修复后看上去数据并没有遭受太大损失,但 pgsql 数据库却遭遇了无法启动的问题。

一直在 /var/log/messages 文件中不断地输出相关信息:

2024-02-06T01:35:12+08:00 NAS coredump[3356]: Process postgres[3208](/usr/bin/postgres) dumped core on signal [6]. Core file [/volume1/@postgres.synology_avoton_1815+.42962.core.gz]. Cmdline [postgres: startup                        ]
2024-02-06T01:35:19+08:00 NAS coredump[3356]: Core file [/volume1/@postgres.synology_avoton_1815+.42962.core.gz] size [4084009]

进一步检查发现似乎是 pgsql 的部分数据文件损坏了,而 pgsql dump 的文件内也有类似 could not stat file "./base/81548/81918_vm": Input/output error 的错误信息。

在群晖系统中,pgsql 负责存储如 SynologyPhotos、DownloadStation、VideoStation 等服务的索引和历史数据,而这些都依赖于 pgsql-adapter.service 服务。

◢ 我观察了正常的 pgsql 数据库内容
root@NAS:/var/log# su - postgres
postgres@NAS:~$ psql
psql (11.11)
Type "help" for help.

postgres=# \l
                                             List of databases
      Name      |           Owner            | Encoding  |  Collate   |   Ctype    |   Access privileges
----------------+----------------------------+-----------+------------+------------+-----------------------
 download       | DownloadStation            | SQL_ASCII | C          | C          |
 mediaserver    | MediaIndex                 | UTF8      | en_US.utf8 | en_US.utf8 |
 ong            | SynologyApplicationService | SQL_ASCII | C          | C          |
 postgres       | postgres                   | SQL_ASCII | C          | C          |
 synodrive      | postgres                   | SQL_ASCII | C          | C          |
 synoffice      | office                     | SQL_ASCII | C          | C          |
 synofoto       | SynologyPhotos             | UTF8      | C          | C          |
 synoindex      | MediaIndex                 | SQL_ASCII | C          | C          |
 template0      | postgres                   | SQL_ASCII | C          | C          | =c/postgres          +
                |                            |           |            |            | postgres=CTc/postgres
 template1      | postgres                   | SQL_ASCII | C          | C          | =c/postgres          +
                |                            |           |            |            | postgres=CTc/postgres
 video_metadata | VideoStation               | SQL_ASCII | C          | C          |
(11 rows)

postgres=# \c synofoto
You are now connected to database "synofoto" as user "postgres".

synofoto-# \dt
                           List of relations
 Schema |                 Name                 | Type  |     Owner
--------+--------------------------------------+-------+----------------
 public | acl_permission                       | table | SynologyPhotos
 public | activity                             | table | SynologyPhotos
 public | address                              | table | SynologyPhotos
 public | administrative                       | table | SynologyPhotos
 public | album                                | table | SynologyPhotos
 public | aperture                             | table | SynologyPhotos
 public | background_task                      | table | SynologyPhotos
 public | burst_additional                     | table | SynologyPhotos
 public | camera                               | table | SynologyPhotos
 public | check_album_task                     | table | SynologyPhotos
 public | cluster                              | table | SynologyPhotos
 public | condition_album                      | table | SynologyPhotos
 public | config                               | table | SynologyPhotos
 public | delete_album                         | table | SynologyPhotos
 public | delete_condition_album               | table | SynologyPhotos
 public | delete_item                          | table | SynologyPhotos
 public | exposure_time                        | table | SynologyPhotos
 public | face                                 | table | SynologyPhotos
 public | file_operation_error                 | table | SynologyPhotos
 public | file_operation_task                  | table | SynologyPhotos
 public | filter                               | table | SynologyPhotos
 public | focal_length                         | table | SynologyPhotos
 public | folder                               | table | SynologyPhotos
 public | folder_operation_error               | table | SynologyPhotos
 public | folder_operation_task                | table | SynologyPhotos
 public | general_tag                          | table | SynologyPhotos
 public | geocoding                            | table | SynologyPhotos
 public | geocoding_info                       | table | SynologyPhotos
 public | group_info                           | table | SynologyPhotos
 public | index_queue                          | table | SynologyPhotos
 public | iso                                  | table | SynologyPhotos
 public | item                                 | table | SynologyPhotos
 public | lens                                 | table | SynologyPhotos
 public | live_additional                      | table | SynologyPhotos
 public | many_item_has_many_normal_album      | table | SynologyPhotos
 public | many_unit_has_many_administrative    | table | SynologyPhotos
 public | many_unit_has_many_general_tag       | table | SynologyPhotos
 public | many_unit_has_many_person            | table | SynologyPhotos
 public | metadata                             | table | SynologyPhotos
 public | mobile_config                        | table | SynologyPhotos
 public | normal_album                         | table | SynologyPhotos
 public | notification                         | table | SynologyPhotos
 public | one_filter_has_many_unit             | table | SynologyPhotos
 public | person                               | table | SynologyPhotos
 public | person_group                         | table | SynologyPhotos
 public | person_item_count                    | table | SynologyPhotos
 public | person_migration_mapping             | table | SynologyPhotos
 public | photo_request                        | table | SynologyPhotos
 public | search_timeline                      | table | SynologyPhotos
 public | share                                | table | SynologyPhotos
 public | share_permission                     | table | SynologyPhotos
 public | takentime                            | table | SynologyPhotos
 public | team_library_folder_has_many_sorting | table | SynologyPhotos
 public | team_library_group_permission        | table | SynologyPhotos
 public | team_library_user_permission         | table | SynologyPhotos
 public | thumb_preview                        | table | SynologyPhotos
 public | thumbnail                            | table | SynologyPhotos
 public | unit                                 | table | SynologyPhotos
 public | user_flag                            | table | SynologyPhotos
 public | user_info                            | table | SynologyPhotos
 public | version_time                         | table | SynologyPhotos
 public | video_additional                     | table | SynologyPhotos
 public | video_convert                        | table | SynologyPhotos
(63 rows)

目前看重建数据库似乎不会影响到数据,但应该会导致如 DownloadStation 下载记录丢失,并且还需花费大量时间重新构建索引。

我在重建数据库后确认了下,我的 DownloadStation、VideoStation 恢复了初始状态,SynologyPhotos 的相册、分类等信息丢失缩略图也需要重新生成。

群晖官方提供了一个用于重建数据库的脚本,但地址已无法下载。

https://ftp.synology.com/support_web/Tools/script/pgsql_analyzer.sh

还好,互联网档案馆收录了这个地址,目前可以从下面的地址下载这个脚本文件:

https://web.archive.org/web/20220112183140if_/https://ftp.synology.com/support_web/Tools/script/pgsql_analyzer.sh

下载后上传到 NAS 中,使用 bash pgsql_analyzer.sh -r 将会重建 pgsql 数据库。执行后需要重启 NAS。

2024年04月22日 更新:

pgsql_analyzer 脚本官方直连脚本:

curl -s https://supweb.synology.com/support_web/Tools/script/pgsql_analyzer.sh | sh -s -- -r

恢复数据耗费了 3 天,心累。目前 NAS 在炒豆子(重建索引)故障时插的内存条拿到另一台电脑上跑内存测试了,希望是内存故障引起的。不然 btrfs 存储真不敢用了😭

附 ChatGPT:在使用 btrfs 文件系统的服务器上,当没有 ECC 的内存出现故障时是否会影响 btrfs 内的数据?

在使用 btrfs 文件系统的服务器上,如果使用的是没有 ECC(Error-Correcting Code)功能的内存,并且这些内存出现故障,那么确实存在可能影响 btrfs 文件系统中数据的风险。因为 ECC 内存可以检测并修正内存中的一些错误,没有 ECC 的内存则缺乏这一层额外的保护措施。

当非 ECC 内存发生故障时,可能出现的问题包括:

  1. 丢失或损坏的数据:如果内存中保存的文件数据在写回磁盘之前发生错误,这些错误可能传递到文件系统并导致数据损坏。
  2. 文件系统结构损坏:内存中元数据的损坏可能会直接影响到文件系统的结构,导致无法挂载或错误地操作文件系统。
  3. 操作系统崩溃:某些内存错误可能导致操作系统的关键组件失败,这可能会引发系统崩溃或其他不稳定的行为。
  4. 未定义的行为:内存错误引发的行为很多是不预测的,这可能包括错误的系统计算、脚本执行错误,甚至是安静的数据损坏,这种损坏最为危险,因为它可能不会立即被检测到。

尽管 btrfs 提供了若干保护数据完整性的特性,如校验和、副本和快照,但这些特性通常是在数据已经被正确写入存储介质后才能发挥作用。如果内存发生故障并导致错误数据被写入,那么这些特性可能无法完全防止数据损坏。

因此,在不使用 ECC 内存的环境中,重要的防范措施应包括:

  • 使用高品质的内存模块:尽管没有 ECC,高品质的内存模块仍旧能够提供相对较高的可靠性。
  • 定期进行内存测试:使用如 Memtest86+ 等工具可以帮助检测内存中的错误。
  • 定期备份:保持数据的定期备份是预防故障引起的数据丢失的关键策略。
  • 监控系统日志:关注系统日志,如 /var/log/messages,可能有助于早期检测内存问题的迹象。

总体上,没有 ECC 功能的内存确实增加了数据损坏的风险,特别是在文件系统如 btrfs 这样重度依赖内存操作的情况下。在无法使用 ECC 内存的情况下,应该通过上述措施来尽量减小风险。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据