【问题标题】:Uniquely identify source JDBC process in Oracle DB在 Oracle DB 中唯一标识源 JDBC 进程
【发布时间】:2018-10-10 06:15:57
【问题描述】:

我们正在使用 java(Spring 和 Spring Boot)开发微服务,并且通过 JDBC Oracle 驱动程序访问我们的 Oracle DB。

问题是我们的 DBA 只能在 Oracle 端看到连接了“JDBC 瘦客户端”。没有更好的连接应用程序的逻辑表示。如果没有这样的识别,很难知道哪个微服务可能表现不佳。其他非 JDBC 客户端使用主机名清楚地标识自己。

有什么办法可以改变标识字符串,使它代表源应用程序/进程的清晰标识?

注意:我们的系统在使用容器的 Cloud Foundry 上运行,因此实际上不可能提供机器名称或类似名称 - 最好使用逻辑应用程序名称。

谢谢

【问题讨论】:

    标签: java spring oracle jdbc spring-jdbc


    【解决方案1】:

    如果您可以访问连接到 Oracle 数据库的代码,您可以尝试:

    private static String getProcessId(final String fallback) {
     // Note: may fail in some JVM implementations
     // therefore fallback has to be provided
     // something like '<pid>@<hostname>', at least in SUN / Oracle JVMs
     final String jvmName = ManagementFactory.getRuntimeMXBean().getName();
     final int index = jvmName.indexOf('@');
    
     if (index < 1) {
       // part before '@' empty (index = 0) / '@' not found (index = -1)
       return fallback;
     }
    
     try {
       return Long.toString(Long.parseLong(jvmName.substring(0, index)));
       } catch (NumberFormatException e) {
       // ignore
       }
     return fallback;
     }
    
    
    
    public void init() {
        java.util.Properties props = new java.util.Properties();
        String javaPid;
        try {
            oracleConnexionPool = new OracleConnectionPoolDataSource();
            oracleConnexionPool.setDriverType(oracle.jdbc.driver.OracleDriver);
            //Java 9+ version:
            //long pid = ProcessHandle.current().pid();
            //Java < 9 version:
            try
            {
                javaPid = getProcessId("<PID>");
                props.put("v$session.process", javaPid);
                props.put("v$session.program", "<Your program name>");
                oracleConnexionPool.setConnectionProperties(props);
            }
            catch (SQLException e) {
                }
    
            oracleConnexionPool.setURL(<DB URL>);
    

    如果您可以访问启动 java 的命令行,请尝试:

    java ...-Doracle.jdbc.v\$session.process=$$ ...
    

    用于识别会话“属于”谁的可用关键字是(Unix 风格的语法):

    java ...-Doracle.jdbc.v\$session.process=<My PID> \
      -Doracle.jdbc.v\$session.machine="<My machine>" \
      -Doracle.jdbc.v\$session.osuser="<My OS username>" \
      -Doracle.jdbc.v\$session.program="<My program>" \
      -Doracle.jdbc.v\$session.terminal="<My term>" ...
    

    【讨论】:

      【解决方案2】:

      谢谢大家的建议, 我都试过了,遗憾的是它们都不起作用。

      这可能是因为我使用 Spring Data 和默认的 Hikari 连接池进行连接。

      花了几个小时后,在这里找到了最终解决方案:Spring Boot 1.3.5 with Hikari Connection Pool not able to set program name in v$session

      spring:
        datasource:
          hikari:
            data-source-properties:
               v$session.program: AppName
      

      简单,无需更改代码,即可使用!

      【讨论】:

        【解决方案3】:

        可以将 JDBC 连接属性“oracle.jdbc.v$session.process”设置为(作为系统属性 -D)唯一标识您的微服务的值,然后可以在 V$SESSION 视图(“进程”列)中检索该值。

        【讨论】:

        【解决方案4】:

        根据您的 Oracle 版本,该功能在方法中实现 setEndToEndMetrics(自 12.1 起已弃用,取而代之的是 setClientInfo()) 或setClientInfo

        这里是一个使用的小例子。获取连接(通常来自连接池)后的客户端(您的服务)设置属性 actionclientIdmodule

        String[] metrics = new String[OracleConnection.END_TO_END_STATE_INDEX_MAX];
         metrics[OracleConnection.END_TO_END_ACTION_INDEX] = 'myAction1';
         metrics[OracleConnection.END_TO_END_CLIENTID_INDEX] = 'myClient';
         metrics[OracleConnection.END_TO_END_MODULE_INDEX] = 'myModule1';
         con.setEndToEndMetrics(metrics, (short) 0);
        

        并在返回连接之前重置它们。

        DBA 可以通过以下查询观察V$SESSION 中的设置

        select sid,  client_info, module, action from v$session
        

        因此她不仅可以将数据库会话与服务相关联,而且客户端/模块和操作的组合可以提供服务状态的更多详细信息。

        需要考虑三件事:

        仅当所有服务在设置值时都建立一定的纪律时才有效。在重新使用连接池中的会话时,很容易从前任服务“继承”错误设置。我建议将其作为连接池资源处理的一个方面来实现。

        此外,Java 版本、JDBC 驱动程序和 Oracle Server 必须具有兼容版本,因此最好在简单的脚本中测试功能。

        最后不要用于设置PL/SQL API(PL/SQL 开发人员自然会这样做)。最大的区别在于 PL/SQL API 触发到数据库的往返,而 JDBC API 则不会(值与下一个请求一起发送)。

        【讨论】:

          【解决方案5】:

          数据库用户

          如果您将用于连接的数据库用户命名为微服务,则 DBA 应该能够将连接映射到微服务。

          IP 地址

          对于数据库,连接还包含传入的 IP 地址。使用微服务的 IP 地址表,DBA 可能能够将连接映射到微服务。

          恭敬

          对于 DBA 来说,找出程序员的错误可能是一项令人兴奋的工作。如果程序员和 DBA 之间的关系是协调一致的,那么谈话可能会解决他们(在代码中)出现的问题。如果不能很快实现统一,更详细的合同或规范可能是一个解决方案。

          它看起来像一个解决方法。错误在代码中,让我们在代码中找到它。

          API取消资格

          如果您想通过数据库连接来识别微服务,您将取消使用 API 访问数据库的资格。如果您希望将 Single-Source-Of-Truth 作为微服务使用,Database API 可能会很有用。

          【讨论】:

          • 典型的协调讨论如下所示 - 程序员:数据库中存在性能问题。 DBA:有一些有问题的查询,但我们不知道是谁发起的(除了 USER 和 HOST,对于所有微服务都是相同的)。所以显然某种程度的 E2E 仪器 可能是有意义的......
          • @MarmiteBomber 很好的例子。让他们意识到两者都是正确的,你有你的和谐......没有解决问题。他们还没有具体的解决方案。
          猜你喜欢
          • 2022-11-30
          • 2010-09-16
          • 2014-02-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-09-27
          • 2018-02-09
          • 2012-05-06
          相关资源
          最近更新 更多