Docker容器阻塞内的Apache Batik Transcoder

时间:2017-12-06 00:08:50

标签: java docker svg apache-fop batik

我们在docker容器中运行Spring应用程序。我们的应用程序可以获取SVG文件并将其转换为PDF格式以嵌入PDF中。

应用程序可以按预期在osx和转码上正常运行。但是,当从具有不同文件系统的docker容器内部运行时,代码转换器会卡住并在一些奇怪的递归文件搜索循环中使cpu崩溃。

java.lang.Thread.State: RUNNABLE
    at java.io.UnixFileSystem.getBooleanAttributes0(Native Method)
    at java.io.UnixFileSystem.getBooleanAttributes(UnixFileSystem.java:242)
    at java.io.File.isFile(File.java:882)
    at org.apache.commons.io.filefilter.FileFileFilter.accept(FileFileFilter.java:59)
    at org.apache.commons.io.filefilter.AndFileFilter.accept(AndFileFilter.java:122)
    at org.apache.commons.io.filefilter.AndFileFilter.accept(AndFileFilter.java:122)
    at org.apache.commons.io.filefilter.OrFileFilter.accept(OrFileFilter.java:118)
    at java.io.File.listFiles(File.java:1291)
    at org.apache.commons.io.DirectoryWalker.walk(DirectoryWalker.java:357)
    at org.apache.commons.io.DirectoryWalker.walk(DirectoryWalker.java:364)
    at org.apache.commons.io.DirectoryWalker.walk(DirectoryWalker.java:364)
    at org.apache.commons.io.DirectoryWalker.walk(DirectoryWalker.java:364)
    at org.apache.commons.io.DirectoryWalker.walk(DirectoryWalker.java:364)
    at org.apache.commons.io.DirectoryWalker.walk(DirectoryWalker.java:364)
    at org.apache.commons.io.DirectoryWalker.walk(DirectoryWalker.java:364)
    at org.apache.commons.io.DirectoryWalker.walk(DirectoryWalker.java:364)
    at org.apache.commons.io.DirectoryWalker.walk(DirectoryWalker.java:364)
    at org.apache.commons.io.DirectoryWalker.walk(DirectoryWalker.java:364)
    at org.apache.commons.io.DirectoryWalker.walk(DirectoryWalker.java:364)
    at org.apache.commons.io.DirectoryWalker.walk(DirectoryWalker.java:364

这里是一个运行PDFTranscoder的线程的堆栈跟踪。 Walk被称为递归调用一段时间,然后最终调用getBooleanAttributes0并且所有内容都会阻塞。

经过一些进一步的研究后,我们发现我们可以仔细研究一下strace命令发生了什么,并发现系统基本上是在无限循环中发送垃圾邮件。

STAT(“/./ SYS /设备/ pci0000:00 / PNP0103:00 /子系统/设备/ PNP0103:00 /子系统/设备/ PNP0103:00 /子系统/设备/ PNP0103:00 /子系统/设备/ PNP0103 :00 /子系统/设备/ PNP0103:00 /子系统/设备/ PNP0103:00 /子系统/设备/ PNP0103:00 /子系统/设备/ PNP0103:00 /子系统/设备/ PNP0103:00 /子系统/设备/ PNP0103:00 /子系统/设备/ PNP0103:00 /子系统/设备/ PNP0103:00 /子系统/设备/ PNP0103:00 /子系统/设备/ PNP0103:00 /子系统/设备/ PNP0103:00 /子系统/设备/ PNP0103:00 /子系统/ devices / PNP0103:00 / subsystem / devices / pcspkr / input / input1 / subsystem / input0 / subsystem / input0 / uniq“,{st_mode = S_IFREG | 0444,st_size = 4096,...})= 0< 0.000224> ;

我们似乎被阻止或挂在stat调用中。但是我们已经深入研究了系统调用,因为它很难调试。有没有人有任何想法?

5 个答案:

答案 0 :(得分:3)

我得到了同样的错误。在尝试了很多东西来修复之后,我得出的结论是,在Mac OS X上你可以使用字体是个问题,而你的(无头)Docker容器操作系统没有字体。在整个地方搜索字体时,代码转换器没有正常失败。我通过强制转码器use the default fonts(以及不自动寻找其他字体)解决了这个问题:

...
PDFTranscoder transcoder = new PDFTranscoder();
transcoder.addTranscodingHint(PDFTranscoder.KEY_AUTO_FONTS, false);
...
transcoder.transcode(transcoderInput, transcoderOutput);
...

请注意,当遇到14种字体之外的字体时,这有一个缺点。我试着解决这个问题,但到目前为止没有运气。

我希望这有助于某人。

答案 1 :(得分:2)

我遇到了同样的问题,并就我的情况解决了。这个线程很有帮助。现在,我想将所有部分放在一起-也许也适合那些遇到此问题的其他人。

这样做的原因是您在其中启动Java应用程序的目录。我认识到在以下情况下会发生此问题:

  • 该Java应用程序是在文件系统根目录中启动的。
  • 在Apache FOP中启用了字体自动扫描。

我在Infinite scan for fonts in Apache FOP on CentOS中找到了类似的帖子。费奥多尔·谢斯托比托夫的解释听起来很合理。

Apache FOP使用Java应用程序的工作目录来扫描字体。在这种情况下,这是文件系统根目录。因此将扫描整个文件系统。

以下代码是从PDFDocumentGraphics2DConfigurator复制而来的。它显示使用了new File(".").getAbsoluteFile().toURI()-这是工作目录。启动Java应用程序的目录。

    /**
     * Creates the {@link FontInfo} instance for the given configuration.
     * @param cfg the configuration
     * @param useComplexScriptFeatures true if complex script features enabled
     * @return the font collection
     * @throws FOPException if an error occurs while setting up the fonts
     */
    public static FontInfo createFontInfo(Configuration cfg, boolean useComplexScriptFeatures)
        throws FOPException {
        FontInfo fontInfo = new FontInfo();
        final boolean strict = false;
        if (cfg != null) {
            URI thisUri = new File(".").getAbsoluteFile().toURI();
            InternalResourceResolver resourceResolver
                    = ResourceResolverFactory.createDefaultInternalResourceResolver(thisUri);
            //TODO The following could be optimized by retaining the FontManager somewhere
            FontManager fontManager = new FontManager(resourceResolver, FontDetectorFactory.createDefault(),
                    FontCacheManagerFactory.createDefault());

            //TODO Make use of fontBaseURL, font substitution and referencing configuration
            //Requires a change to the expected configuration layout

            DefaultFontConfig.DefaultFontConfigParser parser
                    = new DefaultFontConfig.DefaultFontConfigParser();
            DefaultFontConfig fontInfoConfig = parser.parse(cfg, strict);
            DefaultFontConfigurator fontInfoConfigurator
                    = new DefaultFontConfigurator(fontManager, null, strict);
            List<EmbedFontInfo> fontInfoList = fontInfoConfigurator.configure(fontInfoConfig);
            fontManager.saveCache();
            FontSetup.setup(fontInfo, fontInfoList, resourceResolver, useComplexScriptFeatures);
        } else {
            FontSetup.setup(fontInfo, useComplexScriptFeatures);
        }
        return fontInfo;
    }

您可以通过两种方式解决此问题:

  • 如Bob Schultz所述,禁用自动扫描Apache FOP中的字体。如果这样做,则必须手动配置Apache FOP的字体。
  • 不要像snyman所说的那样在文件系统根目录中启动Java应用程序。在这种情况下,您可以继续使用自动扫描字体。

禁用自动扫描

这是代码段,该代码使用配置文件配置Apache FOP。如果您未在该文件中启用自动扫描,则无需以编程方式将其禁用。

// Load configuration for manually configuring fonts
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
Configuration cfg = cfgBuilder.build(ResourceUtil.getResourceStream("path/to/config"));

PDFTranscoder transcoder = new PDFTranscoder();
transcoder.configure(cfg);
// Disable auto scanning for fonts programatically - not necessary if you
// don't enable auto scan in your config file
// transcoder.addTranscodingHint(PDFTranscoder.KEY_AUTO_FONTS, false);

在单独的文件夹中启动应用程序

通过指定WORKDIR,所有内容均在此文件夹中发生。自动扫描在那里运行,并且快速,流畅地完成。

FROM openjdk:8-jre-alpine

WORKDIR /app

ARG JAR_FILE=target/myapp-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
...
ENTRYPOINT ["java","-jar","app.jar"]

答案 2 :(得分:0)

我的项目遇到了同样的问题。我通过将蜡染降级到1.7版来解决它。

我希望这对你有用。

答案 3 :(得分:0)

尝试将参数'-Duser.dir = /%CATALINA_HOME /'添加到您的CATALINA_OPTS。我在centos服务器上遇到了同样的问题。

答案 4 :(得分:0)

有同样的问题。 通过在DockerFile中设置WORKDIR变量来解决它。 我将它设置为我的部署目录,我复制了spring jar文件。 即

WORKDIR ${DEPLOYMENT_DIR}

在pom中使用最新的蜡染库

    <dependency>
        <groupId>org.apache.xmlgraphics</groupId>
        <artifactId>batik-all</artifactId>
        <version>1.9.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.xmlgraphics</groupId>
        <artifactId>fop</artifactId>
        <version>2.2</version>
    </dependency>