冬季开始之前就是各种收拾装备的时间了。 对滑雪这个项目来说,是一个装备比较多的项目,所以在每年的训练季或者说是滑雪季开始之前,各种展会就开始了。 通常这种小展会的规模并不是很大,多是在具体的滑雪场举办。 https://www.isharkfly.com/t/topic/14752
冬季开始之前就是各种收拾装备的时间了。 对滑雪这个项目来说,是一个装备比较多的项目,所以在每年的训练季或者说是滑雪季开始之前,各种展会就开始了。 通常这种小展会的规模并不是很大,多是在具体的滑雪场举办。 https://www.isharkfly.com/t/topic/14752
3 天前,运行的社区系统报告,很多老的历史照片都无法作为附件加载 —— 小鲨鱼,快来解决问题。 很多人都问题,为什么程序员每天不是在调 Bug 就是在调 Bug 的路上。 其实呀,计算机是一个逻辑性非常强的东西,每一步都应该是原因的,所以我们要通过逻辑性找到不同的原因。 这个和把大象关进笼子里有几步差不多。 调试的方法其实就是针对问题去找到原因,为什么会出现这个问题。 对 Web 系统来说,无非就是程序和数据,首先需要确定数据丢了没有,如果数据丢了,怎么调试都没有用,因此先恢复数据,保障系统运行永远是第一位的。 Step 1 有没有快速的解决方案 为什么会出现这个问题,不是好好的吗?原来是因为更换了域名,同时更换了云存储的存储路径。 现在问题就是主题中的内容都没有丢,但是当主题重新生成 HTML 后,只要主题中有附件的部分,全部都没有正确生成 HTML。 快点检查存储在云端的附件有没有被删掉。找到一个老的主题已经生成的 HTML,然后检查丢失的图片对比的服务器地址。 云存储的附件都还在,没有被丢掉,如果直接把绝对 URL 拷贝过来,问题就解决了。 赶紧的,有备份吗? 有备份,赶快恢复一次。 Step 2 数据恢复 恢复备份后无法解决问题。 备份恢复了,问题依旧。怎么办? 有多少主题被影响到? 往前面找 3 个月,1 个月,2 个星期的随机帖子,貌似各种情况都有,但是大量丢的都在 几个星期之前的,几乎都无法显示。 那应该是在生成 HTML 的短 Hash 代码转码回去的时候出现问题了。 这个数量已经非常大了,没有办法通过手工恢复的方式完成了。 这里有个判断,如果只影响到几个主题,通常我们都可以手工恢复的,如果影响的主题超过几十个,这个时候是没有办法手工恢复,只能找到原因让程序去做了。 Step 3 调试存储桶路径 因为我们知道存储桶路径换了,是不是因为存储桶的名字问题呢? 把服务器上存储桶的名字重新改回来,问题依旧。 现在这个和存储桶的路径应该没有太大的关系。 Step 4 调试 Hash 算法 是不是因为在 Base 62 Hash 算法的时候因为 SHA1 的不同而导致了算法没有被正常解码? 读了下程序,貌似问题也不在这里。 这个 Base62 算法,程序中没有加摘要扰乱计算。 Step 5 查询数据库的数据 现在我们得从数据库查看了,因为没有办法确定到底是程序还是数据的问题。 貌似在备份前 3 天的数据是好的,我们应该要把数据库的数据恢复下看看。 服务器现在在运行的,好在新加的主题没有问题,那就让服务器运行着吧。 我们把服务器上的数据 Dump 下来,导入到我们本地的 PGSQL 数据库中吧。 这个导入过程可能要一天也可能是几个小时,因为导入数据比较容易出错。 Step 6 如何进入服务器 Docker 容器内查询 数据本地拿到了,Hash 前的和 Hash 后的数据都在呀,那问题在哪呢? 到 Docker 容器内去查询下现有的服务器数据吧。 这个时候,你就可能需要时间去了解下如何进入 Docker,如何在 Docker 连接数据库后运行 SQL。 因为这个库是在容器内的,你是没有办法通过其他数据库工具直接连接到数据库上运行 SQL 的,通常生成服务器也不允许你这么做。 查询的结果,发现是本地有的记录,服务器上没有。 大概率知道数据库映射出了问题。 Step 7 把本地的备份数据恢复 1 条 把本地备份的 1 条数据恢复到服务器上,然后刷下效果,看是不是就是因为数据丢了? 太棒了,恢复的这条数据被显示出来了,主题正常了。 原来就是丢数据了,备份不应该是备份全部的吗?看来应该是恢复哪里或者某个表出问题了。 Step 8 获得具体有多少数据被影响 因为我们知道那个表现在有问题了, Select Count(*) 呗。 发现一共了 4000 多条记录被影响。 赶紧把本地的这些记录组织成 SQL 到服务器上运行吧,都是 Insert 应该问题大。哪怕是重复数据,因为有 Key,重复数据会被忽略掉。 导入后问题解决了。 Step 9 解决问题后 2 天同样的问题又出现了 先查 Count,后来发现 Count 数据被删掉了 2000 多。 这肯定是有自动运行进程对数据进行清理了。 上网考古下,发现貌似有一个无用附件清理进程会对程序认为无用的附件进行清理。 先不管了,把这 2000 多条数据恢复再说。 Step 10 关闭清理进程 先关闭清理进程,然后看为什么这个程序会把我们实际是需要的数据给清理掉? 读代码,在清理之前,程序会判断那些数据是需要清理的,这里有一个 Join 的 SQL 查询。 这里 Join 了另外一个表。 Step 11 对比 JOIN 表数据量 马上对比另外表的数据量。 这里了明显又丢了好几千条记录。 原来在主题和附件的关系映射表中的数据丢了部分,导致整个附件表的有用数据被当做无效数据清理掉了。 Step 12 数据恢复 把 JOIN 的映射表数据进行恢复。 然后等待重构运行结果,保持清理进程开启,2 天后查看结果。 同时增加服务器备份数量,从保留 30 天的备份,到现在增加到保留 300 天。 Step 13 问题总结和记录 把整个过程总结下来,花个 10 多分钟记录下问题。 上面是针对一个问题进行调试的小过程,如果你对系统比较熟悉的话,很快就会定位到映射部分。如果对系统不熟悉的话,上面的步骤就是一个几乎完整的 Debug 流程。 在上面的流程中到处都是坑,这就是为什么有些人看起来只需要几个小时或者几分钟就解决问题了,你却用了几天的时候,甚至几天都没有进展。 相信我,不是因为你不够优秀,仅仅是因为你对已有的这套系统的设计,数据,逻辑不熟悉而已,这没什么大不了的,时间问题。 https://www.isharkfly.com/t/topic/14724
群晖(Synology)NAS 的后台在新版本对 Docker 不再称为 Docker,现在改称为 Container Manager 了。 单击进入后运行 Container Manager。 PostgreSQL 容器 针对 PostgreSQL 的容器,我们选择容器后,如果你已经安装了 PostgreSQL 的话,应该就能看到运行的容器了。 然后选择设置。 在 PostgreSQL 的容器设置中有 2 个参数比较重要。 端口 第一个是 PostgreSQL 的端口,默认是 5432,但是不知道为什么我的 NAS 提示 5432 端口被占用了。 所以我还必须使用另外端口来进行映射。 我选择的端口是 5433 来进行映射。 在局域网中,我们需要端口 5433 来链接运行在 5422 的 PostgreSQL 服务。 环境变量 另外一个重要的环境变量是 POSTGRES_PASSWORD,这个是连接 PostgreSQL 的默认密码。 如果这个变量不设置的话,PostgreSQL 容器是没有办法启动的。 当上面的 2 个参数被设置好以后,PostgreSQL 容器应该可以运行的了。 然后使用 pgAdmin 进行连接测试。 https://www.isharkfly.com/t/synology-nas-docker-postgresql/14719
最近我们有一个 SQL 需要导入到 PostgreSQL ,但数据格式使用的是用: -- -- TOC entry 7877 (class 0 OID 21961) -- Dependencies: 904 -- Data for Name: upload_references; Type: TABLE DATA; Schema: public; Owner: - -- COPY public.upload_references (id, upload_id, target_type, target_id, created_at, updated_at) FROM stdin; 45698 760 Post 667 2023-05-05 04:11:35.947138 2023-05-05 04:11:35.947156 42396 6674 Post 3903 2023-05-05 01:59:37.447183 2023-05-05 01:59:37.447202 45699 761 Post 667 2023-05-05 04:11:35.947163 2023-05-05 04:11:35.947167 \. 这样的格式。 这样的格式只能使用 psql 来进行导入。 注意到上面有一个 COPY FROM stdin; 这个是 psql 的专用导入格式。 导入的命令为: psql -h 127.0.0.1 -p 5433 -U username -W -d database name < dump.sql 我们在导入的命令中加入了不少的参数。 有关 psql 的参数列表,请参考文章:PostgreSQL: Documentation: 15: psql. 上面的参数中: -h 服务器地址 -p 数据库服务器运行端口 -U 登录用户名 -W 登录密码 -d 数据库名 当导入开始后,在控制台上,会出现导入结果。 数据提示 在导入的数据库,中我们发现 PostgreSQL 使用的 COPY Stdin。 在数据的默认有一个数据终止符 \.。 这个数据终止符是不能丢的。 https://www.isharkfly.com/t/postgresql-psql-sql/14720
Discourse 提供了较为完善的日志查看方式。 用得最多的可能就是 Logster 的基于 Web 的 UI 了。 Logster Discourse 的错误日志面板用的是 logster,采集的是 Rails/Rack 的日志,正常应该用 Rails::Logger 但是 discourse 做了封装。 正常的访问地址为你的域名后面添加 logs。 例如,可以访问域名后面添加 logs 的地址。 但需要注意的是,你需要登录系统,具有系统管理员的访问权限才可以。 否则将会出现页面没有找到的错。 系统日志 和所有系统一样,Discourse 使用了 nginx 为 Web 服务器。 这个日志不会显示在 logster 上面的。 你需要进入你的服务器后才能看到。 Discourse 做了系统的优化,把系统使用的日志卷给映射出来了,你并不需要进入容器才能看到日志。 举个例子,我们希望看见 nginx 的 access 访问日志。 那么在你的服务器上可以直接访问: /var/discourse/shared/standalone/log/var-log/nginx 这个地址就可以了。 所有容器中的日志,也可以通过上面的路径查看到,你并不需要进入 Discourse 的容器内。 https://www.isharkfly.com/t/discourse/14715
在需要了解 Discourse 如何访问数据库之前我们需要了解的是 Discourse 的所有软件都使用的是 Docker 容器。 因此我们必须要进入到 Docker 容器后才能访问 Discourse 内部的东西。 进入 Discourse 容器 进入 Discourse 容器的命令是 cd /var/discourse/ ./launcher enter app 进入 PostgreSQL 进入容器后再运行 sudo -u postgres psql discourse 命令就可以进入 psql 的控制台了。 在这个控制界面中,你可以输入 SQL 语句进行查询了。 例如我们可以运行 select count(*) from topics; 这个 SQL 来查看当前你的运行实例中有多少个主题。 在 Discourse 容器内部运行查询的命令和如何进入后执行 SQL。 https://www.isharkfly.com/t/discourse/14716
根据官方的这个主题:Configure an S3 compatible object storage provider for uploads - sysadmin - Discourse Meta Discourse 可以支持很多不同的对象存储。 感觉上是只要和 S3 兼容的基本上都能用。 建议 从对象存储的角度考虑,还是建议使用 S3。 因为这个 S3 的对象存储可以 CloudFont 进行集成,不仅仅是提供对象存储,同时还可以提供 CDN 服务。 对于其他的对象存储,没有怎么用过,所以不是非常熟悉。 我们,使用的 S3 对象存储,对我们来说可以获得非常大的存储空间,同时不依赖程序的重新部署,想象下你的 Discourse 可能有超过 10 万的主题,平均下来,每个主题可能有 1 个图片或者附件。 这样你的附件也轻轻松松超过 10 万。 对于这个数据量,我们认为还是属于比较基本的数据量。 对比 Discourse 的官方,昨天我们才发的帖子,估计目前的数据量应该超过了 27 万。 因为 Discourse 的设计,主题的 ID 使用数据库的 Sequence 来进行自增的。 对于一个网站的数据量,Discourse 还是比较好估计的。 https://www.isharkfly.com/t/discourse/14717
支持主题的数量和 ID 使用的数据类型有关。 根据我们从 Discourse 上 dump 出来的 SQL,我们看到 Discourse 的官方使用 Integer 作为 ID 的数据类型。 随后,我们查看了 pgsql 的官方文档,integer 是 4 字节的,能够存储的最大值为:2147483647。 对 Discourse 来说,这个值应该是够用了。 对数据量来说,应该还是不太可能有机会出现溢出的情况。 https://www.isharkfly.com/t/discourse/14718
近期,我们在对 Discourse 进行恢复的时候,我们发现新的备份可能会导致不是所有的数据都能恢复到服务上。 这时候我们应该考虑让 Discourse 保留多少备份的问题? 在默认情况下,我们设置 Discourse 的备份是保留 5 个。这是官方的默认值。 现在我们觉得这个值应该是太低了,如果系统运行故障,你希望找到以前老的备份,可能找不到。 建议值 我们建议这个至少应该保留 90 天到半年以上。 通常我们不会追太久的数据,但是丢数据了也非常麻烦,尤其是不少网站访问频率比较高的情况下。 所以这个值我会设置到 600, 让服务器上保留 600个备份,因为我们每天备份 1 次,所以这里能够差不多保留 2 年的数据。 Discourse 最多只能每天备份,Discourse 没有办法做到上午和下午同时备份。 https://www.isharkfly.com/t/discourse/14714/1
Discourse 对上传的附件会进行清理,对于一些没有任何被引用的附件,Discourse 会认为是垃圾而清理掉。 原因应该是为了降低存储空间的使用,但是我们目前使用的是 S3 ,所以对存储空间并没有太多的要求。 根据官方的说法,如果满足下面的条件的上传附件将会被清理掉: https://github.com/discourse/discourse/blob/master/app/jobs/scheduled/clean_up_uploads.rb TL;DR: an image is orphaned if and only if it’s not referenced in the latest version of a post in a draft in a queued post in a logo site setting in a custom emoji in a theme in a user avatar/background/card image in a category logo/background image 官方的讨论地址为:How to make an image orphaned so that it gets removed? - support - Discourse Meta 通过代码,我们会看到,Discourse 使用了一个查询来判断附件是否被引用。 这个表是:upload_references 如果附件没有被关联到主题中,这个附件就会被认为是没有关联的附件而被清理掉。 根据我们备份恢复的情况来看,我们估计可能是这个表 upload_references 丢数据了,导致 uploads 中标的数据被清理掉了。 本地查询 我们本地查询了下操作前 3 天的记录。 发现这个表中有:9000 多条记录。 服务器查询 同时,我们对服务器上的表进行了查询。 查询结果返回的是:6000 多。 很明显这里有差距,那肯定是在恢复的过程中可能丢数据了。 我们需要做的就是把本地表中的数据恢复到服务器上。 运行 SQL: select count(*) from upload_references; 来查看下服务器上的记录,貌似服务器上的参考引用全部被恢复了。 因为我们禁用了自动清理程序,所以我们现在应该可以把自动清理进程打开了。 https://www.isharkfly.com/t/discourse/14713