태그 보관물: tomcat

톰캣 웹 어플리케이션의 클래스 패스..

웹 어플리케이션들은 보통 아래의 구조를 가지고 있습니다.

WEB-INF
  -lib
  -classes

그리고, 각 어플리케이션마다 별도의 클래스 로더가 클래스들을 로딩합니다..
그런데.. 위의 lib 폴더는 클래스 패스로 안 잡네요.. ^^;;
어쩐지, 각종 프레임웍들의 설정파일들이 classes 폴더에 넣는 이유가 있었네요.. ^^;;

tomcat 하위 버전의 memory leak에 대한 내용..

이것도 문서를 정리하다가 발견했네요. ^^

1. 톰캣 메모리 릭 : http://java.dzone.com/articles/memory-leak-protection-tomcat
 웹 어플리케이션을 로딩할때, 클래스 로더가 각 어플리케이션별로 세팅이 되고, 이 로더가 클래스를 다시 로딩하면서 기존의 클래스들에 대한 reference를 클래스 로더가 유지를 하고 있어서 eden 영역의 메모리가 차는 현상이 발견. 결과로 OutOfMemory Error

2. 패치 : 7.0대 버전에서 발견되서, 6.0.24  버전(http://mirror.khlug.org/apache/tomcat/tomcat-6/v6.0.24/RELEASE-NOTES)에 반영

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 어플들의 서비스가 더 문제가 아닐까 생각한다.

Application Server(Tomcat)의 효과적인 운영 방안

1. 어플리케이션 서버에서 필요한 메모리 계산 방법
 – 계산식 : (MaxProcessMemory – JVMMemory – ReservedOsMemory) / (ThreadStackSize) = Number of threads
 – 메모리 계산 예
가정 : Java 1.5를 사용중이며 OS가 120MB를, 디폴트 스택사이즈는 0.5M


  • JVM에 1.5GB할당되었을 경우 : (2GB-1.5Gb-120MB)/(1MB) = ~380 threads
  • JVM에 1.0GB할당되었을 경우 : (2GB-1.0Gb-120MB)/(1MB) = ~880 threads
통계적으로 대략 200명의 동시 사용자 수용할 경우 300MB정도 필요하합니다. 이것을 고려해서 메모리를 계산하면 됩니다.

2. Application Server 에러 대처 방안(java.lang.OutOfMemoryError: PermGen space 현상)


  • Tomcat의 경우 v6.0.14이상의 안정적 릴리즈 된것을 선택
  • JDK1.4보다는 1.5, 1.6의 사용을 권고함
  • -XXMaxPermSize 설정을 통해 perm 사이즈를 증가시킴
  • JHat으로 메모리릭 원인을 찾고 JConsole, Lambda probe 등을 통해 메모리 모니터링을 함
  • Application Server운영자는 Garbage Collection에 대한 이해가 있어야 함

3. Tomcat에서 설정 예시



  • 힙메모리 정보를 출력 : -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC

위 설정을 통해 출력되는 로그를 보고 New Generation의 eden 영역, Old Generation 영역, Permanent 영역을 확인하여 각 영역이 작으면 아래와 같은 설정으로 적당 사이즈를 확보해 줍니다.



  • 도출된 설정 : -Xms256m -Xmx512m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:MaxPermSize=128m -XX:SurvivorRatio=5
    -Xms : 최소 힙 싸이즈
    -Xmx : 최대 힙 싸이즈
    -XX:NewSize : New Generation의 최소 싸이즈
    -XX:MaxNewSize : New Generation의 최대 싸이즈
    -XX:MaxPermSize : Permanent Generation의 최대 싸이즈 가 되겠다.
    -XX:SurvivorRatio : 영역비율(New Generation)

결론적으로 적용할 설정은 아래와 같습니다.



  • CATALINA_OPTS=”-server -Xss256k -Xms256m -Xmx512m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:MaxPermSize=128m -XX:SurvivorRatio=5 -XX:ReservedCodeCacheSize=128m -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -Djava.net.preferIPv4Stack=true -Djava.awt.headless=true ”

Open Soure는 100% 안정적이지 않기 때문에 가장 최신의 안정적인 버젼이 릴리즈되는지 항상 예의 주시하여 버전업에 게을러서는 안됩니다

위 내용은 http://www.mimul.com/pebble/default/2008/01/26/1201346400000.html 에서 발췌를 하였습니다.

Tomcat 버전별 클래스 로딩 순서

Tomcat5.5 클래스 로딩 순서

Bootstrap classes of your JVM
System class loader classses (described above)
/WEB-INF/classes of your web application
/WEB-INF/lib/*.jar of your web application
$CATALINA_HOME/common/classes
$CATALINA_HOME/common/endorsed/*.jar
$CATALINA_HOME/common/i18n/*.jar
$CATALINA_HOME/common/lib/*.jar
$CATALINA_BASE/shared/classes
$CATALINA_BASE/shared/lib/*.jar

Tomcat5.0 클래스로딩 순서

Bootstrap classes of your JVM
System class loader classses (described above)
/WEB-INF/classes of your web application
/WEB-INF/lib/*.jar of your web application
$CATALINA_HOME/common/classes
$CATALINA_HOME/common/endorsed/*.jar
$CATALINA_HOME/common/lib/*.jar
$CATALINA_BASE/shared/classes
$CATALINA_BASE/shared/lib/*.jar

Tomcat4.1 클래스로딩 순서

/WEB-INF/classes of your web application
/WEB-INF/lib/*.jar of your web application
Bootstrap classes of your JVM
System class loader classses (described above)
$CATALINA_HOME/common/classes
$CATALINA_HOME/common/endorsed/*.jar
$CATALINA_HOME/common/lib/*.jar
$CATALINA_BASE/shared/classes
$CATALINA_BASE/shared/lib/*.jar

* Reference
http://www.jakartaproject.com/article/jsptip/111456818395700