풀링 패턴 (Pooling Pattern)
Pooling Pattern - 풀링 패턴
자주 사용되는 리소스에 대해 Provider에서 사용할때마다 생성, 반환시 성능상의 문제가 있다.
최초 정해진 갯수의 리소스를 초기화하여 Pool에 미리 만들어놓고 필요할때마다 사용하여 성능을 높일 수 있다.
캐시와의 차이점은 같은 종류의 리소스를 사용하므로 Identified가 필요하지 않다.
문제 예시) Web-based e-commerece Solution
클라이언트 유저들이 하나의 전자상거래 웹 서비스 카탈로그를 요청하게 되면, 서버에서는 서블릿(servlet)이 Database와 커넥션(할당 - 해제)을 맺어 데이터를 유저에게 다시 Response 해주는 부분을 보여주고 있다.
하지만 다수의 클라이언트가 동시 접속하여 서비스를 요청하게 된다면 서버와 데이터베이스의 커넥션은 수많은 할당, 해제가 일어나야 될 것이다. 여기에서 성능상의 문제와 함께 서비스가 제대로 이루어지기 힘들어질 것이다. 이를 해결하기 위해서 Pooling Pattern을 사용하게 된다.
풀링 패턴 (Pooling Pattern) 설계 시 필요 사항
- 리소스 재사용이 가능해야한다
- 성능을 보장해야 한다
- 리소스의 빠른 재사용이 가능해야한다
- 구조가 복잡하지 않아야 한다.
- 메모리 할당 해제 반복시 단편화(flagment)가 발생하므로 최소화 필요
Pooling Pattern 사용 범위
데이터베이스 or 네트워크 커넥션, 오브젝트 인스턴스, 스레드, 메모리 및 기타 등등
Resource Pool 시나리오)
- Resource Pool에 미리 Resource들을 생성 및 관리해 놓는다.
- 유저의 요청으로 리소스를 요청(acquire)를 하게 되면 이미 만들어진 Resource Pool에서 Resource를 얻어와서 사용을 하고 사용이 끝나면 release를 통해 Resource Pool 로 반환한다.
- 만약 Resource Pool에 더이상 Resource가 없을 경우 Resource Environment를 통해서 새로운 Resource를 요청 생성하고, leasing 기법을 통해서 해제 한다. (Leasing Pattern)
<Connection Pool Design 예시>
예제 코드 다이어그램)
예제 코드)
Pool.h
1 2 3 4 5 6 7 8 9 10 | #pragma once class CResource; class CPool { public: virtual CResource* aquire() = 0; virtual void release(CResource* res) = 0; }; |
Resource.h
1 2 3 4 5 6 7 | #pragma once class CResource { public: virtual void* getConnection() = 0; }; |
ConnectionPool.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #pragma once #include <list> class CConnectionPool : public CPool { public: CConnectionPool(unsigned int poolSize); virtual ~CConnectionPool(); public: CResource* aquire(); void release(CResource* res); protected: CResource* findNewConnection(); private: list<CResource*> m_pool; }; |
ConnectionPool.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | #include "stdafx.h" #include "ConnectionPool.h" // 생성자 CConnectionPool::CConnectionPool(unsigned int poolSize) { // 풀 사이즈만큼 커넥션 생성 for (int i = 0; i<poolSize; i++) { CResource* resource = new CConnection; m_pool.push_back(resource); } } // 소멸자 CConnectionPool::~CConnectionPool() { // 모든 커넥션 메모리 해제 for each (CResource* entry in m_pool) delete entry; m_pool.clear(); } // 커넥션 얻기, 없으면 생성 반환 CResource* CConnectionPool::aquire() { CResource * resource = NULL; if (NULL == (resource = findNewConnection())) { resource = new CConnection; m_pool.push_back(resource); } return resource; } // 커넥션 반환 void CConnectionPool::release(CResource* res) { for each (CResource* entry in m_pool) { if (entry == res) { static_cast<CConnection*>(entry)->setInUse(true); break; } } } // 사용 가능 커넥션 찾기 CResource* CConnectionPool::findNewConnection() { for each (CResource* entry in m_pool) { if (!static_cast<CConnection*>(entry)->getInUse()) { static_cast<CConnection*>(entry)->setInUse(true); return entry; } } return NULL; } |
Connection.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #pragma once #import "C:\\Program Files\\Common Files\\System\\ado\\msado15.dll" rename("EOF", "EndOfFile") no_namespace typedef struct { long ticks; int hour; int minutes; int seconds; int month; int day; int year; } DATETIME; class CConnection : public CResource { public: CConnection(); virtual ~CConnection(); public: void* getConnection(); void setInUse(bool value); bool getInUse(); private: bool m_currentlyUsed; DATETIME mlastUsage; _ConnectionPtr m_connection; }; |
Connection.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | #include "stdafx.h" #include <time.h> CConnection::CConnection() : m_currentlyUsed(false) { // 연결 m_connection.CreateInstance(__uuidof(Connection)); m_connection->CursorLocation = adUseServer; m_connection->Open(L"연결 프로바이더 설정", L"", L"", adConnectUnspecified); } CConnection::~CConnection() { if (m_connection) { m_connection->Close(); m_connection = NULL; } } void* CConnection::getConnection() { return m_connection; } void CConnection::setInUse(bool value) { // 사용 날짜 시간설정(Leaseing Pattern 이용 목적) if (value) { time_t seconds = time(NULL); struct tm* timeinfo = localtime(&seconds); mlastUsage.ticks = seconds; mlastUsage.hour = timeinfo->tm_hour; mlastUsage.minutes = timeinfo->tm_min; mlastUsage.seconds = timeinfo->tm_sec; mlastUsage.month = timeinfo->tm_mon; mlastUsage.year = timeinfo->tm_year; mlastUsage.day = timeinfo->tm_mday; } m_currentlyUsed = value; } bool CConnection::getInUse() { return m_currentlyUsed; } |
Main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | int _tmain(int argc, _TCHAR* argv[]) { CoInitialize(NULL); // 풀 갯수 지정 풀생성 CPool* mPool = new CConnectionPool(5); // 리소스 요청 CResource* pResource = mPool->aquire(); // 리소스 사용.... // 리소스 반환 mPool->release(pResource); delete mPool; CoUninitialize(); return 0; } |
'Gof Design Pattern' 카테고리의 다른 글
동기화 패턴 : 스레드 안전 인터페이스(Synchronization Patterns : Thread Safe Interface) (0) | 2014.02.21 |
---|---|
동기화 패턴 : 범위 잠금 (Synchronization Patterns : Scoped Locking) (0) | 2014.02.21 |
해석자 패턴 (Interpreter Pattern) (0) | 2014.02.08 |
방문자 패턴 (Visitor Pattern) (0) | 2014.02.04 |
중재자 패턴 (Mediator Pattern) (0) | 2014.02.04 |