패턴과 아키텍처는 잘 구성되어 있는가?
- 너무 많은 패턴을 사용하지 않았는가?
- 너무 많은 패턴을 적용하면 유지보수성이 떨어지고, 문제가 발생했을 때 추적하기가 어려워진다.
- 좋은 패턴이라고 무작정 적용하기보다는 꼭 필요한 패턴만을 사용해야 한다.
- 데이터를 리턴할 때 TO(혹은 VO) 패턴을 사용하였는가? 아니면 Collection 관련 클래스를 사용하였는가?
- 데이터를 주고 받는 시간을 절약하기 위해서 일반적으로 TO 패턴을 사용한다.
- 그리고 때에 따라서는 Collection 관련 클래스를 사용하기도 한다.
- 이러한 패턴을 적용하지 않았거나 관련 표준을 정하지 않고 개발을 할 경우 시스템의 응답 시간도 영향이 있겠지만, 유지 보수성이 떨어진다.
- 게다가 HashMap으로 데이터를 주고 받으면, 소스를 완전히 뜯어 보지 않는 이상 개발자만 어떤 키과 값이 들어 있는지 알게 된다.
- Service Locator 패턴은 적용이 되어 있는가?
- 이 패턴을 사용하면 애플리케이션에서 필요한 대상을 찾는 룩업 작업을 할 때 소요되는 대기 시간을 줄일 수 있다.
- 만약 서버의 CPU 사용량이 높지 않을 때 응답 속도가 느리다면, 서비스 로케이터를 적용해야 하는 부분이 있지 않은가 한 번쯤 확인을 해 봐야 한다.
기본적인 애플리케이션 코딩은 잘 되어 있는가?
- 명명 규칙은 잘 지켰는가?
- 클래스 이름을 보고 어떤 일을 하는 클래스인지 바로 인식이 가능한지를 확인해야 한다.
- 필요한 부분에 예외 처리는 되어 있는가?
- 예외 처리를 제대로 하지 않으면 사용자는 아무런 응답을 받지 못하고
- 운영하는 시스템을 더 이상 사용하지 않을 수도 있다.
- 문제가 발생했을 때 원인을 밝히기 위해서 예외 처리는 필수다.
- 예외 화면은 지정되어 있는가?
- 예외 화면에 대한 표준이 있는지 확인해 보아야 한다.
- 만약 예외 화면을 구성하지 않고 지정하지도 않는다면, 사용자는 서버의 종류가 어떤 것인지 알게 될 것이다.
- 때에 따라서는 시스템에 어떤 클래스가 있는지도 확인할 수 있을 것이다.
- 예외 정보를 혹시 e.printStackTrace()로만 처리하고 있지 않은가?
- e.printStackTrace() 메서드를 호출하면 서버에서 스택 정보를 취합하여야하기 때문에 서버에 많은 부하가 발생하게 된다.
- System.gc() 메서드가 소스에 포함되어 있지 않은가?
- 우리가 개발할 때는 GC가 '언제 되어야 할지'에 대해서 절대로 신경쓰면 안 된다.
- System.exit() 메서드가 소스에 포함되어 있지 않은가?
- 이 메서드가 수행되면 WAS의 프로세스가 죽는다.
- 스레드가 죽는 것이 아니라 프로세스가 죽는 것이니 이 메서드가 소스에 포함되어 있다면 반드시 제거하자.
- 문자열을 계속 더하도록 코딩하지는 않았는가?
- 몇십 페이지 정도 되는 쿼리를 더하기로 처리할 경우 서버는 GC를 하느라 바빠질 것이다.
- JDK 5.0 이상을 사용하면 자동으로 StringBuilder 클래스로 변환을 해주기는 하지만 루프를 수행하면서 문자열을 더할 경우에는 컴파일러도 어쩔 수가 없다.
- 무한 루프가 작동할 만한 코드는 없는가?
- static을 남발하지 않았는가?
- 메모리를 아낀다고 static을 남발하다가는 시스템이 심각한 오류를 발생시킬 수 있다.
- 필요한 부분에 synchronized 블록을 사용하였는가?
- 그냥 동시에 해당 메서드가 호출될 것 같아서 synchronized 블록을 사용한 것은 아닌지 확인해야 한다.
- 필요 없는 부분에 synchronized 블록을 사용하게 될 경우 성능 저하를 발생시킬 수 있다.
- IO가 계속 발생하도록 개발되어 있지 않은가?
- 가장 많이 실수하는 부분이 설정 파일을 매번 파일에서 읽도록 개발하는 것이다.
- 100명 이상의 사용자가 사용하는 시스템에서 해당 설정 파일을 매번 읽기 위해 IO를 발생시키면서 시스템의 아까운 자원을 낭비하지 말자.
- 필요 없는 로그는 다 제거했는가?
- '로그 레벨이 DEBUG가 아니니 괜찮겠지.'하는 생각은 버려라.
- 우리가 개발하는 시스템은 필요한 데이터만 처리하기 위해서 메모리가 소비된다.
- 프린트하지도 않을 로그 데이터를 문자열로 만들기 위해서 아까운 메모리를 사용하고, 그 메모리를 청소하기 위해서 GC를 해야 하는 불쌍한 JVM을 생각해보라.
- 디버그용 System.out.println은 다 제거했는가?
웹 관련 코딩은 잘 되어 있는가?
- JSP의 include는 동적으로 했는가? 아니면 정적으로 했는가?
- JSP를 동적으로 include하면 서버에도 부하를 줄 뿐만 아니라 응답 시간에도 영향을 준다.
- 그렇다고 무조건 정적으로 include를 하면 변수를 공유하게 되어 예기치 못한 문제가 발생할 수 있으므로 유의해서 사용하자.
- 자바 빈즈는 너무 많이 사용하지 않았나?
- 하나의 화면에서 자바 빈즈를 수십 개씩 사용하지 않는가?
- 하나의 TO를 사용해서 처리할 수도 있는 데이터라면,
- 여러 개의 자바 빈즈를 사용해서 응답 시간에 영향을 주는 일이 없도록 하자.
- 태그 라이브러리는 적절하게 사용했나?
- 많은 양의 데이터를 태그 라이브러리로 처리할 경우에는 성능에 많은 영향을 끼친다.
- EJB는 적절하게 사용하였나?
- EJB를 많이 사용한다고 해서 시스템이 안정화되는 것은 아니다.
- 서버를 기동하는데 시간의 여유가 있다면, 서버의 메모리가 충분히 여유가 있다면 상관없다.
- 하지만 EJB 하나하나는 일반 클래스보다 많은 메모리를 점유해야 하며,
- 서버를 기동할 때에도 많은 시간이 소요된다.
- 따라서 반드시 필요한 경우에만 EJB를 사용하자.
- 이미지 서버를 사용할 수 있는 환경인가?
- 웹 서버 이외에 정적인 컨텐츠만을 제공하는 서버를 사용하자.
- 사용 중인 프레임워크는 검증되었는가?
DB 관련 코딩은 잘 되어 있는가?
- 적절한 JDBC 드라이버를 사용하는가?
- DB Connection, Statement, ResultSet은 잘 닫았는가?
- 반드시 finally 구문을 사용해서 Connection, Statement, ResultSet을 명시적으로 닫자.
- DB Connection Pool은 잘 사용하고 있는가?
- 프로젝트 규모가 크면 클수록 표준을 따르지 않을 확률도 커진다.
- 관련되는 표준을 반드시 정하고, DB Connection Pool은 반드시 사용해야 DB의 리소스를 보다 효율적으로 사용할 수 있다.
- 자동 커밋 모드에 대한 고려는 하였는가?
- 기본 커밋 모드는 자동 커밋으로 되어 있다.
- 하지만 조회성 프로그램도 자동 커밋 여부를 지정하게 되면, 약간의 응답시간 저하가 발생하게 된다.
- 반드시 필요하지 않은 경우에는 자동 커밋을 하도록 하자.
- ResultSet.last() 메서드를 사용하였는가?
- 데이터의 건수가 많을수록 응답 시간이 느려진다.
- 쿼리를 두 번 수행하더라도 전체 건수를 가져오기 위한 last() 메서드의 사용은 자제하자.
- PreparedStatements를 사용하였는가?
- Statement를 사용하면 매번 쿼리를 수행할 때마다 SQL 쿼리를 컴파일하게 된다. 이 작업은 DB에 많은 부하를 준다.
- 그러므로 쿼리 문장이 계속 동적으로 변경되어야 하는 경우를 제외한 대부분의 경우에는 PreparedStatements를 사용하자.
서버의 설정은 잘 되어 있는가?
- 자바 VM 관련 옵션들은 제대로 설정되어 있는가?
- 클래스 패스는 순차적으로 인식된다. 여러 JAR 파일 중 만약 같은 패키지명에 같은 클래스가 존재할 경우에는 앞에 명시한 클래스 패스에 우선권이 있다.
- 메모리는 몇 MB로 설정해 놓았는가?
- 설정하지 않으면 서버는 기본 64MB로 시작한다.
- GC 설정은 어떻게 되어 있는가?
- 혹시 -client로 설정되어 있는지 확인해 보자.
- GC의 방식에 따라서 서버의 성능이 엄청난 차이가 발생할 수 있다.
- 가능하면 성능 테스트를 통해서 시스템과 서버에 맞는 GC 옵션을 설정하자.
- 서버가 운영 모드인지 개발 모드인지 확인하였는가?
- 서버가 개발 모드라면, WAS는 주기적으로 변경된 클래스가 있는지 확인할 것이다. 이 작업은 서버에 많은 부하를 주게 된다.
- 서버가 주기적으로 느려진다면 이 부분을 확인해보자.
- WAS의 인스턴스가 몇 개 기동되고 있는가?
- WAS에서 하나의 인스턴스당 적어도 한 개는 있어야 제대로 된 운영이 가능하다.
- CPU는 4개인데, 인스턴스가 30개 정도 있는 것은 아닌지 확인하자.
- WAS의 CPU 개수가 적을 겨우, 때에 따라서 인스턴스 개수를 증가시키면 서버의 처리량이 증가될 수 있다. 이 인스턴스의 개수에 대해서는 정답이 없다.
- 그러므로, 서버 및 애플리케이션의 상황에 맞게 성능 테스트를 통해서 시스템의 적절한 인스턴스 개수를 도출해야 한다.
- JSP Precompile 옵션은 지정해 놓았는가?
- 서버를 기동할 때 JSP를 미리 컴파일하도록 해 놓으면 사용자는 JSP가 수정이 되었는지 여부와 상관없이 일정한 응답 속도를 느낄 것이다.
- 하지만 서버가 기동될 때 JSP를 컴파일하기 위한 시간도 많이 소요된다.
- DB Connection Pool 개수와 스레드 개수는 적절한가?
- 스레드 개수가 DB Connection Pool의 수보다 절대로 적어서는 안 된다.
- 스레드의 개수는 DB Connection Pool의 개수보다 보통 10개 정도 더 많이 설정한다.
- 만약 DB Connection Pool의 설정을 서버 기본 설정으로 해 놓고 운영을 한다면, 서버의 리소스도 별로 사용하지 않고 10명 이상의 동시 사용자를 처리하지 못할 것이다.
- 대부분 WAS의 DB Connection Pool의 초기 값은 10~20개이다.
- 세션 타임아웃 시간은 적절한가?
- 세션을 더 이상 사용하지 않을 때 세션 정보는 삭제되어야 한다.
- 만약 세션 타임아웃 시간을 하루 이상의 큰 값으로 지정하고, 해당 서버를 재시작하지 않으면 해당 서버는 메모리 릭이 발생하여 더 이상 사용할 수 없는 상황이 될 것이다.
- 검색 서버가 있다면, 검색 서버에 대한 설정 및 성능 테스트를 하였는가?
- 일반적으로 검색 서버에서 주기적으로 데이터를 모으기 위해서 서버의 리소스를 많이 사용하게 된다.
- 만약 검색 서버의 세팅을 점검하지 않고, 선능 테스트를 하지 않는다면, 예기치 못한 부분에서 시스템의 리소스를 점유하고 있을지도 모른다.
모니터링은 어떻게 하고 있는가?
- 웹 로그를 남기고 있는가?
- 애플리케이션의 사용량과 자주 사용하는 애플리케이션을 분석하기 위해서, 추후 용량 산정의 기초 자료가 되는 웹 로그는 반드시 남겨서 관리하자.
- verbosegc 옵션은 남기고 있는가?
- GC가 어떤 형태로 발생하는지를 확인하고자 한다면, 반드시 verbosegc 옵션을 사용하여 로그를 남기자.
- 메모리의 크기를 지정하기 위해서나, GC 옵션을 변경하기 위해서라도 verbosegc 옵션은 매우 유용하게 활용될 것이다.
- 하지만, GC 튜닝을 하지 않을 시스템에 verbosegc 옵션을 남기는 것은 리소스 낭비다.
- 각종 로그 파일에 대한 규칙은 있는가?
- 일별로 로그를 쌓도록 옵션을 지정하면, 특정 이슈가 발생한 날짜의 데이터를 분석하기에도 좋고 백업을 하기에도 편리하다.
- 서버의 시스템 사용률은 로그로 남기고 있는가?
- WAS나 DB가 얼마나 사용을 하고 있는지 로그를 남겨야 한다.
- 대부분의 사이트에는 SMS나 APM을 설치하여 서버를 모니터링하고 있겠지만,
- 그렇지 않은 사이트에서는 서버의 사용량을 유닉스의 vmstat나 sar 명령어를 사용해서 남겨야
- 시간대별 서버 사용량을 구할 수 있다.
- 그리고 나중에 서버를 증설할 때에도 이 데이터는 매우 유용하게 사용된다.
- 모니터링 툴은 사용 중인가?
- WAS를 모니터링하기 위한 툴은 설치되었는가? 모니터링 툴이 없다면, 장님이 코끼리를 만지는 것과 비슷하다.
- 툴을 구매할 여력이 안되고 서버가 많은 부하를 받고 있지 않는다면,
- JMX 기술을 사용하여 서버를 모니터링하는 것도 좋은 방법이다. (JConsole도 있음)
- 모니터링 툴에 대한 설정은 적절하게 되어 있는가?
- 모든 메서드에 대해서 프로파일링을 하도록 지정을 사면 대부분의 툴이 성능에 많은 영향을 주게 된다.
- 그러므로 꼭 필요한 내용만 모니터링이 되도록 설정을 잘 맞추어야 제대로 사용할 수 있다.
- 서버가 갑자기 코어 덤프를 발생시키지 않는가?
- 서버에서 코어 덤프를 발생시키는 경우의 수는 굉장히 많다. 만약 서버가 지속적으로 코어 덤프를 발생시킨다면 적어도 다음의 내용을 점검해 보기 바란다.
- 10,000건 이상 조회하는 것이 있나 확인해야 한다. 한꺼번에 많은 양의 데이터를 처리하려면 많은 메모리가 필요한데, 이 때 코어덤프가 발생할 수 있다.
- 메모리 릭이 있는지 확인해야 한다. 메모리를 점유하고 해제하지 않는 로직이 있으면 서버를 매일 재기동해도 메모리는 점차적으로 부족해진다. 서버가 기동된 후 힙 덤프를 받아 놓은 뒤, 운영 중과 운영 후에 각각 덤프를 받아서 메모리 사용량의 추이를 확인해야 한다.
- 서버에서 코어 덤프를 발생시키는 경우의 수는 굉장히 많다. 만약 서버가 지속적으로 코어 덤프를 발생시킨다면 적어도 다음의 내용을 점검해 보기 바란다.
- 응답 시간이 너무 느리지 않은가?
- 응답 시간이 느려지는 이유는 상상을 초월할 정도로 많다. 그러므로 이 문제를 해결하기 위해서는 상황을 정확히 판단해야 한다.
- WAS단 이후에서 느린것인지, 그 이전 단계인 네트워크나 웹 서버에서 느린지 확인해야 한다.
- 만약 WAS에서 느리다면, 정확히 어느 부분에서 느린지 프로파일링을 해서 확인해 봐야 한다.
'개발서적 > 자바 성능 튜닝 이야기' 카테고리의 다른 글
[자성튜이] 성능 튜닝을 위한 기초 법칙 (0) | 2024.09.16 |
---|---|
[자성튜이] 반드시 튜닝해야 하는 대상 (0) | 2024.09.16 |
[자성튜이] GC 발생 시점 (0) | 2024.09.16 |
[자성튜이] JVM은 도대체 어떻게 구동될까 (0) | 2024.09.16 |
[자성튜이] 서버를 어떻게 세팅해야 할까? (1) | 2024.09.16 |