SDK 및 애플리케이션 통합

Completed

Azure Database for PostgreSQL을 애플리케이션에 통합하려면 적절한 클라이언트 라이브러리를 선택하고, 연결을 효과적으로 관리하고, 오류를 정상적으로 처리해야 합니다. 이 단원에서는 프로그래밍 언어에 적용되는 모범 사례와 함께 Python에 대한 SDK 통합 패턴을 다룹니다.

비고

이 단원의 코드 예제에서는 PostgreSQL을 애플리케이션과 통합하는 패턴을 보여 줍니다. psycopg 라이브러리는 자주 업데이트됩니다. 최신 API 세부 정보 및 모범 사례는 psycopg 설명서를 참조하세요.

psycopg와 Python 통합

psycopg 라이브러리(버전 3)는 Python에 권장되는 PostgreSQL 어댑터입니다. 동기 및 비동기 인터페이스, 연결 풀링 및 PostgreSQL 기능에 대한 전체 지원을 모두 제공합니다.

pip의 binary extra를 사용하여 간단하게 psycopg를 설치합니다 pip install "psycopg[binary]". 이진 배포에는 미리 컴파일된 종속성이 포함되어 있으므로 개발 머신에 PostgreSQL 클라이언트 라이브러리를 설치할 필요가 없습니다. 특정 PostgreSQL 클라이언트 라이브러리에 대해 컴파일해야 하는 프로덕션 배포의 경우, 이진 파일 추가 없이 설치하고, libpq 개발 헤더가 사용 가능한지 확인하세요.

연결 문자열 또는 개별 매개 변수를 사용하여 psycopg.connect() 연결을 만듭니다. 연결 문자열은 구성 파일에 편리하지만 개별 매개 변수는 Key Vault에서 암호 검색과 같은 프로그래밍 방식으로 값을 계산할 수 있는 유연성을 제공합니다.

import psycopg

# Connection string format
conn = psycopg.connect("postgresql://user:password@myserver.postgres.database.azure.com/mydb?sslmode=require")

# Individual parameters
conn = psycopg.connect(host="myserver.postgres.database.azure.com", dbname="mydb",
                       user="myuser", password="mypassword", sslmode="require")

컨텍스트 관리자는 예외가 발생하더라도 연결이 제대로 닫혀 있는지 확인합니다. 외부 with 블록은 연결을 관리하고 내부 with 블록은 커서를 관리합니다.

with psycopg.connect(connection_string) as conn:
    with conn.cursor() as cur:
        cur.execute("SELECT * FROM conversations WHERE id = %s", (conversation_id,))
        row = cur.fetchone()

항상 매개 변수가 있는 쿼리를 사용하여 SQL 삽입 공격을 방지합니다. 매개 변수가 있는 쿼리는 SQL 구조를 데이터 값과 분리하여 데이터베이스 드라이버가 적절한 이스케이프를 처리하도록 합니다. 위치 매개 변수에는 %s 자리 표시자를, 명명된 매개 변수에는 %(name)s 자리 표시자를 사용합니다. 문자열 서식 또는 연결을 사용하여 사용자 입력을 사용하여 쿼리를 작성하지 마세요.

요구 사항과 일치하는 커서 메서드를 사용하여 쿼리 결과를 검색합니다. fetchone()는 단일 행을 기대할 때 사용하고, fetchall()는 작은 결과 집합에 사용하며, 큰 결과 집합은 한번에 메모리에 모두 로드하지 않도록 커서를 직접 반복합니다.

연결 관리 모범 사례

효과적인 연결 관리는 사용하는 프로그래밍 언어에 관계없이 애플리케이션 안정성 및 성능을 향상시킵니다.

데이터베이스에 연결할 수 없거나 쿼리가 예상보다 오래 실행되는 경우 애플리케이션이 중단되지 않도록 적절한 시간 제한을 설정합니다. 연결 시간 제한은 클라이언트가 연결을 설정하기 위해 대기하는 시간을 제어하는 반면 문 시간 제한은 쿼리 실행 시간을 제한합니다. 애플리케이션의 대기 시간 허용 오차에 따라 시간 제한 값을 선택합니다. 웹 애플리케이션은 일반적으로 일괄 처리 작업보다 더 짧은 시간 제한(5~30초)을 사용합니다.

conn = psycopg.connect(
    connection_string,
    connect_timeout=10,
    options="-c statement_timeout=30000"  # milliseconds
)

지수 백오프를 사용하여 다시 시도 논리를 구현하여 네트워크 문제, 서버 다시 시작 또는 리소스 경합의 일시적인 오류를 처리합니다. 연결 및 시간 초과 오류의 OperationalError를 포착합니다. 다시 시도하지 않고 코드 변경이 필요한 제약 조건 위반 또는 구문 오류를 다시 시도하지 마세요.

사용이 끝나면 항상 연결을 끊으세요. 유출된 연결은 연결 풀을 소모하고 새 연결을 방지할 수 있습니다. 컨텍스트 관리자는 예외가 발생하는 경우에도 작동하는 자동 정리를 제공합니다.

오류 처리 전략

데이터베이스 작업은 여러 가지 이유로 실패할 수 있습니다. 오류를 적절하게 처리하면 사용자 환경이 개선되고 디버깅이 간소화됩니다.

연결 오류는 서버에 연결할 수 없거나 연결을 거부할 때 발생합니다. 네트워크 문제, 잘못된 자격 증명, 방화벽 규칙 또는 서버 유지 관리가 모두 원인일 수 있습니다. 최종 사용자에게 사용자에게 친숙한 메시지를 제공하는 동안 문제 해결에 대한 세부 정보를 로깅하여 연결 오류를 처리합니다.

고유 제약 조건, 외세 키 및 check 제약 조건은 위반 시 특정 오류를 발생합니다. UniqueViolation, ForeignKeyViolation, CheckViolation를 잡아서 의미 있는 피드백을 제공합니다. 제약 조건 위반 후 항상 트랜잭션을 롤백합니다.

교착 상태는 두 트랜잭션이 서로의 잠금을 대기하여 순환 종속성을 만들 때 발생합니다. PostgreSQL은 교착 상태를 자동으로 검색하고 하나의 트랜잭션을 종료합니다. 애플리케이션은 DeadlockDetected를 포착한 후 롤백하고 작업을 다시 시도합니다. 교착 상태 위험을 최소화하려면 트랜잭션을 디자인하여 일관된 순서로 잠금을 획득합니다. 마찬가지로 잠금을 기다리는 쿼리 시간이 초과되면 LockNotAvailable 처리합니다.

성능 고려 사항

애플리케이션 수준 패턴은 데이터베이스 성능에 큰 영향을 줄 수 있습니다.

루프에서 개별 삽입을 실행하는 대신 단일 문에 여러 행을 삽입합니다. 일괄 처리 작업은 네트워크 왕복을 줄여 대량 데이터 작업의 처리량을 크게 향상시킵니다. 수백 개에서 몇 천 개의 행을 삽입하는 데 사용합니다 executemany . 더 큰 데이터 세트(10,000개 이상의 행) COPY 의 경우 이 명령은 개별 삽입보다 2~10배 빠른 가장 높은 성능을 제공합니다.

with cur.copy("COPY messages (conversation_id, role, content) FROM STDIN") as copy:
    for record in records:
        copy.write_row(record)

준비된 문은 다른 매개 변수를 사용하여 반복적으로 실행되는 쿼리의 성능을 향상시킬 수 있습니다. 데이터베이스는 쿼리를 한 번 구문 분석하고 계획한 다음 해당 계획을 다시 사용합니다. 대부분의 PostgreSQL 드라이버는 매개 변수가 있는 쿼리에 대해 준비된 문을 자동으로 사용합니다.

새 데이터베이스 연결을 만드는 데는 비용이 많이 듭니다. 각 연결에는 네트워크 핸드셰이크, 인증 및 서버 쪽 리소스 할당이 필요합니다. 연결 풀을 사용하여 애플리케이션에서 대여하고 반환할 수 있는 재사용 가능한 연결을 유지 관리합니다.

from psycopg_pool import ConnectionPool

pool = ConnectionPool(connection_string, min_size=1, max_size=10)

with pool.connection() as conn:
    with conn.cursor() as cur:
        cur.execute("SELECT * FROM messages WHERE conversation_id = %s", (id,))

추가 리소스