Using Fox DB Profile¶
이 문서는 Fox DB Profile 을 적용할 때의 몇가지 팁과 구체적인 활용 방법에 대해서 설명합니다.
활용 목적¶
Fox DB Profile 기능은 쿼리 수행 결과(FoxDbProfileInfo 객체)를 수집하는 기능을 제공합니다. 이 기능을 어떤 목적으로 사용할 것인가를 결정하는 것은 매우 중요합니다. 이 결정에 따라서 쿼리 수행 결과를 얼마 만큼 수집할 것인지, 어디에 기록할 것인지, 그리고 수집된 정보를 어떻게 활용 및 분석할 것인지가 결정되기 때문입니다.
쿼리 감사(Auditing)¶
많은 앱들은 데이터베이스에 수행되는 쿼리에 대해 감사 정보를 기록하도록 요구 받습니다. 이러한 앱들은 대개 보안 상의 이유로 누가 언제 어떤 쿼리를 수행했는지를 기록해야 합니다. Fox DB Profile 은 이러한 감사 목적에 사용될 수 있습니다. 이러한 경우 Fox DB Profile 이 유발하는 오버헤드에도 불구하고 모든 쿼리 수행 결과에 대해 기록을 남겨야 하기 때문에 성능적인 고려 사항에 주목해야 합니다. 또한, 단순한 감사용이라면 텍스트 파일에 쿼리 수행 정보를 기록하는 것도 문제가 없을 수 있습니다.
성능 진단/분석¶
앱의 성능 문제들 중 상당 부분은 데이터베이스 병목에서 기인합니다. 어떤 쿼리가 어떤 매개변수 값과 수행될 때 낮은 성능을 내는지 파악하고 해당 쿼리를 튜닝하는 것은 성능 진단 및 분석에 핵심이라 할 수 있습니다. Fox DB Profile 의 필터링 기능(executionTime
속성)을 사용하면 일정 시간 이상 소요되는 쿼리들만 로그에 기록할 수 있기 때문에 Fox DB Profile 이 유발하는 오버헤드를 크게 걱정하지 않을 수 있습니다. 성능 진단 위해서는 상당 기간 동안 쿼리 수행 결과를 수집해야 하고 수집된 정보로 분석을 수행해야 하기 때문에 쿼리 수행 결과는 별도의 데이터베이스에 기록하는 것이 유리합니다.
모니터링¶
앱 오픈 직후나 대규모 업데이트와 같은 이벤트 발생 시 데이터베이스에 대한 모니터링에 Fox DB Profile 을 활용할 수 있습니다. 물론, 별도의 데이터베이스 모니터링 도구나 솔루션을 사용하는 것이 좋지만 이러한 추가적인 투자 없이도 간단한 수준의 모니터링이 가능합니다.
성능적인 고려 사항¶
Fox DB Profile 은 쿼리 수행 결과에 대한 정보를 수집하고 로그에 기록합니다. 이 기능이 쿼리 수행에 영향을 최소화 하도록 세심하게 설계되었지만 추가적인 오버헤드가 발생하게 됩니다. 따라서 Fox DB Profile 을 사용하는 목적에 따라 쿼리 수행 결과의 수집 범위를 조정해야 하며, 수집된 정보를 기록할 저장 매체도 조심스럽게 선택해야 합니다.
Fox DB Profile 작동 방식 이해¶
Fox DB Profile 이 활성화되면 FoxDbAccess
는 쿼리 수행 전 성능 측정 준비를 수행하고 쿼리 수행 후 성능 측정을 완료합니다. FoxDbAccess
는 추가적인 쿼리 수행 정보(CommandText
, DB 매개변수 정보, QueryString
정보 등등) 수집 작업을 비동기로 예약하고 즉시 호출자에게 반환 합니다.
비동기적으로 쿼리 수행 정보 수집 작업이 완료되면 수집된 정보(FoxDbProfileInfo
객체)를 설정된 로거로 기록(Information
로거 수준 사용)합니다. 로거가 쿼리 수행 정보를 기록하는 방식은 로거마다 작동방식이 서로 다를 수 있습니다. 이 과정에서 만약 오류(예외)가 발생한다면 이 오류는 대부분 무시됩니다.
Warning
Fox DB Profile 설정 중 diagnostics
속성이 true
로 지정되면 FoxDbAccess
는 추가적인 쿼리 수행 정보를 비동기가 아닌 동기적으로 수집합니다. 그리고 로거에 쿼리 수행 정보를 기록한 후에 FoxDbAccess
를 호출한 호출자에게 반환 합니다. 이 과정에서 오류가 발생하면 해당 오류는 그대로 호출자에게 전달됩니다(throw
).
diagnostics
속성을 true
로 지정하면 오버헤드가 크게 늘어납니다. 따라서 Fox DB Profile 의 문제점을 해결하는 용도로만 diagnostics
속성을 사용해야 합니다.
쿼리 정보 수집 범위¶
Fox DB Profile 이 유발하는 오버헤드는 이 기능이 얼마나 많은 쿼리 수행 정보를 기록하는가와 관련이 깊습니다. 따라서 쿼리 수행 정보를 얼마나 많이 남길것인가를 주의 깊게 결정해야 합니다.
감사 목적으로 Fox DB Profile 을 사용한다면 거의 대부분의 쿼리에 대한 수행 정보를 기록해야 합니다. Fox DB Profile 이 성능 저하를 최소화 하려면 로거가 FoxDbProfileInfo
객체를 기록하는 부분을 최적화해야 합니다. 단순한 감사용이라면 텍스트 파일에 로그를 기록하는 것이 성능적으로 유리하지만 데이터베이스에 기록을 해야 한다면 NoSQL 데이터베이스에 기록하는 것이 성능적으로 유리할 것입니다.
한편, 성능 진단/분석을 위해 Fox DB Profile 을 사용하는 경우 모든 쿼리에 대한 정보를 기록할 필요는 없습니다. 예상 보다 느린 쿼리들이나 오류가 발생한 쿼리들에 대해서만 기록을 남기면되기 때문에 필터링 기능(executionTime
속성)을 활용하는 것이 좋습니다. 쿼리 수행 정보를 기록할 매체도 분석하기 좋고 질의 작성이 편리한 데이터베이스를 선택하여 기록하는 것이 좋습니다. 따라서 Fox DB Profile 을 위한 전용 로거를 작성하는 것을 권장합니다.
로그 전용 DB¶
감사 목적이건 성능 진단/분석 목적이건 데이터베이스에 쿼리 수행 정보를 기록하기로 결정하였다면 쿼리 수행 정보를 위한 전용 데이터베이스를 따로 구성하는 것이 좋습니다. 앱이 사용하는 데이터베이스에 Fox DB Profile 이 생성하는 정보를 기록한다면 필연적으로 앱의 성능 저하 혹은 처리량 감소를 불러올 수 있습니다. 따라서 낮은 하드웨어 사양일지라도 별도의 서버에 데이터베이스를 구축하고 Fox DB Profile 정보를 기록하는 것을 권장합니다. PostgreSQL 과 같은 오픈 소스 RDB 데이터베이스를 사용하거나 MongoDB 와 같은 NoSQL 데이터베이스를 사용하여 별도 데이터베이스 구축에 소요되는 비용을 낮추는 것도 고려해 볼 수 있습니다.
전용 로거 작성¶
수집된 쿼리 수행 결과를 데이터베이스에 기록하고자 한다면 Fox DB Profile 을 위한 전용 로거를 작성하는 것이 좋습니다. 이 로거는 수집된 쿼리 수행 결과를 담는 FoxDbProfileInfo
객체를 데이터베이스에 기록하는 역할을 담당합니다.
Note
커스텀 로거를 작성하는 구체적인 방법은 별도의 문서를 참고 하십시요.
Fox DB Profile 전용 로거는 FoxDbProfileInfo
객체에 수집된 정보들 중 필요한 항목을 빠르게 데이터베이스에 기록해야 합니다. 다음 코드는 FoxDbProfileInfo
객체를 PostgreSQL 의 Jsonb
타입의 컬럼에 기록하는 로거 코드의 일부를 보여줍니다.
전용 로거에 대한 전체 예제 코드는 FoxDbProifle 활용 예제를 참고 하십시요.
로거의 WriteLog
메서드에 전달된 data
매개변수를 통해 전달된 로그 데이터는 FoxDbProfileInfo
객체입니다. 따라서 위 로거는 data
매개변수를 FoxDbProfileInfo
객체로 형변환한 후, json 으로 변환하여(ToJson()
메서드) Jsonb
타입의 info
컬럼에 저장합니다.
위 로거 코드에서 주목할 부분은 트랜잭션 관련 코드 입니다.
DB 프로파일 로그를 발생하는 코드는 매우 다양하며 Fox Transaction 을 사용하는 데이터 액세스 코드는 암시적으로 환경 트랜잭션(ambient transaction)을 사용할 수도 있습니다. 환경 트랜잭션이 활성된 상태에서 위 로그 기록 코드가 수행되면 로그를 기록하는 쿼리가 환경 트랜잭션에 자동으로 참여(enlist)하게 됩니다. 이 경우, 어떠한 이유에서 예외가 발생하면 트랜잭션이 롤백되며 로그 기록 역시 롤백될 수 있습니다. 하지만 로그 기록은 트랜잭션과 무관해야하므로 환경 트랜잭션에 참여하지 않도록 TransactionScope
객체를 Suppress
옵션으로 활성화 해야 합니다.
또, 위 코드는 성능 향상을 위해 DB 독립적인 FoxDbAccess
클래스 대신 PostgreSQL 에 대한 구체적인 FoxNpgsqlDbAccess
클래스를 사용합니다. PostgreSQL 이 제공하는 다양한 JSON 지원 중 Jsonb
타입의 컬럼을 활용하기 위함입니다.
이제 작성한 DB 프로파일 전용 로거를 사용하도록 연결 문자열로 로거 구성 설정을 수행하면 됩니다. 다음은 앱이 사용하는 데이터베이스가 Oracle 이며 DB 프로파일 로그를 기록하는 데이터베이스가 PostgreSQL 인 구성 설정 예를 보여 줍니다.
위 구성 설정에서 앱이 사용하는 데이터베이스 연결 문자열(Oracle
)에는 DB 프로파일이 활성화 되어 있고 사용할 로거는 ProfileLogger
를 지정하고 있습니다. ProfileLogger
로거는 위에서 살펴본 전용 로거를 사용합니다. 이 예의 경우, 로거 프로바이더 클래스가 dbprofile_usage.DbProfileLoggerProvider
입니다. 그리고 전용 로거는 connectionStringName
로거 속성을 사용하여 로그를 기록할 연결 문자열 이름으로 LoggingDb
를 사용하여 PostgreSQL 에 접속합니다.
Note
커스텀 로거의 로거 프로바이더 및 로거 속성에 관련한 상세한 내용을 커스텀 로거 작성 문서를 참고 하십시요.
분석 도구 작성¶
쿼리 수행 결과가 데이터베이스에 수집되었다면 수집된 데이터를 활용할 수 있는 도구를 작성하는 것이 권장됩니다. 단순한 감사의 목적이 아니라면 Fox DB Profile 을 통해 수집된 쿼리 수행 결과들은 다양한 목적으로 활용될 수 있습니다. 예를 들어 다음과 같은 질문에 대한 자료를 수집할 수 있습니다.
-
매일 13시~14시 동안 1.5초 이상 소요되는 쿼리들은 무엇인가?
-
지난 1주일 동안 오류를 발생한 쿼리들은 어떤 것들인가?
-
지난 1주일 동안 특정 쿼리(저장 프로시저)가 3초 이상 소요되었을 때의 매개변수들은 어떠한가?
위와 같은 질문들에 답할 수 있도록 FoxDbProfileInfo
객체들을 데이터베이스에 기록되어야 할 것이며 다음은 저장할 PostgreSQL 테이블의 예를 보여 줍니다.
앱의 규모에 따라 달라질 수 있지만 대부분의 상황에서 Fox DB Profile 이 생성하는 로그의 개수는 대단히 많습니다. 따라서 대개의 질의가 특정 기간 동안 발생한 로그 항목에서 자료를 찾도록 제한되는 것이 일반적입니다. 이렇게 기간이 대부분의 질의에 포함되므로 별도의 컬럼에 로그 발생 시간을 나타내는 컬럼을 사용하고 이 컬럼에 인덱스를 적용함으로써 대량의 데이터에서 빠르게 결과를 추출할 수 있도록 스키마를 고려해야 합니다.
만약 Fox DB Profile 을 사용하는 분석에서 쿼리 수행 시간이 자주 포함된다면 쿼리 수행 시간(ExecutionTime
속성) 역시 별도의 컬럼을 사용하고 인덱스를 적용하는 것이 좋습니다. 다음은 JSON 내부에 있는 수행 시간 속성을 사용하여 3초 이상 수행된 쿼리를 조회하는 예를 보여줍니다.
Fox DB Profile 을 통해 수집된 정보는 다양한 목적으로 사용이 가능하고 앱에서 구동되는 쿼리의 성능 분석을 위한 것이라면 자주 사용되는 질의를 별도의 앱으로 작성하여 전용 쿼리 성능 분석 도구를 작성하는 것도 좋은 방법 입니다.
Summary¶
Fox DB Profile을 효과적으로 활용하기 위한 팁과 구체적인 적용 방법을 요약하자면 다음과 같습니다.
-
활용 목적: 쿼리 감사, 성능 진단 및 분석, 모니터링 등 다양한 목적에 따라 Fox DB Profile을 설정하고 활용할 수 있습니다.
-
성능 고려 사항: 기능 활성화 시 발생할 수 있는 오버헤드를 최소화하기 위해 수집 범위와 저장 매체를 신중하게 선택해야 합니다.
-
작동 방식에 대한 이해:
FoxDbAccess
가 쿼리 수행 전후에 성능 측정을 하고, 수집된 정보를 비동기 또는 동기 방식으로 로거에 기록합니다. -
정보 수집 전략: 목적에 따라 모든 쿼리를 기록하거나 필터링 기능을 활용해 특정 조건의 쿼리만 기록할 수 있습니다.
-
전용 로거 및 로그 DB 구성: 성능 저하를 방지하기 위해 별도의 데이터베이스와 전용 로거를 사용하는 것이 권장됩니다.
-
분석 도구 작성: 수집된 데이터를 기반으로 다양한 성능 분석 질의를 수행할 수 있으며, 이를 위한 전용 도구 개발도 가능합니다.