HttpClient로 빈번히 connection을 맺었다가, 사용이 끝나면 끊고 하다 보면 더 이상 connection을 열 수 없는 경우가 발생할 수 있다.
그 이유는 connection을 닫는다고 호출을 해도, 실제로는 어느 정도 TIME_WAIT 상태에 있다가 끊어지는데 이런 것들이 많이 쌓여 있으면 File Descriptor가 꽉 찼다는 에러(Too Many Open Files)가 나면서 connection을 맺지 못 하게 된다.
이런 현상을 방지하기 위해서는 Connection을 재사용할 수 있도록 HttpClient에서 제공하는 Connection Pool을 사용하는 것이다.


<사용 라이브러리>
httpclient-4.2.3.jar, httpcore-4.2.2.jar

public class ConnectionManager {

private static PoolingClientConnectionManager connectionManager = null;
public static synchronized HttpClient getHttpClient() {
if (connectionManager == null) {
connectionManager = new PoolingClientConnectionManager();
connectionManager.setMaxTotal(50);
connectionManager.setDefaultMaxPerRoute(20);
}

return new DefaultHttpClient(connectionManager);
}

public static void abort(HttpRequestBase httpRequest) {
if (httpRequest != null) {
try {
httpRequest.abort();
} catch (Exception e) {}
}
}

public static void release(HttpResponse response) {
if (response != null && response.getEntity() != null)
EntityUtils.consumeQuietly(response.getEntity());
}
}


요런 식으로, static으로 PoolingClientConnectionManager 를 하나 선언해 두고, 최초로 getHttpClient를 호출할 때 Connection Pool이 지정된 사이즈로 생성된다. 그리고, Connection을 하나 만들어 리턴한다.

- maxTotal : Connection Pool의 수용 가능한 최대 사이즈
- defaultMaxPerRoute : 각 host(IP와 Port의 조합)당 Connection Pool에 생성가능한 Connection 수


protected <T> T get(String url) {
HttpClient httpClient = null;
HttpGet httpGet = null;
HttpResponse response = null;
try {
httpClient = ConnectionManager.getHttpClient();
httpGet = new HttpGet(url);
response = httpClient.execute(httpGet);

StatusLine statusLine = response.getStatusLine();
// 에러 발생
if (statusLine.getStatusCode() < 200 || statusLine.getStatusCode() >= 300) {
throw new Exception(statusLine.getStatusCode(), getReason(response));
}
// 성공
else {
                            // do something
}
} catch (ClientProtocolException e) {
e.printStackTrace();
ConnectionManager.abort(httpGet);
throw e;
} catch (IOException e) {
e.printStackTrace();
ConnectionManager.abort(httpGet);
throw e;
} finally {
ConnectionManager.release(response);
}
}

Connection Pool은 요런 식으로 이용하면 되겠다. 위는 GET 방식 사용시.


Pool을 사용할 때마다 항상 주의할 것은 역시 반환을 꼭 해 줘야 한다는 것!!!
Exception이 발생하면 abort를 호출해서 정리해 주고, finally에선 항상 EntityUtils.consumeQuietly를 호출해서 리소스를 반납하게 해 준다.


AND

IE나 Firefox에서는 보통 쓰던대로 아래와 같이 넘기고 받으면 끝이었다.


Parent.html

    var retVal = window.showModalDialog("popup.html", null,);

    if (retVal) {

        $("#some_id").val(retVal.some_id);

        $("#some_name").val(retVal.some_name);

    }


popup.html

function fn_Click(some_id, some_name) {

    var obj = new Object();

    obj. some_id  =  some_id ;

    obj. some_name = some_name ;

    window.returnValue = obj;

    self.close();

}


그런데, Chrome에서는 popup에서 받은 retVal이라는 변수가 undefined이다.

이럴 때 아래와 같이 Chrome 브라우저에 대한 추가처리코드를 추가해 주면 해결된다.


Parent.html

    var retVal = window.showModalDialog("popup.html", null,);


    if (retVal == undefined)

    retVal = window.returnValue;


    if (retVal) {

        $("#some_id").val(retVal.some_id);

        $("#some_name").val(retVal.some_name);

    }


popup.html

function fn_Click(some_id, some_name) {

    var obj = new Object();

    obj. some_id = some_id ;

    obj. some_name = some_name ;

    if (window.opener)

        window.opener.returnValue = obj; 

    window.returnValue = obj;

    self.close();

}



'Java_Web' 카테고리의 다른 글

대용량 파일 조회 및 문자열 찾기  (0) 2015.03.10
HttpClient Connection Pooling  (0) 2015.03.10
JD Java Decompiler  (0) 2010.04.19
Hibernate에서 CLOB 컬럼 사용하기  (0) 2009.12.16
HQL UNION 제약사항  (0) 2009.08.21
AND


Django에서는 Cache 기능도 제공한다.

memcached, DB, 로컬메모리, 파일(?) 등의 종류를 제공하는데 각각 장단점이 있다.


memcached는 외부 캐쉬프로세스를 띄워 놓고, 거기에 

DB 방식의 경우는 여러 인스턴스가 동일한 DB를 바라보니까 모두 같은 데이터를 사용할 수 있겠지만, 속도는 좀 느릴 것이고,

로컬메모리 방식은 각 인스턴스가 자기 메모리에 각각 cache하니까 다른 데이터를 사용할 수 있는 가능성이 있겠지만, 속도는 빠를 것이고,

파일은 DB와 비슷할 것 같다.


나는 설정할 것이 별로 없고 빠른 로컬메모리 방식을 선택했다.

거의 변경가능성이 희박한 데이터를 cache한다면, 로컬메모리 방식이 가장 좋을 듯하다.


일단 settings.py에 cache를 사용하겠다고 설정을 해 줘야 한다.

CACHES = {

    'default': {

        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',

        'TIMEOUT': 3600,

    }

}


이렇게 하면, Local Memory 방식의 cache를 사용하고, 3600초(1분) 단위로 cache 들어간 데이터가 삭제한다는 뜻이다.


다음은 코드에서 사용하기만 하면 된다.

from django.core.cache import cache


cache.set('key', value)
cached_val = cache.get('key')


아주 간단하다.

cache를 import 하고, cache.set으로 집어 넣고, cache.get으로 꺼낸다.


이것을 응용해서 구현을 한다면,

get해서 나온 값이 None이면 넣을 데이터를 조회하거나 만들어서 set을 하면 되겠다.

cache에는 어떤 값이나 객체도 넣을 수 있는 것 같다.


이외에도 get_many로 한번에 여러 key를 리스트로 던지면, key와 value로 구성된 dict로 리턴하는 함수도 있고,

cache에서 내용을 지우는 delete, 전체를 지우는 clear 함수도 있다.


다시 매뉴얼을 보니 화면단에서도 cache를 사용할 수 있는데, 필요한 분들은 매뉴얼을 보시길...


'Python_Django' 카테고리의 다른 글

decorator 만들기  (0) 2012.07.25
hash(digest) 호출  (0) 2012.07.25
request의 값 처리  (0) 2012.07.25
CSRF token 생성  (0) 2012.07.25
Django의 session 처리  (0) 2012.07.13
AND