Java vs C# Serialize 비교와 C# DataSet을 쓰지 말아야 되는 이유(?)

며칠전에 사석에서 상사분이 톰캣(Tomcat)은 IIS에 비해서 connection을 적게 받고, 그로 인해서 성능이 떨어진다고 말씀을 하시네요. ^^;; 서비스의 전체적인 성능 문제를 자바(Java)나 톰캣이 문제가 있다는 시각이어서, 자바쪽의 경험치로 말씀하시는게 아니라 선입견(Overlapped I/O의 성능만 말씀하시네 ^^;;)으로 얘기를 하고 있다는 느낌이 많이 받았습니다. 대체로, 서비스의 성능 이슈는 톰캣이나 IIS보다 그 위에 올라가는 애플리케이션이 더 성능에 영향을 미칠텐데 말입니다. ^^;;

그래서 IIS 기반의 ASP.NET 서비스들이 주로 사용하는 DataSet에 대해서 Serialize 데이타에 대해서 살펴보았다. 비교는 단순히 자바, C# Object, C# DataSet으로 10개의 리스트를 가지는 모델을 가지고 했다. 아래의 코드로 자바에서의 Object Array, C#에서의 Object Array, C#에서의 DataSet의 Serialize된 객체의 사이즈를 알 수 있다. 단순하게 Serialize하는 속도 및 Deserialize하는 속도는 같다고 가정을 한다.

* Java
– SerializeModel.java

import java.util.ArrayList;
import java.io.Serializable;
public class SerializeModel implements Serializable {
  private static final long serialVersionUID = -7168303693593724718L;
  private int count = 0;
  private String name = null;
  private String address = null;
  private ArrayList<SerializeModel> models = new ArrayList<SerializeModel>();

  public SerializeModel(int count, String name, String address) {
    this.count = count;
    this.name = name;
    this.address = address;
  }

  public void addModel(SerializeModel model) {
    this.models.add(model);
  }
}

– SerializeTest.java

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class SerializeTest {
 
  public static void main(String[] args) throws Exception {
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("java.ser"));
    SerializeModel model = new SerializeModel(0, "a", "b");
    
    for(int i=0; i<10; i++) {
      model.addModel(new SerializeModel(i, i +" name", i +" address"));
    }

    out.writeObject(model);
    out.flush();
    out.close();
  }
}

* C#

– SerializeModel.cs

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Collections;
using System.Collections.Generic;
namespace SerialzieTest
{
  [Serializable()]
  class SerializeModel
  {
    private int count = 0;
    private String name = null;
    private String address = null;
    private ArrayList models = new ArrayList();
    public SerializeModel(int count, String name, String address) 
    {
      this.count = count;
      this.name = name;
      this.address = address;
    }

    public void AddModel(SerializeModel model) 
    {
      this.models.Add(model);
    }
  }
}

– SerializeModelDataSet.cs

using System;
using System.Data;
using System.Collections.Generic;
using System.Text;

namespace SerialzieTest
{
  [Serializable]
  class SerializeModelDataSet
  {
    private DataSet dataSet = new DataSet();
    public void AddDataTable(DataTable table) 
    {
      this.dataSet.Tables.Add(table);
    }

    public DataSet GetDataSet()
    {
      return this.dataSet;
    }
  }
}

– Program.cs

using System;
using System.Data;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace SerialzieTest
{
  class Program
  {
    static void SerializeObjectArray()
    {
      Stream stream = File.Open("csharp.ser", FileMode.Create);
      BinaryFormatter bformat = new BinaryFormatter();
      SerializeModel model = new SerializeModel(0, "a", "b");

      for (int i = 0; i &lt; 10; i++)
      {
        model.AddModel(new SerializeModel(i, i + " name", i + " address"));
      }
      
      bformat.Serialize(stream, model);
      stream.Flush();
      stream.Close();
    }

    static void SerializeDataSet()
    {
      Stream stream = File.Open("csharp_dataset.ser", FileMode.Create);
      BinaryFormatter bformat = new BinaryFormatter();
      SerializeModelDataSet model = new SerializeModelDataSet();
      DataTable table = new DataTable();
      DataColumn itemCount = new DataColumn("count", Type.GetType("System.Int32"));
      DataColumn itemName = new DataColumn("name", Type.GetType("System.String"));
      DataColumn itemAddress = new DataColumn("address", Type.GetType("System.String"));
      table.Columns.Add(itemCount);</span>
      table.Columns.Add(itemName);
      table.Columns.Add(itemAddress);

      DataRow row;
      for (int i = 0; i &lt; 10; i++)
      {
        row = table.NewRow();
        row["count"] = i;
        row["name"] = i + " name";
        row["address"] = i + " address";
        table.Rows.Add(row);
      }

      model.AddDataTable(table);
      bformat.Serialize(stream, model);
      stream.Flush();
      stream.Close();
    }

    static void Main(string[] args)
    {
      SerializeObjectArray();
      SerializeDataSet();
    }
  }
}

위 코드를 사용해서 저장한 Object의 사이즈는 아래와 같습니다.

Java(Object ArrayList) : 665 byte
C#(Object ArrayList) : 1035 byte
C#(DataSet) : 3000 byte

네트웍으로 전송되는 데이터의 크기는 성능에 중요한 영향을 준다는 것은 이미 알고 있다. 성능을 높이기 위해서 Socket Buffer의 사이즈를 적당히 줄이는 것도 팁중의 하나이다. 그리고, 위 코드로 만들어지는 C#의 DataSet은 더욱 멋진 모습을 보여준다. 아래의 화면처럼 말이죠.. 아래의 화면은 Hex Viewer로 본 화면이다.

Object의 Serialize는 C#이 version, locale 및 가비지(?) 데이타로 인해서 좀 더 크게 나온다. 그리고, 중간의 DataSet은 Serialize된 내용을 보면, xml의 형태로 데이터를 저장하고 있다. 결국 DataSet을 데이타로 직렬화해서 네트웍으로 전송하게 되면, 데이터 크기보다는 Serialize/Deserialize할때의 String연산(XML 데이타 리드)이 성능저하의 주범이 될 것 같다. 결국, Tomcat, IIS가 중요한게 아니라 C#에서 널리 쓰이는 DataSet을 많이 사용하고 있는 IIS기반의 ASP.NET 어플들의 서비스가 더 문제가 아닐까 생각한다.

Java vs C# Serialize 비교와 C# DataSet을 쓰지 말아야 되는 이유(?)”에 대한 8개의 생각

  1. 123

    직렬화 하나로 DataSet을 쓰지 말아야 하는 이유라고 하기엔..너무 빈약합니다..웹어플리케이션에서 직렬화를 하는 경우는 웹서비스를 사용하는 경우 빼고는 거의 없기도 하구요..사실 DataSet이 상당히 무거운 Class이긴 합니다만 개발 편의성에서 무시하기 힘든 장점이 있는 것 또한 사실이죠.. 대강 써보면 이게 뭐 편하다고(?)할 수 있겠지만.. 제가 개발할때는 DataSet을 쓰진 않습니다만.. ㅎㅎ

    응답
    1. mcsong

      DataSet의 개발 편의성은 탁월하다는 거에는 동의 합니다.
      하지만, 위에서 기술하는 내용이 직렬화 하나만으로 DataSet을 쓰지 말야야 된다는게 아닙니다.
      성능저하의 주범이 된다는 내용이지요.
      따라서, 성능을 중요하게 생각한다면, DataSet을 사용하지 않는것이 좋다(맞다?)는 것이구요.
      위 코드는 DataSet을 이용해서 성능을 저하시키는 예구요..
      님께서 말씀하시는, 웹 어플리케이션에서만 주로 사용한다고 하셨으나, 그 이유가 3-Tier 형태에서 DataSet으로 Serialize하고 Deserialize 하기 편하기 때문이겠죠..
      그리고, 제가 재직하고 있는 회사에서는 웹 서비스가 아닌 어플리케이션단에서의 DataSet도 종종 Serialize/Deserialize 하고 있네요.. ^^;;

      응답
  2. Nasky

    확실히 DataSet(DS) 자체가 무거운건 누구나 인정하는 사실이지만 관리 테이블이 다수일경우 관리적 측면에서 DS가 용이하기 때문에 자주 사용되는건 아닐까요? 흠.. 그리고 다른 언어로 주개발을 안해봐서 잘 모르겠지만 DS가 주로 느리다고 생각되는 이유가 View를 많이 써서 그런건 아닌가요? View에서 Data 처리시 매우 느려 바운딩소스를 찾아 DS.Table.Row를 직접 컨트롤 하면 어느정도 성능은 나온다고 생각 합니다만…
    또한 프레임워크 내부 컨트롤에서 바운딩하기 쉬운것도 DS인것 같구요. 리포트 연동이나 그럴때 관련 객체를 만드는 것보다 상위 DS를 동적으로 관리하면서 저장소로 이용한다면 이것또한 어떤 측면에서 성능이 좋을것 같다고 생각됩니다… 보통 DS 자체를 소켓을 통해 주고 받는것은 안하지 않나요? 저같은 경우 Row단을 Array로 바꿔 보내는것이 보통일것이라고 생각됩니다. 아니면 Paging 처리를 통해 보내는 방법도 있고… 흠
    제가 내공이 낮아서 제대로 생각한건지 모르겠네욤 흠흠흠

    응답
    1. mcsong

      관리적 측면이 아니라, 편리함으로 인해서 사용하는 거겠죠.. 프레임웍에서 바인딩되는 것 역시, 편리해서 쓴다는 거겠죠..
      리포트 연동같은 특별한 이슈는 모르겠습니다. 그리고, DS를 시리얼라이즈해서 네트웍을 통해서 주고 받는 경우는 많을것으로 생각이 드네요..
      답이 되었는지 모르겠네요.. ^^;;

      응답
  3. 나그네

    글쎄요. 두가지를 비교하고자 하면 같거나 동등한 것을 비교해야 한다고 봅니다.
    DataSet은 object array와 비교 대상이 안됩니다. DataSet은 훨씬 더 더양하고 많은 기능을 가지고 있기 때문입니다.
    또한 DataSet의 직렬화 결과가 큰 이유는 일반적인 객체 직렬화 대신 Diffgram이라 불리는 고유의 직렬화 포맷을 사용하기 때문입니다. Diffgram은 직렬화된 결과에 DataSet 내의 DataTable, DataRow의 변경 사항들을 모두 포함하도록 하기 때문입니다. 그리고 이 Diffgram의 기본 형태는 XML 입니다. BinaryFormatter를 사용하더라도 마찬가지 이지요. 따라서 DataSet의 RemotingFormat 속성 값을 SerializationFormat.Binary로 지정해 주어야 합니다.
    그리고 말씀하신대로 성능은 Tomcat 이냐 IIS냐가 문제가 아닙니다. 대부분의 어플리케이션 성능은 어플리케이션 코드(SQL 쿼리 포함)에 의해 좌우 됩니다. DataSet을 사용하더라도 빠른 어플리케이션을 작성할 수 있습니다.

    응답
    1. mcsong@gmail.com

      동등한 것을 비교한다고 하면, 어떤게 동등할 수 있을까요?
      자바가 ArrayList니 MS도 ArrayList로 해야 할까요? 위에서 제시한 방향은 각 플랫폼에서 많이 사용하는 타입을 기준으로 했고, MS의 DatasSet과 비교할 수 있는 타입이 자바에서는 없는 것으로 알고 있습니다.

      그리고, MS 기반의 프로그래밍 경험이 조금은 있어서, DataSet 편리성에는 동의를 합니다.
      DataSet을 가지고도 빠른 어플리케이션을 작성할 수 있습니다. 네 그렇죠.. 하지만, 게임서버와같은 고 성능의 서버와 통신하는 미들웨어에서 데이터 처리를 DataSet으로 처리하다가 낭패를 본 경우를 종종 봐서요.. 그리고, 빠르다라는게 상대적인 거라서..

      혹시, DataSet과 비교할 만한 대상을 좀 알려주시면 한번 해 보겠습니다.
      감사합니다.

      응답
  4. 남뉴

    Base64로바꾸로 DataSet을 압축해서 보낼경우 3000byte가 665~1000byte로 줄기도 하죠. 다만 PDA같은 Compact에서 없으니 Serialization에서 제공하는 3가지로 써서 가는게 맞지만요

    응답
  5. ㅁㅁㅁ

    멋진 분석이네요

    시간이 지나도 매우 잘 참고가 되었습니다.

    지금은 어떤 일을 하고 계실지 궁금하네요

    감사합니다.

    응답

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.