1. 程式人生 > >Storm工程在初始化Spring環境時的問題

Storm工程在初始化Spring環境時的問題

問題描述

某個工程在啟動時報如下錯誤

Worker is dead on 10.237.65.30:6804,20181213154018, at 2018-12-13 15:40
org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [applicationContext-act.xml]; nested exception is java.io.IOException: Stream closed , at 2018-12-13 15:40
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(
XmlBeanDefinitionReader.java:410) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(
AbstractBeanDefinitionReader.java:181) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:252) at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127) at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93) at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:129) at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:613) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:514) at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:93) at com.xxx.SpringContext.init(SpringContext.java:14)(業務類)

或者是這種

org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from class path resource [applicationContext-act.xml]; nested exception is java.lang.IllegalStateException: zip file closed , at 2018-12-13 16:30
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:414)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:252)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127)
at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93)
at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:129)
at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:613)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:514)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:93)

問題以一定概率出現(最頭痛的情況),但是能夠正常啟動。報的檔案也不固定。因為xml裡又import了多個xml。
其實也許這是一個無傷大雅的問題,但是我們不能這樣的無視。誰知道哪天故障了系統崩潰這就成為你背鍋的理由呢。作為程式設計師,我們確實不能交付一個使用者有感知的BUG的系統並對這個BUG一無所知。
業務所提交的程式碼是這個樣子的。

public class SpringContext {

    public static ApplicationContext context;

    public static synchronized  void init() {
        if (context == null) {
            context = new ClassPathXmlApplicationContext(new String[]{
                    "applicationContext-act.xml"
            });
        }
    }

在每一個bolt的啟動前初始化context。利用JAVA的static模式保證單例模式。並加了鎖。看樣子真是一點問題都沒有。

問題排查

上述程式碼嚴格來說並非沒有問題。因為指令重排的原因,context可能在初始化完成前就已經發布。可能會有執行緒讀到別的執行緒沒有初始化完成的context。不過這無法解釋為什麼會出現流錯誤。
Storm會在nimbus端初始化bolt物件,然後序列化到各個節點。在執行bolt的pepare。同時把jar報作為一個檔案傳遞給不同的節點。不同的worker上,其所謂的流,都是指自己的檔案系統的該XML檔案(Spring配置)。
我們也並非不熟悉StreamClosed這個異常。多個執行緒索引同一個inputstream時,當某一個thread在執行完之後,把這個inputstream關閉了;而此時正在從這個input stream流中讀取資訊的執行緒就會丟擲 java.io.IOException: Stream closed 異常。

public
class InflaterInputStream extends FilterInputStream {
    private boolean closed = false;
    /**
     * Check to make sure that this stream has not been closed
     */
    private void ensureOpen() throws IOException {
        if (closed) {
            throw new IOException("Stream closed");
        }
    }
    public void close() throws IOException {
        if (!closed) {
            if (usesDefaultInflater)
                inf.end();
            in.close();
            closed = true;
        }
    }

很遺憾,我們沒辦法本地復現這個錯誤。我們也缺乏重寫JDK加入日誌的勇氣。依然沒有頭緒。