레이블이 멀티쓰레드인 게시물을 표시합니다. 모든 게시물 표시
레이블이 멀티쓰레드인 게시물을 표시합니다. 모든 게시물 표시

2010년 1월 30일 토요일

데이터베이스 연결과 멀티쓰레드 프로그래밍

일반적으로 데이터베이스와 상호작용하는 프로그램을 만드는 경우, 데이터베이스와 통신을 하기 위해 먼저 데이터베이스와 연결을 설정한 다음, 입력, 조회, 수정, 삭제 등 필요한 작업을 수행하고 최종적으로 연결을 끊어주게 된다. 이 때, 데이터베이스와 연결을 설정하거나 연결을 해제하는데 생각 외로 많은 시간이 걸리게 된다. 많은 경우, 특히 실질적인 작업의 내용이 간단한 경우에는 이들 연결의 설정과 해제에 걸리는 부하가 프로그램의 퍼포먼스를 저하하는데 큰 기여를 하게 되는 경우가 많다.

특히 여러 개의 쓰레드가 데이터를 만들어서 데이터베이스로 저장하는 경우를 생각해보자. 프로그램의 효율을 위해 여러 개의 쓰레드로 동시에 작업을 처리하도록 만들었지만, 각각의 쓰레드가 매번 데이터베이스 연결을 설정하고 작업을 한 다음 해제를 한다면, 데이터베이스 작업에 상당한 부하가 걸리고 수많은 비효율이 발생할 수 밖에 없다. 데이터베이스와 연결을 제외하면 멀티쓰레드가 단일 쓰레드를 사용하는 것보다 훨씬 효율적으로 데이터를 처리할 것이다. 하지만, 처리된 데이터를 데이터베이스에 저장해주는 부분이 추가되면, 단일 쓰레드를 사용하는 것이 멀티쓰레드들을 이용하여 매번 연결을 설정하고 해제해주는 방식보다 효율적일 수 있다.

앞의 방식의 또 한가지 문제점은 데이터베이스와 연결이 많아진다고 해서 성능이 항상 향상되지는 않는다는 점이다. 특히 모든 쓰레드들이 동일한 테이블에 대해 데이터를 저장하는 경우에는 해당 테이블에 index라도 걸려있게 되면, 하나의 연결이 설정되어 작업이 진행되는 동안 락(lock)이 걸려서 다른 연결들은 작업을 진행하지 못하고 대기하게 된다. 그러므로 무작정 데이터베이스의 연결 수를 늘려주는 것은 바람직하지 못하다.

위의 두가지 문제점을 극복할 수 있는 방법을 한번 고민해보자. 어떻게 하면 데이터베이스 연결 설정과 해제의 부하를 최소하시키면서 적절한 수의 연결을 유지할 수 있을까? 직관적으로 생각할 수 있는 것이 바로 여러 쓰레드들이 몇몇 연결을 공유하는 방식이다. 먼저 몇개의 연결을 설정해놓으면 가장 효율적으로 데이터베이스를 통해 작업을 할 수 있는지 파악을 한다. 그 다음은 각각의 쓰레드에서 연결을 설정하고 해제하지 말고, 아예 메인 프로그램에서 적절한 수의 연결을 미리 설정해 놓는 것이다. 그리고 쓰레드들은 해당 연결을 공유하는 방식을 취하는 것이다.

여기에서 고려해야할 점은 데이터베이스를 통한 작업의 세부 프로세스들이 매우 밀접하게 묶여 있다는 것이다. 예를들어 데이터로부터 특정한 데이터를 조회하는 경우를 생각해보자. 먼저 쓰레드에서 Statement 객체를 설정하여 설정된 연결을 통해 데이터베이스로 보낼 것이다. 다음은 ResultSet 객체로 데이터베이스로부터 결과를 받아 처리하고, ResultSet 객체와 Statement 객체를 종료해주게 된다. 중요한 것이 이 Statement 객체 설정부터 ResultSet 객체의 종료까지가 하나의 프로세스 단위가 되어야 한다는 점이다. 다시 말해, 어느 한 쓰레드가 이 프로세스에 있는 동안에는 다른 쓰레드는 해당 연결을 사용해서는 안된다는 점이다.

어떤가? 쓰레드들을 이용하여 연결을 공유하는 방식을 위해, 앞서 이야기 한 프로세스 단위를 그대로 Thread-safe하게 처리하기 위해 코드가 복잡해지는 것을 감안한다면, 얻는 소득은 거의 미비할 것이다. 실제로 MySQL 사이트의 문서들에서도 멀티쓰레드에서 데이터베이스 연결을 공유하는 것은 그다지 성능향상에 도움이 되지 않는다고 한다.

좀더 우아한 방식은 아파치의 DBCP와 같은 database pool을 이용하는 것이다. 이들 라이브러리를 통해 데이터베이스 연결 갯수를 제한하고, 쓰레드들은 해당 pool에서 이미 설정된 연결들을 사용하고 사용이 끝난 후에는 반환을 해주는 방식을 사용하면 된다. 물론 database pool 자체를 구현하는 것 역시 추가적인 코딩을 요구한다. 하지만, DBCP와 같은 널리 사용되는 라이브러리를 이용하면, 거의 쓰레드에서 직접 데이터베이스 연결을 설정하고 해제하는 방식과 같은 양의 코드로 손쉽게 구현이 가능하다.

결론적으로 데이터베이스와 빈번한 연결이 필요한 멀티쓰레드 프로그램을 구현할 때는 Connection Pool을 이용하는 것이 가장 좋은 방법이라고 추천을 하고 싶다. Connection Pool을 설정하고 사용하는 방법에 대해서는 다음 기회에 자세히 설명해보도록 하겠다.