使用gotenberg提供LibreOffice文档类型转换服务word转pdf 解决context deadline exceeded 503问题
本文一起做的事:
- 解决
convert to PDF: supervisor run task: context deadline exceeded503 504 timeout 异常 - 部署 gotenberg 服务提供 api 接口,实现 word 等 office 文件转换成 pdf 文件的功能。内部实现是 LibreOffice。
- 使用负载均衡模式,来解决 LibreOffice 处理任务锁住导致并发上不去的问题。
解决convert to PDF: supervisor run task: context deadline exceeded 503/504/timeout异常
部署服务很简单可以直接往下看,这里我们先说解决这个异常,这个是最棘手的。
问题现象
现象出现在,需要处理很多文档的解析,有很多不通地区不同时间不同人不同电脑创建的office word文档,doc/docx 都有,需要转换成 pdf 文件再过 OCR 模型去解析,我使用 gotenberg 这个服务,能提供 api 接口并内部调用 LibreOffic 来实现 pdf 的转换,实际跑批时候发现这个服务经常出现 503/504/timeout 等问题,即使按照文档设置了接口超时到 3600s 也不行,同样会卡住 1h 然后提示超时。
表象是服务超时,但是 1h 还超时就肯定不对了,gotenberg 日志提示convert to PDF: supervisor run task: context deadline exceeded这里的 task 就是 LibreOffice 执行的,它异常,我认为 1h 已经是 LibreOffice 自己卡死了进入死循环了,那么为什么?什么会导致它卡死,为什么有的 word 正常,有的 word 不正常,这是我要找到的原因。
经过很长时间试错,直到我尝试对比多个 word 里包含的字体种类,我猜测是字体的原因。word 转 pdf 最容易出现的就是字体问题,比如 pdf 出现很多方框,还没想过缺少字体会把 LibreOffice 卡死。那么我尝试加上字体试试:
我们按照官网的方式重新打一个docker镜像 https://gotenberg.dev/docs/configuration#fonts
编写Dockerfile文件:
1 | FROM gotenberg/gotenberg:8.23.1 |
- ./fonts/* 目录里是我当前 windows10 电脑里的所有字体,都是 ttf 文件。目录在
C:\Windows\Fonts直接全选复制粘贴到我们的这个文件夹里。 - fonts-noto-color-emoji 是 emoji,没啥用但是加上吧还是。
- fontconfig 是一个字体管理工具,必须的。
- fonts-wqy-zenhei 文泉驿正黑,一个高质量的开源中文字体,覆盖了大部分汉字。
- fonts-noto-cjk 谷歌的思源字体,同时支持中文、日文和韩文,是处理多语言文档的理想选择。能够保障覆盖绝大多数字体。
- fonts-arphic-gkai00mp 文鼎 PL 简报楷,高质量的楷体字体。
- fonts-arphic-gbsn00lp 文鼎 PL 简报宋,高质量的宋体字体。
- fonts-symbola 包含大量 Unicode 符号和特殊字符,对于处理数学公式或特殊符号的文档很有帮助。
- ttf-mscorefonts-installer 包含微软常用的核心字体,如 宋体 (SimSun)、黑体 (SimHei)、Times New Roman 等。这个包能很好地解决 Word 文档兼容性问题。gotenberg原始镜像里包含这个工具,所以我没有重新装。
你要问上边这些怎么选出来的:Gemini给的。
fc-cache -f -v是使用 fontconfig 刷新系统字体缓存。
注意官方最后还是用了USER gotenberg,但是这里我不用,仍然用 root 账户。
然后我们编写docker-compose.yml文件
1 | services: |
编写 gotenberg 的环境变量文件.env
1 | API_TIMEOUT=240s # gotenberg api接口内部超时时间 |
我们编译新的镜像,并启动服务
1 | docker compose build |
这时候再跑之前老转换超时的 word 文件,应该就能解决问题。
配置负载均衡模式提高服务并发
LibreOffice 自己带锁,一次只跑一个任务,所以我们要上 nginx,启动多个 gotenberg 实例来负载均衡。
编写docker-compose.yml文件:
1 | services: |
也可以用云原生docker命令直接启动多个实例。我懒,所以不用。
编写nginx.conf文件:
1 | upstream gotenberg_backend { |
编写 gotenberg 的环境变量文件.env
1 | API_TIMEOUT=480s # gotenberg api接口内部超时时间 |
注意这里的 API_TIMEOUT 数值,要和 nginx.conf 里的 timeout 值都写相同值。
最后我们编译镜像并启动容器即可使用。
其他
官方文档 https://gotenberg.dev/docs/configuration
我给官方提的 QA,官方也搞不清楚怎么解决 https://github.com/gotenberg/gotenberg/discussions/1335