풀링 패턴 (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;
}
|
헤드 퍼스트 디자인 패턴:14가지 GoF 필살 패턴! - 프로그래밍 언어 | 쿠팡
쿠팡에서 헤드 퍼스트 디자인 패턴:14가지 GoF 필살 패턴! 구매하고 더 많은 혜택을 받으세요! 지금 할인중인 다른 프로그래밍 언어 제품도 바로 쿠팡에서 확인할 수 있습니다.
www.coupang.com
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."