每日一博 | Trafodion null 问题的源码级剖析

   2017-02-05 0
核心提示:一、问题描述无论是通过 JDBC 还是通过 命令行连接 Trafodion ,总是偶尔出现 unable to evaluate address TCP:null 的异常。二、错误信息org.trafodion.jdbc.t4.HPT4Exception: Unable to evaluate address TCP:null:1.$Z010B5Z,null/23403:ODBC Cause: null

一、问题描述

无论是通过 JDBC 还是通过 命令行连接 Trafodion ,总是偶尔出现 unable to evaluate address TCP:null 的异常。

二、错误信息

org.trafodion.jdbc.t4.HPT4Exception: Unable to evaluate address TCP:null:1.$Z010B5Z,null/23403:ODBC Cause: null
Connecting to database...
	at org.trafodion.jdbc.t4.HPT4Messages.createSQLException(HPT4Messages.java:284)
	at org.trafodion.jdbc.t4.HPT4Messages.createSQLException(HPT4Messages.java:232)
	at org.trafodion.jdbc.t4.Address.validateAddress(Address.java:97)
	at org.trafodion.jdbc.t4.ConnectReply.fixupSrvrObjRef(ConnectReply.java:137)
	at org.trafodion.jdbc.t4.T4_Dcs_Connect.getConnection(T4_Dcs_Connect.java:98)
	at org.trafodion.jdbc.t4.InterfaceConnection.connect(InterfaceConnection.java:791)
	at org.trafodion.jdbc.t4.InterfaceConnection.<init>(InterfaceConnection.java:176)
	at org.trafodion.jdbc.t4.TrafT4Connection.makeConnection(TrafT4Connection.java:1611)
	at org.trafodion.jdbc.t4.TrafT4Connection.<init>(TrafT4Connection.java:1564)
	at org.trafodion.jdbc.t4.HPT4DataSource.getConnection(HPT4DataSource.java:132)
	at org.trafodion.jdbc.t4.HPT4DataSource.getConnection(HPT4DataSource.java:176)
	at org.trafodion.jdbc.t4.T4Driver.connect(T4Driver.java:186)
	at java.sql.DriverManager.getConnection(DriverManager.java:571)
	at java.sql.DriverManager.getConnection(DriverManager.java:215)
	at TrafodionConn.run(TrafodionConn.java:22)
	at TrafodionConn.main(TrafodionConn.java:81)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

三、问题分析

之前一直有个错误的想法,认为是 JDBC 驱动包的问题,一直在找Trafodion 的源代码来分析,追踪了好久都找不到问题所在

后来听同事说,用服务器的上的命令行连接也会报错,就测试了下发现果然报错(注意有两个错误信息),错误信息如下:

Host Name/IP Address: xdata67:23400
User Name: zz

*** ERROR[29111] Unable to evaluate address TCP:null:1.$Z010B5H,null/23402:ODBC Cause: null: 未知的名称或服务


*** ERROR[29111] Unable to evaluate address TCP:null:1.$Z010B5Z,null/23403:ODBC Cause: null

了解到这个信息就知道了不是 JDBC 驱动的问题,应该是 Trafodion 的某个服务异常导致的。

四、问题定位

  • 初步分析

通过观察,偶然发现 $Z010B5Z 这个很熟悉,好像在之前对 Trafodion 进行管理的时候见过。

立马在 Trafodion 安装的集群上 执行 sqps 命令,查看当前 Trafodion 的进程信息

[trafodion@xdata67 scripts]$ sqps
Processing cluster.conf on local host xdata67
[$Z00152S] Shell/shell Version 1.0.1 Apache_Trafodion Release 2.0.1 (Build release [DEV], date 24Jun16)
[$Z00152S] %ps  
[$Z00152S] NID,PID(os)  PRI TYPE STATES  NAME        PARENT      PROGRAM
[$Z00152S] ------------ --- ---- ------- ----------- ----------- ---------------
[$Z00152S] 000,00038200 000 WDG  ES--A-- $WDG000     NONE        sqwatchdog     
[$Z00152S] 000,00038201 000 PSD  ES--A-- $PSD000     NONE        pstartd        
[$Z00152S] 000,00038334 001 GEN  ES--A-- $TSID0      NONE        idtmsrv        
[$Z00152S] 000,00038349 001 DTM  ES--A-- $TM0        NONE        tm             
[$Z00152S] 000,00039024 001 GEN  ES--A-- $ZSC000     NONE        mxsscp         
[$Z00152S] 000,00039202 001 SSMP ES--A-- $ZSM000     NONE        mxssmp         
[$Z00152S] 000,00045613 001 GEN  ES--A-- $Z001288    NONE        mxosrvr        
[$Z00152S] 000,00045638 001 GEN  ES--A-- $Z00128Y    NONE        mxosrvr        
[$Z00152S] 000,00049097 001 GEN  ES--A-- $Z00152S    NONE        shell          
[$Z00152S] 001,00008006 000 WDG  ES--A-- $WDG001     NONE        sqwatchdog     
[$Z00152S] 001,00008007 000 PSD  ES--A-- $PSD001     NONE        pstartd        
[$Z00152S] 001,00008132 001 DTM  ES--A-- $TM1        NONE        tm             
[$Z00152S] 001,00008597 001 GEN  ES--A-- $ZSC001     NONE        mxsscp         
[$Z00152S] 001,00008702 001 SSMP ES--A-- $ZSM001     NONE        mxssmp         
[$Z00152S] 001,00013667 001 GEN  ES--A-- $Z010B5H    NONE        mxosrvr       --果然在这里    
[$Z00152S] 001,00013684 001 GEN  ES--A-- $Z010B5Z    NONE        mxosrvr       --果然在这里
[$Z00152S] 002,00026976 000 PSD  ES--A-- $PSD002     NONE        pstartd        
[$Z00152S] 002,00026975 000 WDG  ES--A-- $WDG002     NONE        sqwatchdog     
......

惊喜的发现了上面的信息,看信息应该是 mxosrvr 的进程名称,发现前面有进程的 pid 号,下一步通过 pid 查找 对应的 mxosrvr 在那台机器上,因为 Trafodion 是分布式是系统,各进程分布在集群各个机器上。【文末分析为什么连接 Trafodion 进程 会定位连接到 mxosrvr 进程,这里就不打断】

[trafodion@xdata67 scripts]$ pdsh -w xdata[67-71] ps -ef | grep 13684 | grep -v grep
xdata68: 503      13684 13483  0 09:31 ?        00:00:01 mxosrvr -ZKHOST xdata67:2181,xdata68:2181,xdata69:2181 -RZ null:2:1 -ZKPNODE /trafodion -CNGTO 60 -ZKSTO 180 -EADSCO 0 -TCPADD null -MAXHEAPPCT 0 -STATISTICSINTERVAL 60 -STATISTICSLIMIT 60 -STATISTICSTYPE aggregated -STATISTICSENABLE true -SQLPLAN true -PORTMAPTOSECS -1 -PORTBINDTOSECS -1
[trafodion@xdata67 scripts]$ pdsh -w xdata[67-71] ps -ef | grep 13667 | grep -v grep
xdata68: 503      13667 13456  0 09:31 ?        00:00:01 mxosrvr -ZKHOST xdata67:2181,xdata68:2181,xdata69:2181 -RZ null:2:2 -ZKPNODE /trafodion -CNGTO 60 -ZKSTO 180 -EADSCO 0 -TCPADD null -MAXHEAPPCT 0 -STATISTICSINTERVAL 60 -STATISTICSLIMIT 60 -STATISTICSTYPE aggregated -STATISTICSENABLE true -SQLPLAN true -PORTMAPTOSECS -1 -PORTBINDTOSECS -1

通过定位发现两个出错的 mxosrvr 都在 xdata68 这台机器上,第一时间的想法 - 难道只是巧合?

于是重启 Trafodion的 DCS服务(mxosrvr的名称会变) 又执行上面的流程测试了一遍,发现出错的mxosrvr 进程还是在 xdata68 机器上,这些肯定了应该不是偶然,和xdata68 这台机器的特殊环境应该有关系。

知道问题所在心里就有底多了,知道至少找对路了。这里可以总结一个问题定位心得 : 对于偶然出现的问题一定要找出问题的规律。

  • 深入分析

找到了出错的进程,就想这两个进程和其他机器上的正常的进程有什么区别呢?

于是就查了下 xdata68(异常机器)的 mxosrvr 进程信息:

[trafodion@xdata68 conf]$ ps -ef | grep mxosrvr
503      13456  9801  0 09:31 ?        00:00:00 /bin/sh -c cd /home/trafodion/apache-trafodion_server;. sqenv.sh;mxosrvr -ZKHOST xdata67:2181,xdata68:2181,xdata69:2181  -RZ null:2:2  -ZKPNODE "/trafodion"  -CNGTO 60  -ZKSTO 180  -EADSCO 0  -TCPADD null  -MAXHEAPPCT 0  -STATISTICSINTERVAL 60  -STATISTICSLIMIT 60  -STATISTICSTYPE aggregated  -STATISTICSENABLE true  -SQLPLAN true  -PORTMAPTOSECS -1  -PORTBINDTOSECS -1
503      13483  9801  0 09:31 ?        00:00:00 /bin/sh -c cd /home/trafodion/apache-trafodion_server;. sqenv.sh;mxosrvr -ZKHOST xdata67:2181,xdata68:2181,xdata69:2181  -RZ null:2:1  -ZKPNODE "/trafodion"  -CNGTO 60  -ZKSTO 180  -EADSCO 0  -TCPADD null  -MAXHEAPPCT 0  -STATISTICSINTERVAL 60  -STATISTICSLIMIT 60  -STATISTICSTYPE aggregated  -STATISTICSENABLE true  -SQLPLAN true  -PORTMAPTOSECS -1  -PORTBINDTOSECS -1
503      13667 13456  0 09:31 ?        00:00:02 mxosrvr -ZKHOST xdata67:2181,xdata68:2181,xdata69:2181 -RZ null:2:2 -ZKPNODE /trafodion -CNGTO 60 -ZKSTO 180 -EADSCO 0 -TCPADD null -MAXHEAPPCT 0 -STATISTICSINTERVAL 60 -STATISTICSLIMIT 60 -STATISTICSTYPE aggregated -STATISTICSENABLE true -SQLPLAN true -PORTMAPTOSECS -1 -PORTBINDTOSECS -1
503      13684 13483  0 09:31 ?        00:00:02 mxosrvr -ZKHOST xdata67:2181,xdata68:2181,xdata69:2181 -RZ null:2:1 -ZKPNODE /trafodion -CNGTO 60 -ZKSTO 180 -EADSCO 0 -TCPADD null -MAXHEAPPCT 0 -STATISTICSINTERVAL 60 -STATISTICSLIMIT 60 -STATISTICSTYPE aggregated -STATISTICSENABLE true -SQLPLAN true -PORTMAPTOSECS -1 -PORTBINDTOSECS -1
503      26101 57226  0 10:14 pts/1    00:00:00 grep mxosrv

xdata70 (正常机器) 的 mxosrvr 进程信息:

[trafodion@xdata70 conf]$ ps -ef | grep mxosrvr
503      55695 52775  0 09:31 ?        00:00:00 /bin/sh -c cd /home/trafodion/apache-trafodion_server;. sqenv.sh;mxosrvr -ZKHOST xdata67:2181,xdata68:2181,xdata69:2181  -RZ xdata70:4:2  -ZKPNODE "/trafodion"  -CNGTO 60  -ZKSTO 180  -EADSCO 0  -TCPADD 172.18.84.70  -MAXHEAPPCT 0  -STATISTICSINTERVAL 60  -STATISTICSLIMIT 60  -STATISTICSTYPE aggregated  -STATISTICSENABLE true  -SQLPLAN true  -PORTMAPTOSECS -1  -PORTBINDTOSECS -1
503      55772 52775  0 09:31 ?        00:00:00 /bin/sh -c cd /home/trafodion/apache-trafodion_server;. sqenv.sh;mxosrvr -ZKHOST xdata67:2181,xdata68:2181,xdata69:2181  -RZ xdata70:4:1  -ZKPNODE "/trafodion"  -CNGTO 60  -ZKSTO 180  -EADSCO 0  -TCPADD 172.18.84.70  -MAXHEAPPCT 0  -STATISTICSINTERVAL 60  -STATISTICSLIMIT 60  -STATISTICSTYPE aggregated  -STATISTICSENABLE true  -SQLPLAN true  -PORTMAPTOSECS -1  -PORTBINDTOSECS -1
503      56060 55695  0 09:31 ?        00:00:11 mxosrvr -ZKHOST xdata67:2181,xdata68:2181,xdata69:2181 -RZ xdata70:4:2 -ZKPNODE /trafodion -CNGTO 60 -ZKSTO 180 -EADSCO 0 -TCPADD 172.18.84.70 -MAXHEAPPCT 0 -STATISTICSINTERVAL 60 -STATISTICSLIMIT 60 -STATISTICSTYPE aggregated -STATISTICSENABLE true -SQLPLAN true -PORTMAPTOSECS -1 -PORTBINDTOSECS -1
503      56135 55772  0 09:31 ?        00:00:13 mxosrvr -ZKHOST xdata67:2181,xdata68:2181,xdata69:2181 -RZ xdata70:4:1 -ZKPNODE /trafodion -CNGTO 60 -ZKSTO 180 -EADSCO 0 -TCPADD 172.18.84.70 -MAXHEAPPCT 0 -STATISTICSINTERVAL 60 -STATISTICSLIMIT 60 -STATISTICSTYPE aggregated -STATISTICSENABLE true -SQLPLAN true -PORTMAPTOSECS -1 -PORTBINDTOSECS -1
503      61947 22497  0 10:14 pts/0    00:00:00 grep mxosrvr

通过对比发现 68 机器 有个RZ参数为null, 而 70 机器传了准确的值

每日一博 | Trafodion null 问题的源码级剖析

每日一博 | Trafodion null 问题的源码级剖析

对,就是这里了,终于找到问题了。

为什么 68 这台机器 这个 -RZ 参数会是 null 呢?这个参数从哪里传过来的?

面对这两个问题,就去继续扒。顺着 mxosrvr 的父进程ID就去找,发现 mxosrvr 是通过一个 sh 启动的,而这个 sh 又是谁启动的呢?

通过 sh 进程的父进程 ID 找到是如下一个进程

每日一博 | Trafodion null 问题的源码级剖析

通过我对 Trafodion 的了解和对以上信息的判断,上面找到的进程就是各个机器上的 DCS Server 进程,这个时候就必须补上Trafodion 的架构图了,不然后面没办法讲了

每日一博 | Trafodion null 问题的源码级剖析

每日一博 | Trafodion null 问题的源码级剖析

通过上面两种图,就可以很清晰的明白,mxosrvr 是由各个机器上的 Dcs Server 进程来启动的。理解了上面的信息,就来继续回答上面的问题,为什么 启动 mxosrvr 进程带的 -RZ 参数是 null 呢?

要回答这个问题,就只能深入到 Trafodion 的源代码了。来,源代码走起。

  • 源码分析

接下来就进入我们的源代码分析阶段,首先申明,这里分析的 Trafodion 源代码只是和我们问题相关的部分,所以大家看的时候显得有些跳脱,不过没关系,能解决我们的问题就可以。如果大家想对 Trafodion 有更深入的了解,还只能系统的去分析源码。

和本问题相关的源代码结构大致简化如下:

每日一博 | Trafodion null 问题的源码级剖析

了解了大概结构,接下来我们看和我们问题具体相关的地方,我们先找到,在代码什么地方会启动上面我们分析的 sh 命令,就下面这条,我们的 mxosrvr 进程就是这条命令启动的。

/bin/sh -c cd /home/trafodion/apache-trafodion_server;. sqenv.sh;mxosrvr -ZKHOST xdata67:2181,xdata68:2181,xdata69:2181  -RZ null:2:2  -ZKPNODE "/trafodion"  -CNGTO 60  -ZKSTO 180  -EADSCO 0  -TCPADD null  -MAXHEAPPCT 0  -STATISTICSINTERVAL 60  -STATISTICSLIMIT 60  -STATISTICSTYPE aggregated  -STATISTICSENABLE true  -SQLPLAN true  -PORTMAPTOSECS -1  -PORTBINDTOSECS -1

通过对代码的搜索,我们在文件 Constants.java 文件中找到如下这行

/** Default value for DCS server user program command */
    public static final String DEFAULT_DCS_SERVER_USER_PROGRAM_COMMAND = "cd ${dcs.user.program.home};. sqenv.sh;mxosrvr -ZKHOST -RZ -ZKPNODE -CNGTO -ZKSTO -EADSCO -TCPADD -MAXHEAPPCT -STATISTICSINTERVAL -STATISTICSLIMIT -STATISTICSTYPE -STATISTICSENABLE -SQLPLAN -PORTMAPTOSECS -PORTBINDTOSECS";

这就是启动 sh 的那条命令,接下来我们查找这个变量在哪里使用的,我们在 ServerManger.java 中找到了

private void featureCheck() {
        ......

        boolean ready = false;
        while (!ready) {
            userProgEnabled = conf.getBoolean(
                    Constants.DCS_SERVER_USER_PROGRAM,
                    Constants.DEFAULT_DCS_SERVER_USER_PROGRAM);
            userProgramHome = System.getProperty("dcs.user.program.home");
            userProgramCommand = conf.get(
                    Constants.DCS_SERVER_USER_PROGRAM_COMMAND,
                    Constants.DEFAULT_DCS_SERVER_USER_PROGRAM_COMMAND);   // 就是这里使用的
           ......
        }

        LOG.info("User program enabled");
    }

我们来理解下这里的逻辑,从配置文件 conf(暂时就认为它为空,后续我们会看到它的内容)看我们是否配置了sh命令,如果没有配置就取我们上面看到的默认的命令。如果细心的读者应该发现,上面的 sh 命令只有参数但是没有值啊?这个值是什么时候加上去的? 就找到了 -RZ 这个参数的值为什么为 null 。

我们继续找,就在同一个文件的上面,我们找到了如下这段代码

public ServerRunner(int childInstance, String registeredPath) {
            ......

            String command = userProgramCommand
                    .replace("-ZKHOST", "-ZKHOST " + zkc.getZkQuorum() + " ")
                    .replace(
                            "-RZ",         // 就是这个参数,找的好辛苦啊
                            "-RZ " + hostName + ":" + instance + ":"
                                    + childInstance + " ")
                    .replace("-ZKPNODE",
                            "-ZKPNODE " + "\"" + parentZnode + "\"" + " ")
                    .replace("-CNGTO", "-CNGTO " + connectingTimeout + " ")
                    .replace("-ZKSTO", "-ZKSTO " + zkSessionTimeout + " ")
            ......
        }

这段代码是 ServerRunner的构造函数,它在这里对 userProgramCommand 做了替换,把参数的值放上了。这里我们看到了牵挂已久的 -RZ 参数,我们看到它的值是 hostName。那我们继续找 hostName

public ServerManager(Configuration conf, ZkClient zkc,
            DcsNetworkConfiguration netConf, String instance, int infoPort,
            int childServers) throws Exception {
        this.conf = conf;            // 这就是我们上面看到的是否配置 sh 命令的配置文件
        this.zkc = zkc;
        this.netConf = netConf;
        this.hostName = netConf.getHostName();   // 我们hostName 来的地方
        this.instance = Integer.parseInt(instance);
        this.infoPort = infoPort;
        this.childServers = childServers;

我们发现,两个重要的参数值都是通过 ServerManager 的构造函数给赋值的,我们接下来找ServerManager 调用的地方。

try {
		   	netConf = new DcsNetworkConfiguration(conf);
			serverName = netConf.getHostName();
			..... 
			pool = Executors.newSingleThreadExecutor();
			serverManager = new ServerManager(conf,zkc,netConf,instance,infoPort,childServers);
		    Future future = pool.submit(serverManager);
		    future.get();
		} catch (Exception e) {

我们在 DcsServer.java 的 run()中找到了这么一段代码,我们只关心 ServerManager 的第一个和第三个参数,并且我们发现 netConf 也是从 conf 中来的。但我们还是最关心 netConf.getHostName(),也就是hostName的值等于啥。

我们继续深入DcsNetworkConfiguration

// Constants.java
/** Configuration key for DCS DNS interface */
    public static final String DCS_DNS_INTERFACE = "dcs.dns.interface";
    /** Default value for DCS DNS interface */
    public static final String DEFAULT_DCS_DNS_INTERFACE = "default";
///////////// 

public String getHostName() {
        return canonicalHostName;     // 真实的值
    }

public void getCanonicalHostName(NetworkInterface ni, InetAddress inet)
            throws Exception {
        ......
        canonicalHostName = inet.getCanonicalHostName();      // 赋值
        ......
    }

public DcsNetworkConfiguration(Configuration conf) throws Exception {
        ......
        String dcsDnsInterface = conf.get(Constants.DCS_DNS_INTERFACE,
                Constants.DEFAULT_DCS_DNS_INTERFACE);
        if (dcsDnsInterface.equalsIgnoreCase("default")) {
            intHostAddress = extHostAddress = ia.getHostAddress();
            canonicalHostName = ia.getCanonicalHostName();   // 有可能的赋值
            ......
        } else {
            // For all nics get all hostnames and addresses
            // and try to match against dcs.dns.interface property
            Enumeration<NetworkInterface> nics = NetworkInterface
                    .getNetworkInterfaces();
            while (nics.hasMoreElements() && !matchedInterface) {
                InetAddress inet = null;
                NetworkInterface ni = nics.nextElement();
                ......
                if (dcsDnsInterface.equalsIgnoreCase(ni.getDisplayName())) {
                    ......
                    inet = getInetAddress(ni);
                    getCanonicalHostName(ni, inet);   // 有可能的赋值
                    extInterfaceName = ni.getDisplayName();
                } else {

DcsNetworkConfiguration.java 在这个文件中 对 canonicalHostName 处理还是比较复杂,我们发现有两处可能的赋值,决定的关键是 看配置文件 conf 是否配置 dcs.dns.interface 这个变量。

好了,到了这里我们发现,几处很重要的地方都指向了conf 这个配置文件,那到底这个conf 文件是啥,它里面又是什么内容?

要找到 conf 从什么时候开始赋值的,还得从源头开始找,于是就在 DcsServer.java 中找到了如下代码

public DcsServer(String[] args) {
		this.args = args;
	   	conf = DcsConfiguration.create();          // 这里
		jvmShutdownHook = new JVMShutdownHook();
		Runtime.getRuntime().addShutdownHook(jvmShutdownHook);
		thrd = new Thread(this);
		thrd.start();
	}

找到后我们继续深入 DcsConfiguration

public static Configuration addWmsResources(Configuration conf) {
    conf.addResource("dcs-default.xml");     //就是这里
    conf.addResource("dcs-site.xml");        //就是这里

    return conf;
  }

  /**
   * Creates a Configuration with Dcs resources
   * @return a Configuration with Dcs resources
   */
  public static Configuration create() {
    Configuration conf = new Configuration();
    return addWmsResources(conf);
  }

看到这里,我们就明白了原来 conf 是从这两个文件来的,那这两个文件在哪呢?

我们发现在 DcsServer 启动的时候带了如下这么一个参数,这就知道在哪了。

-Ddcs.conf.dir=/home/trafodion/apache-trafodion_server/dcs-2.0.1/bin/../conf

知道在哪了,那我们就看看 xdata68 这台机器上的配置文件的内容。打开这个目录发现只有 dcs-site.xml 一个配置文件,内容如下

<configuration>
  <property>
    <name>dcs.zookeeper.quorum</name>
    <value>xdata67,xdata68,xdata69</value>
  </property>
   <property>
    <name>dcs.dns.interface</name>
    <value>eth0</value>
  </property>
</configuration>

知道配置文件的内容,那我们再回过头来看看,在 DcsNetworkConfiguration 中我们得到 hostName 的详细逻辑,我在这再贴下 DcsNetworkConfiguration 中处理这部分的逻辑。

// Constants.java
/** Configuration key for DCS DNS interface */
    public static final String DCS_DNS_INTERFACE = "dcs.dns.interface";
    /** Default value for DCS DNS interface */
    public static final String DEFAULT_DCS_DNS_INTERFACE = "default";
///////////// 

public String getHostName() {
        return canonicalHostName;     // 真实的值
    }

public void getCanonicalHostName(NetworkInterface ni, InetAddress inet)
            throws Exception {
        intHostAddress = extHostAddress = inet.getHostAddress();
        canonicalHostName = inet.getCanonicalHostName();      // 赋值
        ......
    }

public DcsNetworkConfiguration(Configuration conf) throws Exception {

        this.conf = conf;
        ia = InetAddress.getLocalHost();
        
        // 我们发现配置文件中刚好对 dcs.dns.interface 进行赋值了, 为 eth0
        String dcsDnsInterface = conf.get(Constants.DCS_DNS_INTERFACE,
                Constants.DEFAULT_DCS_DNS_INTERFACE);
        if (dcsDnsInterface.equalsIgnoreCase("default")) {  
            intHostAddress = extHostAddress = ia.getHostAddress();
            canonicalHostName = ia.getCanonicalHostName();   // 不可能的赋值
            extInterfaceName = NetworkInterface.getByInetAddress(ia)
                    .getDisplayName();
            ......
        } else {
            // For all nics get all hostnames and addresses
            // and try to match against dcs.dns.interface property
            Enumeration<NetworkInterface> nics = NetworkInterface
                    .getNetworkInterfaces();
            while (nics.hasMoreElements() && !matchedInterface) {
                InetAddress inet = null;
                NetworkInterface ni = nics.nextElement();
                ......
                if (dcsDnsInterface.equalsIgnoreCase(ni.getDisplayName())) {  // 是否等于 eth0
                    ......
                    inet = getInetAddress(ni);
                    getCanonicalHostName(ni, inet);   // 真正赋值的地方
                    extInterfaceName = ni.getDisplayName();
                } else {

通过对上面代码的详细分析,发现关键逻辑在于通过循环判断 NetworkInterface.getNetworkInterfaces() 中获取的项的 ni.getDisplayName() 是否 等于我们配置文件中的配置的 eth0。 所以这里的逻辑是通过配置的网络接口名去找 hostName

  • 最终破案

接下来我们就看看 NetworkInterface.getNetworkInterfaces() 的结果到底是啥,于是随手写了如下代码在xdata68 上跑了下

import java.net.*;
import java.util.*;

public class Hello
{
    public static void main(String[] args) throws Exception
    {
        Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces();
        while (nis.hasMoreElements())
            System.out.println(nis.nextElement());
    }
}

结果

name:eth1 (eth1)
name:lo (lo)

所以从结果上来看就知道了,这个方法是获取机器上的所有网络接口。看到这里我们就有点奇怪了,为什么这里获取所有的网络接口中居然没有我们配置文件中配置的 eth0?

为了再次确认 在xdata68 上执行 ifconfig 命令查看了下,再对比 正常机器 xdata70

[trafodion@xdata68 ~]$ ifconfig 
eth1      Link encap:Ethernet  HWaddr 52:54:00:54:94:B5  
          inet addr:xxxxxxxx  Bcast:172.18.255.255  Mask:255.255.0.0
          inet6 addr: fe80::5054:ff:fe54:94b5/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8473656440 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3531432078 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:1756961980786 (1.5 TiB)  TX bytes:1009432619090 (940.1 GiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:251663643 errors:0 dropped:0 overruns:0 frame:0
          TX packets:251663643 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:64908035275 (60.4 GiB)  TX bytes:64908035275 (60.4 GiB)


[trafodion@xdata70 conf]$ ifconfig
eth0      Link encap:Ethernet  HWaddr 52:54:00:A4:C5:92  
          inet addr:172.18.84.70  Bcast:172.18.255.255  Mask:255.255.0.0
          inet6 addr: fe80::5054:ff:fea4:c592/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:7984801625 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3127534521 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:1740020574559 (1.5 TiB)  TX bytes:956397150875 (890.7 GiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:74985186 errors:0 dropped:0 overruns:0 frame:0
          TX packets:74985186 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:61427646458 (57.2 GiB)  TX bytes:61427646458 (57.2 GiB)

看到这里我们豁然开朗了,原来问题导致的原因是, xdata68 这台机器上比较特殊,没有配置 eth0这个网络接口,而我们的Trafodion dcs 的配置文件 dcs-site.xml 中统一配置的 eth0

知道了问题,解决办法就比较简单了,直接修改 dcs-site.xml 配置文件将 eth0 改成 eth1 就可以了。

五、最终总结

  1. 对问题做深入的观察
  2. 对不确定的问题找到确定的规律
  3. 对专业知识建立足够的认识,这样才会培养足够的敏感度
  4. 对问题进行深入锲而不舍的分析,即使扒遍源码也在所不惜(哈哈)
  5. 对问题的定位分析过程能很好的掌握技术本身

六、备注

这里分析下为什么连接 Trafodion 进程会定位连接到 mxosrvr 进程

通过上面给出的 Trafodion 的架构图了解到 Trafodion DCS( Database Connectivity Services)连接服务,是典型的分布式架构。

Dcs Master 负责监听连接(23400端口),当一个数据库连接到来的时候,先连接到 master,master 接受到连接后,分配给各个机器上的 mxosrvr 进程去处理和维护这个连接。相信大家可以参考官方文档的解释,如下:

-------------------------------------------------------------------------------------------------------------

Connectivity

The Database Connectivity Services (DCS) framework enables applications developed for ODBC/JDBC APIs to access a Trafodion SQL database server. DCS is a distributed service. It uses the underlying HBase ZooKeeper instance for its definition of a cluster. Apache ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. All participating nodes and clients need to be able to access the running ZooKeeper.

DCS is a collection of components:

  • ODBC/JDBC Drivers : Provide a standard programming language middle-ware API for accessing database management systems (DBMS).
  • DCS Master Process : The DCS Master server is responsible for monitoring all server instances in the cluster. It assigns an ODBC/JDBC client connection request to a Master Executor (MXOSRVR) process. It also has a backup process that takes over the Master Executor role during failures.
  • DCS Server Process : This process is responsible for starting and keeping a Master Executor (MXOSRVR) server process executing. There is one DCS Server process per node in the cluster.
  • Master Executor Process : This is the database server that provides database access to ODBC/JDBC clients. There is a one-to-one relationship between an ODBC/JDBC client connection and a database server process. The Master Executor performs all SQL queries on behalf of its client’s requests. It will perform all required SQL calls to execute a SQL query through the Executor to access HBase tables. The Master Executor is often referred to as MXOSRVR.
 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • fedora中使用 mariadb数据库建库和建表-- mariadb数据库服务无法启动?
    fedora中使用 mariadb数据库建库和建表-- maria
    /proc(进程, 过程等含义) 文件系统是一个虚拟文件系统,通过它可以使用一种新的方法在 Linux® 内核空间(内核)和用户空间(用户)之间进行通信。在 /proc 文件系统中,我们可以将对虚拟文件的读写 作为与内核中实体进行通信的一种手段,但是与普通文件不同的是
    02-10
  • mysql_pconnect的水挺深,apache下的数据库长连
      php的mysql持久化连接,美好的目标,却拥有糟糕的口碑,往往令人敬而远之。这到底是为啥么。近距离观察后发现,这家伙也不容易啊,要看apache的脸色,还得听mysql指挥。  对于做为apache模块运行的php来说,要实现mysql持久化连接,首先得取决于apache这个
    02-10
  • 大数据实时多维OLAP分析数据库Apache Druid入门分享-下
    大数据实时多维OLAP分析数据库Apache Druid入门
    了解Apache Druid的基础概念后,本篇进一步研究其核心架构和核心设计原理部分,了解相关外部依赖,对其数据摄取和查询有一定认识,然后通过搭建分布式集群进一步理解其架构组成,最后用一个示例从HDFS将数据摄取到Druid并演示两种查询方式@目录架构核心架构外
    02-10
  • 用IIS+ASP建网站的安全性分析 iis部署asp网站数
      随着Internet的发展,Web技术日新月异,人们已经不再满足于静态HTML技术,更多的是要求动态、交互的网络技术。继通用网关接口(CGI)之后,微软推出的IIS+ASP的解决方案作为一种典型的服务器端网页设计技术,被广泛应用在网上银行、电子商务、网上调查、
    02-10
  • IIS7.5下的asp.net网站不能连接数据库 网站无法
       今天报了一错就是"找不到Table[0]"   感觉是没有连到数据库。  处理方法:把连接字符串由windows身份验证改成 sqlserver验证就好了  我不知道为什么这么做!等待高手给我解答
    02-10
  • 用IIS防止mdb数据库被下载
    用IIS防止mdb数据库被下载
      如何防止mdb数据库被下载?本文讨论的是在服务器端禁止mdb格式数据库文件被下载,而不是在数据库中加入防下载表,将数据库名改为含#号的asp、asa等后缀格式。  下面以IIS6.0为例说明如何在服务器端设置禁止下载mdb数据库。新建一记事本文件,里 面不要
    02-10
  • IIS并发连接数和数据库连接池 连接池连接数和数
    一、数据库连接池1、报错:    超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。 2、问题分析:    问题的原因是与数据库的连接没有显示关闭,而等系统自动回收是要时间的.3、相
    02-10
  • debian命令行删除postgresql数据库
    创建数据库 $ createdb odoo-test 删除数据库$ dropdb odoo-test 
    02-10
  • Fedora5下配置MySQL (很有参考价值的 MySQL资料
    一、下载MySQL的安装文件 完全安装MySQL需要下面6个文件: MySQL-server-community-5.1.26-0.rhel4.i386.rpmMySQL-client-community-5.1.26-0.rhel4.i386.rpmMySQL-shared-community-5.1.26-0.rhel4.i386.rpmMySQL-devel-community-5.1.26-0.rhel4.i386.rpmMy
    02-10
  • [数据库]Ubuntu Linux/Kylin: 安装MySQL
    1 文由由于安装环境较为特殊,实在折煞人也。而此环境的网络博客/教程偏少,觉得有必要记录一下。2 环境安装主机不支持联网 即 不支持APT/APT-GET等傻瓜式的在线安装方式。硬件架构: AARCH64(ARM64架构的V8状态)OS: Kylin(国产操作系统:银河麒麟)基于 Ubuntu
    02-10
点击排行