며칠전에 사석에서 상사분이 Tomcat은 IIS에 비해서 connection을 적게 받고, 그로 인해서 성능이 떨어진다고 말씀을 하시네요.. ^^;; 서비스의 전체적인 성능 문제가 Java 및 Tomcat에 기인을 하고 있다고 생각을 하는것 같아서.. 같은 개발자 입장에서 타 분야에 대한 경험으로 얘기하는게 아니라 말 그대로 선입견(Overlapped I/O의 성능만 말씀하시네 ^^;;)으로 얘기를 하는 듯한 느낌이었습니다.
 
서비스의 성능저하는 Tomcat이나 IIS보다는 그 위에 올라가는 어플이 더 성능에 영향을 미칠텐데 말입니다. ^^;;
그래서 IIS 기반의 ASP.NET 서비스들이 주로 사용하는 DataSet에 대해서 Serialize 데이타에 대해서 살펴보았습니다. 비교는 단순하게 Java , C# Object, C# DataSet으로 10개의 리스트를 가지는 모델을 가지고 하였습니다.

아래의 코드로 Java에서의 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 < 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);
            table.Columns.Add(itemName);
            table.Columns.Add(itemAddress);

            DataRow row;

            for (int i = 0; i < 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

네트웍을 통해서 전송되는 Data의 크기는 성능에 중요한 영향을 미치지요..
실제로 성능을 높이기 위해서 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 어플들의 서비스가 더 성능이 안 좋을 거라는 생각이 드네요... ^^;;;;

Restart IIS from remote computer

from os 2009/11/25 10:06
Windows의 IIS에 배포를 위해서 xcopy 같은 명령어를 많이 사용하는데, 그런경우 copy가 되는 도중에 IIS가 읽어버리면 계속 cache miss 어쩌구 저쩌구 에러로그가 계속 쌓입니다. 그런 경우 해결책이 웹서버 리스타트 인데요..  iisreset 으로 리스타트를 합니다.  여러대의 서버에 배포를 하고 iis reset을 하기 위해서는 아래는 참고하시면 좋은 팁이 될듯 합니다.^^

파일 카피

restart iis from remote computer
iisreset.exe \\computer_name
or
sc.exe \\computer_name stop w3svc
sc.exe \\computer_name start w3svc





Tag // IIS, iisreset, windows