source

Oracle JDBC 간헐적 연결 문제

manysource 2023. 3. 31. 22:31

Oracle JDBC 간헐적 연결 문제

매우 이상한 문제가 발생하고 있습니다.이것은 Oracle 데이터베이스에 접속하는 매우 간단한 JDBC 사용법입니다.

OS: Ubuntu
Java Version:  1.5.0_16-b02
               1.6.0_17-b04
Database: Oracle 11g Release 11.1.0.6.0

file jar를 하는 OJDBC14.jar 파일 항아리를 됩니다.OJDBC5.jar 6을 사용하면할 수 ).OJDBC6.jar도 같은 를 얻습니다.OJDBC5.jar

OJDBC14.jar에서는 사용할 수 없는 JODB5.jar의 특정 기능이 필요합니다.

아이디어

에러

> Connecting to oracle
    java.sql.SQLException: Io exception: Connection reset
    at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:74)
    at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:110)
    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:171)
    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:227)
    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:494)
    at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:411)
    at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:490)
    at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:202)
    at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:33)
    at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:474)
    at java.sql.DriverManager.getConnection(DriverManager.java:525)
    at java.sql.DriverManager.getConnection(DriverManager.java:171)
    at TestConnect.main(TestConnect.java:13)

코드

사용중인 코드는 다음과 같습니다.

import java.io.*;
import java.sql.*;
public class TestConnect {
    public static void main(String[] args) {
        try {
            System.out.println("Connecting to oracle"); 
            Connection con=null;
            Class.forName("oracle.jdbc.driver.OracleDriver");
            con=DriverManager.getConnection(
               "jdbc:oracle:thin:@172.16.48.100:1535:sample",
               "JOHN",
               "90009000");
            System.out.println("Connected to oracle"); 
            con.close();
            System.out.println("Goodbye");
        } catch(Exception e) { e.printStackTrace(); }
    }
}

이 문제에 대한 해결책은 일부 OTN 포럼(https://kr.forums.oracle.com/forums/thread.jspa?messageID=3699989)에서 제공됩니다.그러나 문제의 근본 원인은 설명되지 않았습니다.다음은 문제의 근본 원인을 설명하려는 저의 시도입니다.

Oracle JDBC 드라이버는 안전한 방법으로 Oracle 서버와 통신합니다.드라이버는 java.security를 사용합니다.통신을 보호하기 위해 엔트로피를 수집하는 SecureRandom 클래스.이 클래스는 엔트로피를 수집하기 위해 네이티브플랫폼 지원에 의존합니다.

엔트로피는 암호화 또는 랜덤 데이터를 필요로 하는 다른 용도로 사용하기 위해 운영 체제 또는 응용 프로그램에 의해 수집/생성되는 랜덤성입니다.이 랜덤성은 종종 하드웨어 소음, 오디오 데이터, 마우스 이동 또는 특별히 제공된 랜덤성 발생기에서 수집됩니다.커널은 엔트로피를 수집하여 엔트로피 풀로 저장하고 /dev/random /dev/urandom을 통해 운영 체제 프로세스 또는 애플리케이션에서 랜덤 문자 데이터를 사용할 수 있도록 합니다.

/dev/random에서 읽으면 엔트로피 풀이 요청된 비트/바이트 양으로 고갈되므로 암호화 작업에서 종종 요구되는 높은 수준의 랜덤성을 제공합니다.엔트로피 풀이 완전히 드레인되어 충분한 엔트로피를 이용할 수 없는 경우 추가 엔트로피가 수집될 때까지 /dev/random 블록에 대한 읽기 작업을 수행합니다.이로 인해 /dev/random에서 읽는 응용 프로그램이 일정 기간 동안 차단될 수 있습니다.

위와 달리 /dev/urandom에서 읽어도 차단되지 않습니다./dev/urandom에서도 읽으면 엔트로피 풀이 고갈되지만 엔트로피가 부족하면 부분적으로 읽힌 랜덤 데이터의 비트를 차단하지 않고 재사용합니다.이것은 암호 해독 공격에 취약한 것으로 알려져 있습니다.이는 이론적인 가능성이므로 암호화 작업에서 랜덤성을 수집하기 위해 /dev/urandom에서 읽는 것은 권장되지 않습니다.

java.security.SecureRandom 클래스는 기본적으로 /dev/random 파일에서 읽기 때문에 랜덤 기간 동안 차단될 수 있습니다.읽기 작업이 필요한 시간 동안 반환되지 않으면 Oracle 서버는 클라이언트(이 경우 jdbc 드라이버)를 타임아웃하고 소켓을 종료하여 통신을 드롭합니다.가 블로킹콜에서 돌아온 후 통신을 재개하려고 하면 클라이언트가 IO 예외가 발생합니다.이 문제는 임의의 플랫폼, 특히 하드웨어 노이즈에서 엔트로피가 수집되는 플랫폼에서 랜덤하게 발생할 수 있습니다.

OTN 포럼에서 제시된 바와 같이 이 문제의 해결책은 java.security의 기본 동작을 덮어쓰는 것입니다.SecureRandom 클래스에서 /dev/random에서 읽은 블록 대신 /dev/urandom에서 읽은 블록 없음 읽기를 사용합니다.이를 수행하려면 시스템 속성 -Djava.security.egd=file://dev/urandom을 JVM에 추가합니다.이 솔루션은 JDBC 드라이버와 같은 애플리케이션에 적합한 솔루션이지만 암호 키 생성과 같은 핵심 암호화 작업을 수행하는 애플리케이션에는 권장되지 않습니다.

다른 솔루션은 엔트로피를 수집하기 위해 하드웨어 노이즈에 의존하지 않는 플랫폼에서 사용할 수 있는 다양한 랜덤 시드 구현을 사용하는 것입니다.이 경우에도 기본 동작인 java.security를 덮어쓸 필요가 있습니다.Secure Random.

Oracle 서버 측에서 소켓타임아웃을 늘리는 것도 해결책이 될 수 있지만, 이 방법을 시도하기 전에 서버 관점에서 부작용을 평가해야 합니다.

나는 정확히 같은 문제에 직면해 있었다.Windows Vista 에서는 문제를 재현할 수 없었지만, Ubuntu 에서는 「connection reset」(접속 리셋) 에러가 계속 재현되고 있었습니다.

http://forums.oracle.com/forums/thread.jspa?threadID=941911&tstart=0&messageID=3793101을 찾았습니다.

해당 포럼의 사용자에 따르면:

오라클에서 티켓을 오픈했는데 이렇게 알려줬어요.

java.security.SecureRandom은 Sun에서 제공하는 표준 API입니다.이 클래스에서 제공되는 다양한 메서드 중 하나는 void nextBytes(byte[])입니다.이 메서드는 랜덤바이트 생성에 사용됩니다.Oracle 11g JDBC 드라이버는 이 API를 사용하여 로그인 시 난수를 생성합니다.Linux를 사용하는 사용자에게 SQLException("Io 예외:접속 리셋」).

문제는 두 겹입니다.

  1. SecureRandom.nextBytes(byte[])가 호출되면 JVM은 /tmp(또는 -Djava.io.tmpdir에 의해 설정된 대체 tmp 디렉토리) 내의 모든 파일을 나열하려고 합니다.파일 수가 많은 경우 이 메서드는 응답에 시간이 오래 걸리기 때문에 서버가 타임아웃됩니다.

  2. void nextBytes(byte[]) 메서드는 Linux 및 하드웨어 생성 랜덤 번호가 없는 일부 머신에서 /dev/random을 사용합니다.이 동작은 로그인 프로세스 전체를 정지시킬 정도로 느려집니다.최종적으로는 SQLException("Io 예외:접속 리셋')

기본 OS가 장애가 있는 하드웨어에서 실행되는 Linux인 경우 11g으로 업그레이드하면 이 문제가 발생할 수 있습니다.

원인 이 문제의 원인은 아직 정확히 밝혀지지 않았습니다.하드웨어에 문제가 있거나 소프트웨어가 개발/랜덤에서 읽을 수 없는 것이 원인일 수 있습니다.

해결 방법 응용 프로그램의 설정을 변경하여 Java 명령에 다음 매개 변수를 추가합니다.

-Djava.security.egd=파일:/dev/../dev/urandom

java.security 파일을 변경하여 오류를 없앴습니다.

그게 내 문제를 해결했어

일반적으로 "connection reset" 오류 메시지는 연결(핸드쉐이크)을 만드는 동안 상대방이 연결을 중단했음을 의미합니다.여기에는 여러 가지 원인이 있을 수 있습니다.JDBC 드라이버의 버그, DB측의 타임아웃, 데이터베이스 재기동, DB의 사용 가능한 접속 부족, 네트워크 품질 저하, 불량 virusscanner/firewall/proxy 등

간헐적으로 발생하므로 JDBC 드라이버의 버그는 거의 제외되지 않을 수 있습니다.나머지 가능한 원인을 남겼습니다.먼저 DB 서버의 로그를 살펴보는 것이 좋습니다.

말하기 어렵지만, JDBC 드라이버의 실제 버전을 확인해 보겠습니다.11.1.0.6임을 확인합니다.

Oracle은 파일 이름에 데이터베이스 버전을 포함하지 않습니다.따라서 11.2 드라이버는 11.1 - ojdbc5.jar 드라이버와 정확히 같은 이름입니다.드라이버 항아리 파일을 추출해서 매니페스트를 찾을 거예요MF 파일에는 버전 정보가 포함되어 있습니다.JDBC 드라이버의 버전이 데이터베이스의 버전과 일치하는지 확인합니다.Oracle의 11.1.0.6 다운로드 페이지에는 ojdbc14.jar라는 이름의 jar 파일이 없기 때문에 버전 문제일 수 있습니다.

버전이 일치하는 경우 - 아이디어가 없습니다:)

이 문제를 일으킨 또 다른 원인은 호스트명의 설정이 잘못되어 있는 것입니다.연결 시도가 다음 위치에서 중단되었습니다.

"main" prio=10 tid=0x00007f7cc8009000 nid=0x2f3a runnable [0x00007f7cce69e000]
   java.lang.Thread.State: RUNNABLE
        at java.net.Inet4AddressImpl.getLocalHostName(Native Method)
        at java.net.InetAddress.getLocalHost(InetAddress.java:1444)
        at sun.security.provider.SeedGenerator$1.run(SeedGenerator.java:176)
        at sun.security.provider.SeedGenerator$1.run(SeedGenerator.java:162)
        at java.security.AccessController.doPrivileged(Native Method)

, 가 「 」, 「 」에 있는 것을 확인해 ./etc/hosts/.

「 」를 hostname츠키다

$ hostname
my.server.com

써주세요./etc/hosts:

127.0.0.1 my my.server.com

Bug https://bugs.openjdk.java.net/browse/JDK-6202721에 따라

Java는 -Djava.security.egd=file:/dev/urandom을 고려하지 않습니다.

-Djava.security.egd=file:/dev/.urandom이어야 합니다.

확실히 하자면, 적어도 우리 쪽에서 발견한 것부터!이것은 JDK 디스트리뷰션의 Linux용 랜덤라이저 셋업에 관한 문제이며, Java6에서는 Java7에 대해서는 확실하지 않습니다.randomizer의 linux 구문은 file:///dev/urandom이지만 파일 내의 엔트리는 file:/dev/urandom으로 되어 있습니다.그러면 Java는 기본값인 /dev/random으로 폴백합니다.그리고 헤드리스 기계에서는 작동하지 않는다!!!

이 문제의 근본 원인은 사용자 인증 버전에 있습니다.데이터베이스 사용자별로 여러 개의 비밀번호 확인자가 데이터베이스에 저장됩니다.일반적으로 데이터베이스를 업그레이드할 때 보다 강력한 새 비밀번호 확인자가 목록에 추가됩니다.다음 쿼리는 각 사용자가 사용할 수 있는 비밀번호 확인 버전을 보여 줍니다.예를 들어 다음과 같습니다.

SQL> SELECT PASSWORD_VERSIONS FROM DBA_USERS WHERE USERNAME='SCOTT';

PASSWORD_VERSIONS
-----------------
11G 12C

드라이버와 서버가 사용할 수 있는 가장 강력한 검증자를 네고시에이트하기 때문에 새로운 버전의 검증자를 사용할 수 있습니다.이 새로운 버전의 검증에서는 보안이 강화되어 보다 큰 난수를 생성하거나 JDBC 접속 확립 중에 문제가 발생하는 이유를 설명할 수 있는 보다 복잡한 해시 함수를 사용해야 합니다.다음을 사용하여 다른 응답에서 언급한 바와 같이/dev/urandom는 보통 이러한 문제를 해결합니다.또한 비밀번호 확인기를 다운그레이드하여 이전 드라이버가 사용하던 것과 동일한 이전 비밀번호 확인기를 새 드라이버에 사용하도록 할 수도 있습니다.예를 들어 10G 비밀번호 검증기를 테스트 목적으로만 사용하려면 먼저 사용자가 사용할 수 있는지 확인해야 합니다. ★★SQLNET.ALLOWED_LOGON_VERSION_SERVER=8서버상의 sqlnet.ora에 있습니다.그 후, 다음과 같이 입력합니다.

SQL> alter user scott identified by "tiger";

User altered.

SQL> SELECT PASSWORD_VERSIONS FROM DBA_USERS WHERE USERNAME='SCOTT';
PASSWORD_VERSIONS
-----------------
10G 11G 12C

그런 다음 이 JDBC 속성을 설정하여 JDBC 씬 드라이버가 10G 검증자를 사용하도록 강제할 수 있습니다.oracle.jdbc.thinLogonCapability="o3"에러가 발생했을 경우"ORA-28040: No matching authentication protocol"이는 서버가 10G 검증기 사용을 허용하지 않음을 의미합니다.이 경우 설정을 다시 확인해야 합니다.

처음에 /dev/urandom을 사용하는 제안 솔루션은 기능했지만 그 후에는 항상 기능하지는 않았습니다.

저희 회사의 DBA가 'SQL* net banner'를 교체하여 위의 유무에 관계없이 영구적으로 수정하였습니다.

SQL* net banner'가 무엇인지 모르겠지만, 이 정보를 여기에 기재함으로써 DBA가 있다면 DBA가 무엇을 해야 하는지 알 수 있기를 바랍니다.

SQL Net Banner를 비활성화하여 구했습니다.

-Djava.security.egd=file:/dev/.urandom 이 아니라 -Djava.security.egd=file://dev/urandom 이 옳아야 합니다.

젠킨스에게서 액체가 실행되었을 때도 같은 문제에 직면했습니다.산발적으로 이 에러가 출력에 투하되어 액화효소 변경 로그는 전혀 실행되지 않았습니다.

제공되는 솔루션:jenkin의 maven 프로젝트에서 jdk는 jdk8-131에서 새로운 버전(예: java8-162)으로 업데이트되었습니다.

OracleXETNSListener - 이 서비스가 비활성화되어 있는 경우 서비스를 시작해야 합니다.

run -> services.msc 

그리고 그 서비스들을 주의해서

언급URL : https://stackoverflow.com/questions/2327220/oracle-jdbc-intermittent-connection-issue