2014-03-25 1 views
1

응용 프로그램은 Report이라는 객체를 계속 수신하고 객체를 서로 다른 세 가지 소비자에 대해 Disruptor에 저장합니다.직렬화의 성능 비용과 Java에서 객체 압축

Eclipse 메모리 분석을 사용하면 각 Report 오브젝트의 보유 된 힙 크기는 평균 20KB입니다. 응용 프로그램은 -Xmx2048으로 시작하여 응용 프로그램의 힙 크기가 2GB임을 나타냅니다.

그러나 개체 수는 한 번에 약 100,000 개이므로 개체의 전체 크기는 약 2GB입니다.

소비자가 데이터를 비동기 적으로 소비 할 수 있도록 모든 100,000 개의 개체를 Disruptor에로드해야한다는 요구 사항이 있습니다. 그러나 각 개체의 크기가 20KB 크기라면 불가능합니다.

그래서 나는 그것을 String에 개체를 직렬화하고 압축 싶습니다

Before compression

압축하기 전에 :

private static byte[] toBytes(Serializable o) throws IOException { 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    ObjectOutputStream oos = new ObjectOutputStream(baos); 
    oos.writeObject(o); 
    oos.close(); 

    return baos.toByteArray(); 
} 

private static String compress(byte[] str) throws IOException { 
    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    GZIPOutputStream gzip = new GZIPOutputStream(out); 
    gzip.write(str); 
    gzip.close(); 
    return new String(Base64Coder.encode(out.toByteArray())); 
} 

compress(toBytes(Report)) 후, 객체의 크기가 작 압축 후

After compression

지금 개체의 문자열은 약 6KB입니다. 지금은 더 좋습니다.

  1. 크기 문자열보다 작은 다른 데이터 형식이 있습니까 :

    여기 내 질문?

  2. 때마다 직렬화 및 압축을 호출하면 ByteArrayOutputStream, ObjectOutputStream 등의 개체가 생성됩니다. ByteArrayOutputStream, ObjectOutputStream과 같은 많은 객체를 만들고 싶지 않습니다. 왜냐하면 객체를 ByteArrayOutputStream, ObjectOutputStream과 같이 한 번만 만들고 각 반복에 사용할 수 있도록 코드를 어떻게 디자인해야합니까?

  3. 소비자는 역 직렬화하고 Disruptor에서 문자열을 압축 해제해야합니다. 세 명의 소비자가 있으면 세 번 deserialize하고 압축을 풀 필요가 있습니다. 주위에?


업데이트 : @BoristheSpider 제안으로

, 직렬화 및 압축 한 조치를 수행해야합니다 ObjectOutputStream에 압축을 사용하여

private static byte[] compressObj(Serializable o) throws IOException { 
    ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
    GZIPOutputStream zos = new GZIPOutputStream(bos); 
    ObjectOutputStream ous = new ObjectOutputStream(zos); 

    ous.writeObject(o); 
    zos.finish(); 
    bos.flush(); 

    return bos.toByteArray(); 
} 
+0

아마도 이것은 갈 길이 아닙니다. 성능에 큰 영향을줍니다. 이런 경우를위한 디자인 패턴이 있습니다. [Flyweight pattern] (http://en.wikipedia.org/wiki/Flyweight_pattern). 참고로 스트림을 직접 압축하면 어떨까요? 왜 당신은 처음에'byte []'를 만들고 나서 그것을 압축합니까? –

+0

앱이 사용자 지정 개체 인 '보고서'를받습니다. 내가하고있는 일은'Report'를 직렬화하고 직렬화 된 String을 압축하는 것입니다. 'Report'를 직접 압축하는 것이 좋습니다? – DerekY

+0

'ByteArrayOutputStream'을'GZIPOutputStream'_then an_'ObjectOutputStream'에 래핑하는 것이 좋습니다. 이 작업은 한 번의 작업으로 일련 화되고 압축됩니다. –

답변

0

이 훨씬 더 비싼 사용하는 것보다 Disruptor는 그것을 사용하는 목적에 어긋납니다. 1000 배 이상 비싸기 쉽습니다.

한 번에 대기중인 개체의 수를 제한하는 것이 훨씬 좋습니다.디자인에 중대한 문제가있는 경우를 제외하고는 단지 20,000 개의 개체가 포함 된 큐를 가지고 있으면 소비자가 효율적으로 작업 할 수있을 정도로 충분해야합니다.

BTW 지속성이 필요한 경우 필자는 부분적으로 필자가 작성했기 때문에 일부만 사용합니다. 압축 또는 바이트 [] 또는 스토리지가 필요하지 않으며 모든 메시지가 지속되고 큐는 제한되지 않고 완전히 힙을 벗어납니다. 100K 개체는 < < 1MB의 힙을 사용합니다.

+0

답변을위한 Thx Peter. 제 걱정거리는 소비자 데이터베이스가 뒤처져 뒤따라 가려하지 않는다는 것입니다. 'Disruptor'는 처리가 끝날 때까지 기다리고 있습니다. – DerekY

+0

@ user838204이 경우 나는 당신이 갈 때 데이터를 지속시킬 크로니클 (Chronicle)에 그것을 스풀링 할 것이고 데이터베이스가 1 시간 또는 1 일 뒤에 있는지 걱정할 필요가 없다. 중복성이 필요한 경우 Chronicle은 TCP 복제를 지원합니다. –

+0

@ user838204 또는 ActiveMQ와 같은 메시지 브로커 만 사용하십시오. 그것은 메시지 등을 지속하도록 구성 할 수 있습니다. –