2014년 4월 30일 수요일

common DBCP 사용시 Thread lock 문제

WAS에서 제공하는 DB Pool을 사용하지 않고
Apache Common DBCP를 사용하는 곳에서 가끔 DB Connection이 밀리는 현상으로 고생하는곳이 있다.

Common DBCP는 Thread Safe하기 위해서 Connection Pool을 Lock 하고 처리를 진행한다.

이건 해당 Thread의 처리 시간이 오래 걸리면 결국 다른 Thread들은 Connection Pool에 접근할 수 없다는 의미이다.

이 문제를 해결하는 가장 간편한 방법은 tomcat DBCP jar파일을 찾아서 바꿔버리면 해결된다.

tomcat다운로드 받아서 lib 폴더에 tomcat-dbcp.jar 를 찾아서 자신의 WAR에 추가하고

기존의 commons-dbcp-1.4jar, commons-pool-1.6.jar, commons-collections-3.2.1-bin.zip  등은 뻬버리자  (tomcat jar 안에 다 들어있다.)

org.apache.commons.dbcp.BasicDataSource  같이 commons로 된 놈이 있으면 아래같이 바꾸자
org.apache.tomcat.dbcp.dbcp.BasicDataSource

(버젼 문제도 안될 수 도 있다. 나에게 따지지 마라 ㅋㅋㅋ)

아니면 Frame work 나 자신의 DB Connection Manager 에서 JNDI Lookup 부분을 찾아서 WAS가 제공하는 DBPool로 바꾸어 주어도 된다.

설마 아직도 bean 이나 servlet에서 Connection 하는 사람은 없겠지....
Framework나 잘 구성된 Manager class를 사용하고 있다면
WAS Pool로 소스를 변경하는 일이 기능적으로는 큰 일이 아니다.

두려움....

혹시나....

어쩌겠는가...내가 할 수 있는일은 솔루션을 제공할 뿐 바꿔드릴 수 는 없음임  (하기 싫음 -.-)

여하간 삽질 하는 누군가에게는 도움이 되길 기원하며...



  1. 이슈
    1. DB Connection을 늘렸음에도 APP들이 getConnection에서 대기하고 있음
      1. DB Connection을 90개로 늘렸음
      2. Application getConnection에서 대기하기는 하지만 제니퍼에서 보면 DB Connection이 모두 사용되고 있는것은 아님
  2. 분석내용
    1. Thread Dump
      1. 특정 Thread가 DataSource를 Lock 하고 풀리지 않아서 다른 모든 APP들이 getConnection에서 대기하고 있음
      1. 해당 문제상태에서 Thread lock 상태 설명

        Icon
        <0x00000007957d27d8> (a org.apache.commons.dbcp.BasicDataSource): 0 Thread(s) sleeping, 803 Thread(s) waiting, 1 Thread(s) locking
        803개의 Thread를 locking 하고 있는 DBCP의 MultiConnectionManager Class
        at coperframe.common.data.impl.MutiConnectionManager.getConnection(MutiConnectionManager.java:74)
        그렇다면
        동일한 Thread가 Lock을 잡고 있어서 일까?
        아래를 보면 10초 사이에 5회에 kill 3으로 생성한 Thread dump 마다 lock을 잡고 있는 Thrad를 추려보았다.
        각각 다른 Thread 이다.
        결국은 하나의 처리가 오래 걸리면서 DBPool을 Lock 하고 이로 인하여 다른 Thread들이 대기 하는 상태로 Dead Lock은 아니고 느리게 처리되고 있는 상황으로 확인 할 수 있다.
        "ajp-0.0.0.0-12501-379" daemon prio=10 tid=0x00007fee78239800 nid=0x70d runnable [0x00007fee5203f000]
        java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.read(SocketInputStream.java:129)
        at com.javaservice.lwst.SocketWrapper$InputStreamWrap.read(Unknown Source)
        at oracle.net.ns.Packet.receive(Unknown Source)
        at oracle.net.ns.NSProtocol.connect(Unknown Source)
        "ajp-0.0.0.0-12501-33" daemon prio=10 tid=0x00007fee78048000 nid=0x7b14 runnable [0x00007fee87921000]
        java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.read(SocketInputStream.java:129)
        at com.javaservice.lwst.SocketWrapper$InputStreamWrap.read(Unknown Source)
        at oracle.net.ns.Packet.receive(Unknown Source)
        at oracle.net.ns.NSProtocol.connect(Unknown Source)
        at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:844)
        at oracle.jdbc.driver.T4CConnection.logon(T4CConnecti"ajp-0.0.0.0-12501-818" daemon prio=10
        "ajp-0.0.0.0-12501-348" daemon prio=10 tid=0x00007fee7820e800 nid=0x55d runnable [0x00007fee528a0000]
        java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.read(SocketInputStream.java:129)
        at com.javaservice.lwst.SocketWrapper$InputStreamWrap.read(Unknown Source)
        at oracle.net.ns.Packet.receive(Unknown Source)
        at oracle.net.ns.DataPacket.receive(Unknown Source)
        "ajp-0.0.0.0-12501-793" daemon prio=10 tid=0x00007fee78516800 nid=0x1086 runnable [0x00007fee4b20d000]
        java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.read(SocketInputStream.java:129)
        at com.javaservice.lwst.SocketWrapper$InputStreamWrap.read(Unknown Source)
        at oracle.net.ns.Packet.receive(Unknown Source)
        at oracle.net.ns.NSProtocol.connect(Unknown Source)
        at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:844)
        at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:268)
        at oracle.jdbc.driver.PhysicalConnection. (PhysicalConnection.java:420)
        "ajp-0.0.0.0-12501-818" daemon prio=10 tid=0x00007fee78532800 nid=0x11de runnable [0x00007fee4b087000]
        java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.read(SocketInputStream.java:129)
        at com.javaservice.lwst.SocketWrapper$InputStreamWrap.read(Unknown Sourc
        coperframe은 개발사 Framework로써 JBoss DB Pool을 사용하지 않고 있음
        사실 framework의 문제라기 보다는 해당 Common DBCP의 고전적인 Thread safety 문제일 것으로 판단되나
        DBCP를 분석하고 싶지 않아서 PASS함.
        이때 문제점은 두 가지 이다.
        1. Thread 처리가 느리다 = SQL이 느린것일 것이다. 쿼리 처리가 빨랐다면 좀 밀려도 대충대충 운영되고 있었겠지만 처리시간이 요청되는 속도 보다 느리기 때문에 결국 전체적으로 처리가 밀린것으로 보면 되겠다. 
          1. 현 시스템으로 마이그레이션 하기전 기존 사이트에서는 이상 없었다는 말이 여기서 나온다. 기존 시스템에서도 Jennifer로 보면 Active Thread가 30~50개 까지 쌓여 있는것을 볼 수 있었다. (정상적이라면 Active Thread는 10개 이상 올라갈 일이 없다.)
          2. 이것은 
            1. 기존 DB가 이전한 DB보다 빠르게 응답을 했다는 의미일 수 있고
            2. 이번에 튜닝을 가이드하면서 WEB/WAS 구간에서의 병목을 해결해 버림으로써 DB로 전보다 높은 부하가 들어가서 DB응답성능이 떨어진것으로 도 생각할 수 있다.
        2. DB Pool이 Thread safe 하다는 것은 병목이다.
          1. DB Pool에 getConnection을 하고 Connection을 받으면 해당 객체를 release 해야 한다. 자기가 처리가 끝날때 까지 Pool을 lock 하는 것이 문제다.
          2. 각각의 Thread가 getConnection을 하고 받은 connection으로 처리를 했다면 SQL처리가 느려서 밀리거나 Connection이 모두 소진되는 문제가 발생 할 수 있으나 이번에서는  Lock 문제로 발견되게 된 것이다. (http://stackoverflow.com/questions/12339726/multithreading-with-apache-dbcp)
          3. 짐작하기에 commonDBCP를 사용하면서 발생하지 않았을까 판단한다. 설명은 링크를 참고한다.(http://blog.naver.com/PostView.nhn?blogId=myca11&logNo=80127605636&beginTime=0&jumpingVid=&from=search&redirect=Log&widgetTypeCall=true)
        == 가해자 Thread
        "ajp-0.0.0.0-12501-379" daemon prio=10 tid=0x00007fee78239800 nid=0x70d runnable [0x00007fee5203f000]
        java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method) <== Read0 는 대부분 DB에 query를 보내고 대기하고 있는 상황을 의미함
        at java.net.SocketInputStream.read(SocketInputStream.java:129)
        at com.javaservice.lwst.SocketWrapper$InputStreamWrap.read(Unknown Source)
        at oracle.net.ns.Packet.receive(Unknown Source)
        at oracle.net.ns.NSProtocol.connect(Unknown Source)
        at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:844)
        at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:268)
        at oracle.jdbc.driver.PhysicalConnection. (PhysicalConnection.java:420)
        at oracle.jdbc.driver.T4CConnection. (T4CConnection.java:165)
        at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:35)
        at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:801)
        at org.apache.commons.dbcp.DriverConnectionFactory.createConnection(DriverConnectionFactory.java:38)
        at org.apache.commons.dbcp.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:582)
        at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:840)
        - locked <0x0000000798a1b9e8> (a org.apache.commons.pool.impl.GenericObjectPool)
        at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:106)
        at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
        at coperframe.common.data.impl.MutiConnectionManager.getConnection(MutiConnectionManager.java:74)
        - locked <0x00000007957d27d8> (a org.apache.commons.dbcp.BasicDataSource)
        at coperframe.common.work.impl.DefaultWorkerManager.executeWorker(DefaultWorkerManager.java:61)
        at coperframe.common.struts.ActionHandler.callService(ActionHandler.java:42)
        at coperframe.common.struts.ActionHandler.callStaticService(ActionHandler.java:29)
        at coperframe.common.struts.WorkerAction.callService(WorkerAction.java:161)
        at coperframe.common.struts.WorkerAction.execute(WorkerAction.java:114)
        at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:413)
        at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:225)
        at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1858)
        at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:446)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at com.tomato.com.http.HttpResponseHeaderFilter.doFilter(HttpResponseHeaderFilter.java:95)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at com.tomato.sso.sp.AuthFilter.doFilter(AuthFilter.java:47)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:183)
        at org.jboss.web.tomcat.service.session.ClusteredSessionValve.handleRequest(ClusteredSessionValve.java:135)
        at org.jboss.web.tomcat.service.session.ClusteredSessionValve.invoke(ClusteredSessionValve.java:94)
        at org.jboss.web.tomcat.service.session.JvmRouteValve.invoke(JvmRouteValve.java:88)
        at org.jboss.web.tomcat.service.session.LockingValve.invoke(LockingValve.java:62)
        at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:95)
        at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
        at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.internalProcess(ActiveRequestResponseCacheValve.java:74)
        at org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:47)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
        at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:437)
        at org.apache.coyote.ajp.AjpProtocol$AjpConnectionHandler.process(AjpProtocol.java:385)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:451)
        at java.lang.Thread.run(Thread.java:662)
        =피해자 Thread
        ajp-0.0.0.0-12501-33" daemon prio=10 tid=0x00007fee78048000 nid=0x7b14 waiting for monitor entry [0x00007fee87922000]
        java.lang.Thread.State: BLOCKED (on object monitor)
        at coperframe.common.data.impl.MutiConnectionManager.getConnection(MutiConnectionManager.java:74)
        - waiting to lock <0x00000007957d27d8> (a org.apache.commons.dbcp.BasicDataSource)
        at coperframe.common.work.impl.DefaultWorkerManager.executeWorker(DefaultWorkerManager.java:61)
        at coperframe.common.struts.ActionHandler.callService(ActionHandler.java:42)
        at coperframe.common.struts.ActionHandler.callStaticService(ActionHandler.java:29)
        at coperframe.common.struts.WorkerAction.callService(WorkerAction.java:161)
        at coperframe.common.struts.WorkerAction.execute(WorkerAction.java:114)
        at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:413)
        at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:225)
        at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1858)
        at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:446)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at com.tomato.com.http.HttpResponseHeaderFilter.doFilter(HttpResponseHeaderFilter.java:95)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at com.tomato.sso.sp.AuthFilter.doFilter(AuthFilter.java:47)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:183)
        at org.jboss.web.tomcat.service.session.ClusteredSessionValve.handleRequest(ClusteredSessionValve.java:135)
        at org.jboss.web.tomcat.service.session.ClusteredSessionValve.invoke(ClusteredSessionValve.java:94)
        at org.jboss.web.tomcat.service.session.JvmRouteValve.invoke(JvmRouteValve.java:88)
        at org.jboss.web.tomcat.service.session.LockingValve.invoke(LockingValve.java:62)
        at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:95)
        at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
        at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.internalProcess(ActiveRequestResponseCacheValve.java:74)
        at org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:47)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
        at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:437)
        at org.apache.coyote.ajp.AjpProtocol$AjpConnectionHandler.process(AjpProtocol.java:385)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:451)
        at java.lang.Thread.run(Thread.java:662)

    2. 조치사항
      1. DB Lock 상태로 인하여 DB Connection을 다 쓰지도 못하고 App들이 정지상태로 대기하는 형태임을 설명해줌
      2. 개발팀에서 framework에서 DBCP를 빼고 JBoss DB Pool로 변경함
      3. JBoss DB Pool 설정 지원

2014년 4월 28일 월요일

청와대 홈피 인기폭발~!!! 당신이 대통령이어선 안 되는 이유....오전 사이트 장애....글 삭제 안내

소셜을보다가 "오늘 오전 청와대 홈피 접속 오류 날때 html 소스" 라는 글을 보고

옹? 이건 뭐지??? 했다가 잠시보고 ㅋㅋㅋㅋㅋㅋㅋ

청와대 홈피가 PHP로 개발되어 있으니 Apache나 nginX에 PHP 실어서 운영하겠지?

Connection Error 라고 하면 .... Server busy 라는 뜻일까?

일반적으로 이런 유명한 사이트는 HTTP 오류발생시 보여줄 페이지를 따로 구성하지

그래서 예쁜 그림에 한글로 된 설명이 나오는게 맞아

"서버 바빠 바쁘니까 나중에 들어와!!"  이렇게

근데 영문으로 저리  나오면 Web Server 자체 오류 페이지라는 말인데

자체페이지에 style 넣는 웹서버가 어디 있나... 지랄.... 폰트는 뭐람...

차라리 "뭔가 하니라 바뻐요..." 라고 하지


어쩌면 CDN 서비스를 쓰는지도 몰라  대충 까보니 IP가 많이 나오는게 CDN서비스 같기도 해

그럼 CDN 이 맛이 가서 그런걸까?  CDN 이라고 메시지를 저따위로 날리지 않을 것 같아....

CDN은 안되면 그냥 먹통이거나 url rerwiting 으로 돌려주고 말지 이런 묘한 메시지를 출력하나?

만약 CDN 서비스라면 서비스 업체 이름 까발려서 절대 저 회사 서비스는 쓰면 안되겠어....



주말 내내 이  글 오픈된거 모르거나 알아도 공무원이라 어쩔 수 없이(?) 쉬다가

보고 하면서 욕먹을까봐 막아 놓았던게 아닐까?  하는 음모론을 펼쳐본다 ^^

불쌍하다 불쌍해...

참고로 이 글은 지워졌고 하도 말이 많으니 같으니 아래 같이 답변이 올라와 있습니다.





이창- 님의 글 복사내용

  오늘 오전 청와대 홈피 접속 오류 날때, html 소스

<!DOCTYPE html>
<html>
<head>
<title>Error</title>
<style>
    body {
        width: 50em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body><center>
<h1>Connection Error</h1>
<h3>Please try connecting again<h3>
</body>
</html>





아래는 청와대 기사 전문입니다.

원래글을 작성하신분의 페북 링크는 아래와 같습니다.
https://www.facebook.com/sungmi.park.338/posts/10152322548266132

경향신문기사 발췌

이하 “당신이 대통령이어선 안 되는 이유” 전문

숱한 사회 운동을 지지했으나 솔직히, 대통령을 비판해본적은 거의 없다 

그러나 처음으로 이번만큼은 분명히 그 잘못을 요목 조목 따져 묻겠다. 
지금 대통령이 더 이상 대통령이어서는 안 되는 분명한 이유를. 


대통령이란 직책, 어려운 거 안다. 아무나 대통령 하라 그러면 쉽게 못 한다. 그래서 대통령을 쉬이 비판할 수 없는 이유도 있었다. 그리고 대통령 물러나라 라는 구호는 너무 쉽고, 공허하기도 했기 때문이다. 
그리고 정부가 아무리 무능해도 시민들이 정신만 차리면 그 사회를 바꿔 나갈 수 있다고 믿었기 때문이다. 

하지만 이번에 대통령은 대통령으로 임무를 수행 해야할 아주 중요한 몇 가지를 놓쳤다. 

첫째, 대통령은 자기가 해야 할 일이 뭔지도 몰랐다. 

대통령이 구조방법 고민 할 필요 없다. 
리더의 역할은 적절한 곳에 책임을 분배하고, 밑의 사람들이 그 안에서 최대한의 역량을 발휘할 수 있게 해주고, 밑에서 문제가 생기면 그 책임을 지는 것이 기본이다. 특히 아래 사람들끼리 서로 조율이 안 되고 우왕좌왕한다면 무엇보다 무슨 수를 쓰든 이에 질서를 부여하는 역할을 해야 한다. 
안행부 책임 하에서 잘못을 했다면 안행부가 책임지면 된다. 해수부가 잘못했으면 해수부가 책임지면 된다. 그런데 각 행정부처, 군, 경이 모여있는 상황에서 가 책임소관을 따지지 못하고 우왕좌왕했다면, 그건 리더가 제 소임을 다하지 못한 거다. 나는 군 최고 통수권자이자 모든 행정부를 통솔할 권한이 있는 사람은 우리나라에서 딱 한 명 밖에 모른다. 대통령이다.

대통령이 했어야 할 일은 현장에 달려가 상처 받은 생존자를 위로한답시고 만나고 그런 일이 아니다. 그런 건 일반인도 할 수 있는 일이다. 
‘구조 왜 못하냐, 최선을 다해 구조해라’ 그런 말은 누구라도 할 수 있다. ‘잘 못하면 책임자 엄벌에 처한다’ 그런 호통은 누구나 칠 수 있다. 대통령이 할 일은 그게 아니다. 
‘중국인들이 우리나라에서 왜 쇼핑을 못 한답니까?’ 그런 말 하라고 있는 자리 아니다. 
공인인증서 폐기하라고, 현장에 씨씨티비 설치하라고, 그러라고 있는 자리 아니다. 
일반인들이 하지 못하는 막대한 권한을, 행사할 수 있었다. 그랬기 때문에 대통령에 책임이 있는 거다. 대통령? 세세한 거 할 필요 없다. 대통령은 대통령만이 할 수 있는 일을 하라.

일이 안 되는 핵심 문제를 파악하고 해결점을 찾는 일, 뭐가 필요하냐 묻는 일. 그냥 해도 될 일과 최선을 다할 일을 구분하고 최선을 다해도 안 되면 포기할 일과 안 돼도 되게 해야 할 일을 구분해주고, 최우선 의제를 설정하고 밑의 사람들이 다른 데 에너지를 쏟지 않을 수 있도록 자유롭게 해주는 일, 비용 걱정 하지 않도록 제반 책임을 맡아 주는 일
영화 현장의 스탭들은 감독이나 피디의 분명한 요청만 있다면 아무리 어려운 일도, 안 돼는 일도 되게 한다.. 단, 조건이 있다. 어려운 일을 되게 하려면 당연히 비용이 오버 된다. 이 오버된 제반 비용에 대한 책임. 그것만 누군가 책임을 져 주면, 스탭들은, 한다. 

리더라면 어떤 어려운 일이
‘안 돼도 되게 하려면’
밑의 사람들이 비용 때문에 망설일 수 있다는 것쯤은 안다. 
그것이 구조 작업이던 뭐던 수단과 방법을 가리지 말아야 한다면 무조건 돈이 든다. 엄청난 돈이.
만약 사람들이 비용 때문에 망설일 수 있다는 사실조차 ‘몰랐다면’
그건 대통령이 정말로 누군가의 말단 직원인 적도 없었고 비용 때문에 고민해 본 적도 없다는 얘기다. 웬만한 중소기업 사장도 다 아는 사실이다. 
만약 리더가 너 이거 죽을 각오로 해라. 해내지 못하면 엄벌에 처하겠다 라고 협박만 하고 비용도 책임져주지도 않고, 안 될 경우 자신은 책임을 피한다면, 그 누가 할 수 있겠는가? 
사람을 구하는데 돈이 문제냐 하지만, 실제 그 행동자가 되면 달라진다. 유속의 흐름을 늦추게 유조선을 데려온다? 하고 싶어도 일개 관리자가 그 비용을 책임질 수 있을까? 그러나 누군가 그런 문제들을 책임져주면 달라진다 
“비용 문제는 추후에 생각한다. 만약 정 비용이 많이 발생하면 내가 책임진다.”
그건 어떤 민간인도 관리자도 국무총리도 쉬이 할 수 없는 일이다. 

힘 없는 시민들조차 죄책감을 느꼈다. 할 수 있었으나 하지 못한 일, 그리고 전혀 남 일인 것 같은 사람들조차 작게나마 뭘 할 수 있었을지를 고민했다. 

그러나 그 많은 사람들을 지휘하고 이끌 수 있었던, 문제점을 파악하고 직접 시정할 수 있었던, 해외 원조 요청을 하건 인력을 모으건 해양관련 재벌 회장들에게 뭐든 요청하건, 일반인들은 할 수 없는, 그 많은 걸 할 수 있었던 대통령은 구조를 위해 무슨 일을 고민했는가? 

둘째, 사람을 살리는 데 아무짝에 쓸모 없는 정부는 필요 없다

대통령은 분명 ‘구조에 최선을 다하라’ 라고 지시했다.
그러나 왜 지휘자들은 ‘구조에 최선을 다하지’ 안았을까? 
그것이 한 두 번의 명령으로 될까? 

날씨 좋던 첫째날 가이드라인 세 개밖에 설치를 못했다면, 이러면 애들 다 죽는다. 절대 못 구한다 판단하고 밤새 과감히 방법을 바꾸는 걸 고민하는 사람이 이 리더 밑에는 왜 한 사람도 없었는가? 목숨걸고 물 속에서 작업했던 잠수사들, 직접 뛰어든 말단 해경들 외에, 이 지휘부에는 왜 구조에 그토록 적극적인 사람이 없었는가?

밑의 사람들은 평소에 리더가 가진 가치관에 영향을 받는다. 급한 상황에서는 평소에 리더가 원하던 성향에 따라 행동하게 되어 있다. 그것은 평소 리더가 어떨 때 칭찬했고 어떨 때 호통쳤으며, 어떨 때 심기가 불편했는지에 따라 달라진다. 

만약 리더가 평소에 사람과 생명을 최우선 가치로 두었던 사람이라면
밑의 사람들은 어떤 상황에서던 말 하지 않아도 그것을 최우선으로 두고 행동한다. 

쌍용차 사태의 희생자들이 분향소를 차렸을 때
박근혜에게 충성하겠다 한 중구청장은 그들을 싹 쫓아냈고
대학생들이 등록금 때문에 죽어가도 아무도 그걸, 긴급하게 여긴 적이 없고
모두 살기보다 일부만 사는 게 효율에서 좋고. 
자살자가 늘어나도 복지는 포퓰리즘일 뿐이고. 
세 모녀의 죽음을 부른 제도를 폐지하는 데에 아직도 대통령이 이끄는 당은 그토록 망설인다. 
죽음을 겪은 사람들을 ‘징징대는’ 정도로 취급하고
죽겠다 함께 살자는 사람들에게 물대포를 뿌렸다. 
이곳에선 한번도 사람이, 사람의 생명이 우선이었던 적은 없었다. 
아직도 이들에겐 사람이 죽는 것보다 중요한 게 많고, 대의가 더 많다. 
‘사람은 함부로 해도 된다’ 는 이 시스템의 암묵적 의제였다. 

평소의 시스템의 방향이 이렇게 움직이고 있던 상황에서
이럴 때 대통령이 ‘구조에 최선을 다하라’ 라고 지시를 하면, 
밑의 사람들은 대통령이
진심으로 아이들의 생명이 걱정되어서 그런 지시를 내린 건지
‘구조에 최선을 다하라’라고 지시했다는 사실을 국민들에게 보여줘라 라는 뜻인지, 
정부의 성과를 보여주기 위해 구조를 하라는 건지, 
여론이 나빠지지 않게 잘 구조를 하라는 얘긴지, 
헷갈리게 된다. 
대책본부실에서 누가 장관에게 전했다. 
“대통령께서 심히 염려하고 계십니다’ 
그러면 이 말이 ‘아이들의 안위와 유가족들의 아픔을 염려하고 있다는’ 건지
‘민심이 많이 나빠지고 있어 자리가 위태로워질 걸 염려한다는’ 건지
밑의 사람들은 헷갈린다. 

대신 지시가 없어도 척척 움직인 건 
구조 활동을 멈추고 의전에 최선을 다한 사람들
재빨리 대통령이 아이를 위로하는 장면을 세팅한 사람들
대통령은 잘했다 다른 사람들이 문제다 라고 사설을 쓸 줄 알았던 사람들.
재빨리 불리한 소식들을 유언비어라 통제할 줄 알았던 사람들. 
구조에 최선을 다하는 것으로 보여지는데 애를 쓴 사람들. 
선장과 기업에게 모든 책임을 돌리는 방향으로 여론몰이를 한 사람들과
순식간에 부르자마자 행진을 가로막고 쫙 깔린 진압 경찰들이다. 

이것은 이들의 평소 매뉴얼이었기 때문이다. 그들은 평소 리더가 중요하게 생각하는 게 뭔지 알고 있었고 그것을 위해 움직였을 뿐이다. 그리고, 거기에 에너지를 쏟느라 정작 중요한 것을 놓쳤다. 

내가 선거 때 박근혜를 뽑지 않았던 이유는 분명히 있다. 
그가 친일파라서도 보수당이어서도 독재자의 딸이어서도 아니었다. 
그녀가 남일당 사태 때 보여준 반응, 자신의 부친 때문에 8명의 사람들이 억울하게 죽었는데, 거기에 대해 일말의 죄책감도 안타까움도 갖지 않는 모습을 보았기 때문이다.
사람의 생명에 대해 그토록 가벼이 생각하는 사람이라면 
대통령으로 뽑아선 안 된다는 그 이유 하나 때문이었다. 

리더의 잘못을 여기에 있다. 
밑의 사람들에게 
평소 사람의 생명이 최우선이 아니라는 
잘못된 의제를 설정한 책임. 

셋째, 책임을 지지 않는 대통령은 필요 없다. 
대통령이란 자리가 그토록 어려운 이유는 책임이 무겁기 때문이다. 막대한 권한과 비싼 월급, 고급 식사와 자가 비행기와 경호원과 그 모든 대우는 그것이 [책임에 대한 대가] 이기 때문이다.
누구도 책임지지 않는 조직에선 어떤 일도 제대로 굴러가지 않는다. 
리더가 책임지지 않는 곳에서 누가 어떻게 책임지는 법을 알겠는가?

자신이 해야할 일을 
일일이 알려줘야 하는 대통령은 필요 없다. 
사람을 살리는 데 아무짝에 쓸모 없는 대통령은 필요 없다. 
결정적으로, 
책임을 질 줄 모르는 대통령은 필요 없다. 

덧붙임.
세월호 선장들과 선원들이 갖고 있다던 종교의 특징은
단 한 번의 회개로 이미 구원을 받았기 때문에 
‘아무리 잘못해도 죄책감을 느끼지 않는 것’ 이라 한다. 
이거,
굉장히 위험한 거다. 

죄책감을 느끼지도 못하는 대통령, 이들과 결코 다르지 않다.
사람에 대해 아파할 줄도 모르는 대통령은 더더욱 필요 없다.

진심으로 대통령의 하야를 원한다



2014년 4월 21일 월요일

생각을 남기자 2014년 4월 20일 ~ 21일


보자 마자 울컥했던 

뭐...이런것 쯤이야... 몇번 더 바뀔지 누가 알아

이건 뭐하자는 -.-;;

뉴스를 볼수록 정신이 깨지고



그사이에도 열심히 사람들의 목소리를 막느라 여념이 없는 사람들
이렇게 생긴 배였는데

넘어간 세월호

이름의 명예보다 자신의 목숨이 소중했던 계약직 선장



그사이 일요일 과천에서는 데이터센터에 불이나고

조선소에서 불이나서 사람들이 죽어간다.
안전한 사회라....행복해야 하는데

현 정부의 철학......

국정의 원리, 목표, 과제

철학

시대적 소명으로 지금까지의 국가중심 발전모델에서 벗어난, 국민행복과 국가발전의 선 순환을 지향한다.


정몽준 아들
기념사진 난리
치료를 위한 테이블에 약을 치우고 라면먹는 장관
북괴에 놀아나는 좌파가 정부 전복 나설것이라면 드립치는 새누리 의원 
...

생각도 없고 철학도 없다

걱정이내....

박통 처럼 잘(?) 하셔야 할 터인데

일단 그냥 보자....

오롯이  피에 새기자...

2014년 4월 19일 토요일

생각을 남기자 2014년 4월 16일 오전 ~ 19일

뭐라고 남길까...

살면서 이런 저런 감정을 느끼긴 했었지만

그 무게를 이해 하기에는 경험이 모자라고 아이의 머리를 가진터라 잘 알지 못했다


강북에 살면서 성북역 근처 고등학교를 다니던 시절

한강 어딘가의 다리가 이유없이 무너졌다는 방송과

등교하던 학생들이 죽었다는 이야기를 들으며

내가 강북에 있는것이 다행이라고 하며 웃었더랬고


길음동에 버스가 정류장을 덥쳐 등교를 위해 기다리던 학생들의

터진뇌가 교복위에 널브러진 것을 보고 식겁했지만

저 버스정류장에 내가 서있지 않았다는것에 안도 했으며


백화점이 무너지고 500명이 넘게 죽어나가도 TV를 보면서 그저 그냥 그러했다

가슴아픈 사연도 많았고 슬프기도 하였으나 지금 내 머리속에 큰 상처로 남지는 않았다


그렇게 시간이 지나

결혼을 하고 가족을 이루고 아이가 생기며 많은 것을 배웠다.

무식하면 용감하다고 했던가....

모르는게 약일 때가 있다고 했던가

타인의 죽음이 그사람의 죽음으로 느껴지지 않고

당신 또는 너의 죽음으로 느껴지기 시작한 나이

부인을 잃은 남편의 눈물

아이를 잃은 아빠의 눈물

감정이 들어간다

그리고 눈물이 흐른다


술 마실때면 누차 이야기하지만

사람은 아는만큼 이해하고

그만큼 만 고민하고

그만큼 만 행동하고

그래서 그만큼 만 성숙한다.


TV에 쓰래기처럼 쏟아져 나오는 이상한 이야기들과

매번 바뀌는 정부의 발표

자식이 아플까봐 이미 너무 흥분해버린 부모들의  절규


모두 흘려보낸다....

가슴을 뚫고 지나가는 감정을 ...쉽게...가볍게....느끼기란 쉽지 않아서

가끔 사랑의 리퀘스트를 보지 않는다며

비겁한 변명을 하는 친구나 내 와이프에게 이런말을 한다

"너 나 나나 비겁 한 것이지 무슨 변명이 필요하냐고"

사람의 죽음이 나에게 다가오지 않는것은

내가 아직 그 감정을 이해 하지 못하는 것이지

보니까 슬퍼서 더 안본다는 그 말은

내가 슬프기 싫은 것이지 다른사람의 아픔과는 아무 관계가 없다.



19일 02시 현재 실종 268명...

이것도 몇시간 전에 또 바뀌었다.(몇번이나 바꾸었는지 이젠 알지도 못하겠다)

이중에 얼마나 많은 사람이 사망으로 나올지

얼마나 많은 이들이 극적으로 구조될지 하늘만 알 일이겠다


하지만 짧은 내 감정으로는 가장 아플것 같은 일은

몇 달 후 실종으로 남아 있을 그 많을 사람들..


세상이 비겁하다.

먹고 살겠다고... 미래에 예상되는 책임의 문제가 현실의 아픔보다 큰 사람들

결정하지 않고....물어보고...기다리고....또 물어보고...기다리고....

그렇게 사람들은 죽어간다.


결정하지 않은 사람들의 말을 그냥 받아적어 기사랍시고...

하루종일 같은 이야기만 떠들며 확인되지 않았지만 자기가 말한 것이 아닌

책임질 일 없는 내용을 그저 적어서 읽어대는 사람들


그리고 그 내용들을 그저 머리로 듣고

살다가 만나는.... 그런 큰 일 중에 하나로....

그들의 죽음으로....저 멀리 밀어놓는 사람들


내가 어렸을때 그러했던 것 처럼......




난 이제 진주의 부모님 댁에 내려가면 물어보아야 겠다

당신이 이야기한 정부에 대한 믿음의 실체 무엇인지

일국의 수장으로 뽑혔으면 일을 할 수 있도록 해 주어야 한다는 생각을 가지고 있다

국가가 소중하니까  내 나라가 조금 망가지더라고

그저 큰 흐름에 잠시 쉬어가는 쉼표일 것이라고
(이것 역시 비겁한 변명이다....가슴이 아프다..)


어찌했든 그렇게 밀어놓고 살면서 이런저런 불합리한 상황으로 회귀되는 세상을 보면서

그 많은 사람들이 피를 흘리고 핍박 받아 이만큼 만들어 놓은 세상인데...

그 훌륭했던 선배들은 먼저 다 떠나 버리고

생각하지 않고 결정하지 않고

삶의 가치가 자본에 있는 자들이 득세한 이 세상이

당신이 만들어놓고 떠나고 싶은 세상이냐고


당신 손자가 죽지 안았으니 또 그렇게 나랏말씀을 듣지 않은 사람들을 욕할 것 이냐고

자기는 작은 손해에도 파르르 떨면서 살아왔으면서

지금 당장 나와 관계 없으니 그리고 그리 살 날도 많이 남지 않았으니

내 삶의 가치는 생명연장의 꿈이라고 ....


차라리 젊은 너희들이 나를 사랑해 주지 않아 외로워서

그 외로움이 분노가 되어 너희들이 좋아하는 세상이 샘나서

조금 투정부리는 것이라고...그렇게 이야기 해주면

불쌍하게라도 보아줄 것 같은데....

아는만큼만 고민하고 행동하고 살아 오셨다면

다 아실일인데...


국가의 문제가 아니라

정부의 문제가 아니라

개인의 문제라고 생각한다

사상이 없고

아는게 없으니

그만큼 만 고민하고 그만큼 만 행동할 뿐

자기는 아는게 없으니 고민도 없을 것이다


난 그들에게 벌을 내리고 싶다.

그 사람이 자신의 가장 가치있게 생각하는 것을 빼앗고 싶다.


살고 싶어 수백명을 버리고 탈출한 선장은 자신의 이름에 올려진 명예보다

자신의 목숨이 소중한 가치이겠으니 그것을 빼앗고 싶고


자본이 삶의 가치인 사람에게서는 돈을 빼았고


명예가 가치인 사람에게는 명예를 실추시키고


직장이나 공무원의 위치가 중요하다면 그것을 빼앗아


자신이 가치가 없는 인간임을 알게 해주고 싶다.


하지만 어찌하겠나

또 비겁한 변명으로

칼로 찔러 죽이지도 못하고
잡아다가 겁박해을 빼앗지도서 돈 못할것이고
능력이 안되니 짜르지도 못하겠지


하지만 계속 투덜대기는 하련다

최소한 내 자식들에게는 정상적인 사고를 심어 주고

그 후손이  그리고 또 그 후손이 상식적인 삶을 살고자 노력하고

그런사람이 많이 질 때 쯤이면 좋은 세상이 만들어 지지 않을까


생각없고 선택하지 못하는 사람들이 첫 단추를 잘못 끼웠다

그리고 불신이라는 씨앗이 심어졌고

그 불신은 자라 자식들을 빼앗길지 모른다는 불안함에 떠밀린 부모들을 흥분시켰다

그리고 그 흥분에 꼭두각시 놀음을 하는 대통령 덕분에

생각없고 선택하지 못하는 사람들은 두번째 단추를 잘 못 끼웠다

이제 이 악순환의 고리는

마구잡이로 열심히만 하자라는 막무가내가 될 것이고

또 다른 희생자들이 나올 것 이라는 생각은 불경스러운 생각인 것일까


지금의 흥분이 가라앉아 자식을 가슴에 품은 부모들이

세상을 향해 자신의 아픔을 알아달라고 소리칠때

지금과는 싹 바뀐얼굴로 그들을 핍박할 것이 분명한데

그런세상을 만들어 놓았는데....



많은 사람이 구조 되어 나오더라도

많은 사람의 죽음이 뒤 따를 것이 분명하겠기에

이렇게 엔트로피가 증가하면 결과는 붕괘일 것이다.


이제 더이상 이 세대에서 연대와 책임에 대한 이야기는 사치가 될 것이고

이미 자본적이고 자신만을 우주의 중심에 둔 많은 사람들은

슬픈 이야기를 떠나 더욱더 자신만을 사랑하겠지


1994학번 올해 마흔

나는 응답하고 싶지 않다

2014년 4월 15일 화요일

OEPN SSL RHEL관련된 취약점 내용

회사에 송과장님이 정리한 내용
RHEL 과 Open ssl 취약점

RHEL 6.5 미만에는 OPEN SSL이 기본 포함이 아니므로 관계가 없는 것은 아니고 ...
없으면 Apache 등을 운영하기 위해 깔았을 것이니 검토는 해보아야 합니다.

REHL 6.5 이상에서는 기본 포함되어 있으므로 사용/미사용을 떠나서 업데이트 해야 합니다.

==============

OpenSSL 취약점 관련 내용입니다.

Red Hat 의 내용.
    : OPENSSL은 Secure Sockets Layer(SSL v2/v3)와 Transport Layer Security(TLS v1) 프로토콜로 암호화를 위한 라이버러리입니다.
    : OPENSSL의 프로젝트 팀으로 부터 보안 이슈를 받아서 패치를 생성할 하였다는 사항이고, 이는 Red Hat의 잘못이 아니라 오픈소스인 Openssl에서 보안홀이 발생이 된 소스를 배포를 함으로 인해 모든 OS가-Openssl을 사용하는- 문제의 사항이 되는 것으로 이 문제의 라이브러리가 포함된 OS는 패치를 해야 되는 것입니다.
    : Red Hat 6에 해당이 되며 openssl-1.0.1e-15.el6 부터 openssl-1.0.1e-16.el6_5.4 패키지를 사용하는 OS가 해당 됩니다.
        ==> 이는 RHEL 6.5 이상 부터 OS에 포함이 되었으므로 하위버전은 상관이 없습니다.
            https://access.redhat.com/site/announcements/781953 에 해당 내용이 있습니다. (아래 발췌 참조)
            ==> 해당 버전은 RHEL 6.5, RHEV Hypervisor 6.5, RHS 2.1 입니다.


REDHAT의 홈페이지에 있는 내용으로는 아래링크를 참고 하시면 되고, https://rhn.redhat.com/errata/RHSA-2014-0376.html

다운로드는 아래링크를 참고하시기 바랍니다.
openssl-1.0.1e-16.el6_5.7.i686.rpm
https://rhn.redhat.com/rhn/software/packages/details/Overview.do?pid=930367
openssl-1.0.1e-16.el6_5.7.x86_64.rpm
https://rhn.redhat.com/rhn/software/packages/details/Overview.do?pid=930347
 

openssl 보안 취약점 관련하여 웹사이트에서 간단히 해당 보안 취약점에 해당 되는지 안되는지 확인 할 수 있는 사이트입니다.

http://filippo.io/Heartbleed/

해당 사이트에서 확인하고 싶은 웹사이트 주소를 치시면  해당 웹사이트가 openssl 보안 취약점에 해당 하는지 안하는지를 확인가능합니다. ps. 해당 취약점 보안패치 (openssl ) 하고 당연히 apache 혹은 웹 서버 프로세서 재기동 하여야 합니다.

감사합니다.

2014년 4월 12일 토요일

지랄도 이정도면 레전드

뭐.....뭐지???

차량 배터리 등 ‘자가 교환’ 금지 추진

http://news.naver.com/main/read.nhn?mode=LSD&mid=shm&sid1=103&oid=056&aid=0010019573

헐...규제푼다더니 장난하나...

엔진오일은 나도 귀찮아서 정비소간다...

오일 빼고나서 정비소가서 버리면 되지만 손버리고 청소하기 구찮아서

십분 이해해서 오일 막 버리는 쓰레기들이 있기도 하니

베터리는 요즘은 다들 무보충으로 배터리액을 버릴 일도 없고

베터리 안에 납이 있어서 반납(착불로 보내면된다)하면 돈으로 돌려주는등

재활용은 충분히  이루어지고 있고 환경오염도 걱정할 일 없는데

뭐지????  누가 로비한거임???  현대? 삼성?

쫌.....

세금미친듣이 더 뜯어가는거는 걍 그런다고 봐주마

지리산 단속 강화

차량운전 단속 강화

...아주 돈 뜯어내려고 발광들을 하는

지랄도 이정도면 레젼드라...


2014년 4월 11일 금요일

오랜만에 Garbage Collection 정리

  1. WAS를 다시보려니 JDK 8도 나오고.... 그러고보니 JDK 5 이후에는 JVM Spec을 찾아본적도 없고.... 간만에 6,7,8 한꺼번에 따라가 봅니다.  내용은 주로 Middleware의 성능튜닝과 관련된 HotSpot 관련 정보입니다.
  2. 문서에서는 다음과 같은 내용에 대한 정보를 제공합니다.
    1. JVM 이란?
    2. JVM에서 Heap과 GC란?
    3. GC 의 종류는
    4. GC 적용 전략
    5. What's new JDK 8
  3. JVM이란
    1. JVM의 장점
      1. 멀티 플랫폼, 높은 호환성
        1. 대부분의 OS에 맞는 JVM Binary 제공
      2. 개발 생산성, 잘 다듬어진 JAVA Comp
        1. Component-inheritance, Implement, Over….
      3. 개발/운영의 편의성
        1. 메모리 자동관리 (never malloc/free)
        2. 시스템 자원 자동할당
    2. JVM의 단점
      1. 이 죽일 놈의 속도 (JNI필수, 개선 JIT/hotspot compiler)
        1. 시어머니가 둘이다! (JNI Interface, OS Interface)
      2. 자동화의 단점, 통제가 안 된다
        1. 메모리 정리(GC)는 JVM 맘대로? System.gc()
        2. 공유객체(static obj)는 말 그대로 공유 쓰레기통?
      3. 높은 생산성 대비 막 운영(?), 막 개발(?)의 폐해
        1. 일단 돌아가게 메모리 많이 줘버려! 
        2. 알아볼 수 없는 코드, 1000개 조회 해서 10개 쓴다, 나쁜 유지관리
    3. OS 측면에서 보면  JVM도 Process 일 뿐이다.
      1. JAVA Process는?
    4. JVM입장에서 보면 WAS도 Java Application 일 뿐이다.
      1. JVM위에서 구현된 Application = Web Application Server
      2. 성능과 자기만의 색깔을 위해 도입된 JNI 와 확장 Package들
        1. JNI : Java Native Thread 들, JVM의 취약점인 IO관련 작업을 C로 처리한다
          1. 사용자 요청을 받아들이는 Server Socket 부문
          2. DB Connection을 생성하는 Client Socket 부문
          3. Log Write를 관리하는 File IO부문 
        2. 확장 Package
          1. Open Source 들 중에 괜찮은 Pkg를 선택해서 추가한다.
          2. 추가할때 그냥 하면 빈티 나니까.... 의존성을 높이기 위해... 편의 API를 제공한다.
            1. JMS를  쓰겠다고 Weblogic Intigration API를 사용했다면 Weblogic에 의존적이됨
            2. Session 공유를 하겠다고 JBoss Infinispan을 쓰면 JBoss와 노예계약  (잘 쓰면 득 못쓰면 독)
      3. WAS의 일반적인 버그는 기능 설정과 관련이 있다
      4. WAS의 Critical 버그는 JVM 버그에 의존적이다.
  4.  JVM에서 Heap 과 GC란
    1. Heap
      1. JAVA Object들의 작업 공간 (Sun(oracle) JVM / HP JVM Architecture,  not equal IBM / BEA(ORACLE) jrockit)
        1. Sun JVM 구조
          1. NEW(Eden) : 신규 생성 되는 객체 들이 저장 되는곳  
          2. Survivor 1(From,ss1),2(To,ss2) : Old로 이전 되기 전 Promotion 대상이 되기 위해 거쳐 가는 곳
          3. Old : 오래(?) 사용되어야 하거나 NEW가 부족한 경우 저장되는 공간
          4. Perm(Permanent) : java code, method들의 List,Static Object 들이 저장되는 공간 (메타데이터라고 들 한다), 
          5. Stack : Thread 당 할당된다.(너무 크게 잡으면 메모리 낭비, 적으면 Stack Overflow)   
          6. Native(Other) : JNI관련 시스템 Object들이 사용하는 공간 
            1. !! Xmx 2G로 잡았는데  Top 명령에서 RSS를 보면 2G를 넘는이유는 Stack 과 Native가 잡는 영역 때문이다.
            2. !! 예를들어 기본적으로 Xmx보다 너무 크다면 Xss를 너무 크게 잡으면 늘어난다.
            3. !! 동적으로 Xmx 보다 크게 늘어난다면 File IO 또는 Socket IO 용 버퍼가 크거나 많이 사용되면 늘어날 수 있다.
            4. !! JIT로 인한 증가는 일반적으로 수백Mbyte 이하이다. JIT로 인한 메모리 누수에는 아래와 같이 JIT대상에서 제외 할 수 있다.
              1. -Xjit:exclude={package/class.method|package/class.method}
              2. 또는 파일에 exclude 대상을 리스팅하여 넣고(한줄에 제외할 메서드 하나씩)
                1. .hotspot_compiler  파일을 만들고 안에다가 내용을 넣는다.
                  1. exclude com/amir/SomeClass someMethod  (한줄에 하나씩, Class를 넣어도 되고 Method를 넣어도 된다.)
                2. -XX:CompileCommandFile=/my/excludefile/location/.hotspot_compiler
            5. JNI로 별도로 개발된 모듈의 메모리 누수는 ..... JNI 할아버지를 불러야 한다...

        2. SUN JVM 구조 
          The memory model of the Sun Hotspot JVM
        3. BEA JVM 구조 (Nursery : 보육장 - Sun의 ᅟ Young)
          Heap of the Oracle JRockit JVM
        4. IBM JVM 구조
          The IBM JVM generational heap
        5. Sun JVM G1 구조

          Humongous(엄청난?) : region의 50%가 넘는 크기의 Obj가 생성되면 Humongous region(몇 개의 region을 합함)으로 저장한다.
        6. Sun JVM의 상세 구조
        7. Heap에 저장되는 Object의 구조 
    2. Garbage Collection 
      1. 이란
        1. Referrer가 없는 Object  들을 메모리에서 제거(Minor, MajorGC) 하거나 지속해서 사용할 Object를 Promotion 하여 저장(OLD)
        2. 단편화된 메모리 공간을 조각 모음 하는 작업
          1. Live,reachable Object : 현재 사용 중인 Object로 GC대상이 아니다.
          2. Unreachable Object :  사용하지 않는 Objject의경우 GC 대상이 된다.
          3. 사용중 과 아님의 기준은? : 참조하는 상위클래스가있는가 == 나에게 referrer가 있는가 
          4. Static Object : Static Object로 선언한 객체의 경우 GC 대상이 아니다.
          5. 위와 같은 그림이지만 Root set이라는 개념과 Obj중 상위 클래스를 참조하는 경우라도 상위 클래스의 참조가 없으면 unreachable 이라는것이 설명 가능해서 추가함
      2. 메모리 관리를 위한 기본 컨셉
        1. weak generational hypothesis  (영역에 대한 자신 없는 가설)
          1. 대부분의 객체는 금방 접근 불가능 상태(unreachable)가 된다.
          2. 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.
        2. 그래서 두 개의 영역으로 쪼갰다
          1. Young 영역(Yong Generation 영역): 새롭게 생성한 객체의 대부분이 여기에 위치한다. 대부분의 객체가 금방 접근 불가능 상태가 되기 때문에 매우 많은 객체가 Young 영역에 생성되었다가 사라진다. 이 영역에서 객체가 사라질때 Minor GC가 발생한다고 말한다.
          2. Old 영역(Old Generation 영역): 접근 불가능 상태로 되지 않아 Young 영역에서 살아남은 객체가 여기로 복사된다. 대부분 Young 영역보다 크게 할당하며, 크기가 큰 만큼 Young 영역보다 GC는 적게 발생한다. 이 영역에서 객체가 사라질 때 Major GC(혹은 Full GC)가 발생한다고 말한다.
        3. 그래도 느리다.
          1. 병렬로 처리 하자
          2. 실시간으로 처리하자
        4. 구조적으로 도저히 방법이 없다. 해결하자
          1. New/Old개념은 가져가되 구조적 영역은 포기
          2. CG First(G1) 알고리즘 제공
      3. 하면
        1. 기본적으로 JVM은 STW (Stop The World) 된다. (GC 튜닝은 STW을 줄이는것이 최종 목표)
      4. 하고 나면 
        1. 필요한 메모리가 정리되고 새로운 Object 생성이 가능하다
      5. 실패하면
        1. 지속적으로 GC를 시도하게 되며, 그동안 STW 상태이므로 사용자는 장애로 판단한다.



      6. 실패하는 이유
        1. 생성해야 할 Object가 너무 큰 거나 Heap이 부족하거나
          1. 생성하고자 하는 Object가 New 영역보다 작을때 : Minor GC를 수행하고 남는 공간이 생성할 공간만 큼 되면 생성한다.
          2. 생성하고자 하는 Object가 New 영역보다 크거나, Minor GC후에도 공간이 없으면 : Old 영역으로 바로 Promotion을 진행한다.
          3. 생성하고자 하는 Object가 Old 영역보다 작고, Old 영역에 여유가 있다면  :  정상적으로 생성하고 진행한다.
          4. 생성하고자 하는 Object가 Old 영역보다 작고, Old 영역에 여유가 없다면  :  Full GC를 수행하고 저장을 시도한다.
          5. Full GC후에도 Old 영역에 여유가 없다면 : OOM 발생하고 객체 생성에 실패한다.
          6. 생성하고자 하는 Object가 Old 영역보다 크면 : OOM 발생하고 객체 생성에 실패한다.
          7. 주의사항
            1. !! OOM이 발생해도 이론상 JVM이 깨지거나 문제가 발생해서는 않된다.(해당 APP의 Exception발생은 정상적인것임)
            2. !! OOM이 발생하면서 JVM에 무한 Full GC가 나거나 Hang 상태로 보이는 이유는 우리가 본 시점의 OOM이 문제가 아니라 OOM이 발생되도록 메모리를 점유하고 있는 그 무엇인가가 문제이다.  (로그를 보고 OOM발생 Exception의 APP를 무조건 의심하면 안된다.)
        2. Object가 지속적으로 Heap을 점유하는 경우
          1. 생성해야 할 Obj의 크기가 크지 않더라도 절대적인 Heap의 여유 공간이 없다면 OOM이 지속적으로 발생한다.
          2. 대표적인 OOM 발생 원인은
            1. Static 객체에 연결한 대량의 정보
              1. 코드상에 Static final로 정의한 사용자 Obj
              2. 세션 객체에 저장한 대용량 Obj
            2. WAS 연계 시스템의 지연
              1. DB Query가 무겁거나 DB에 문제가 있어 응답이 느리면 해당 처리를 위해 Thread가 대기하고 Thread가 사용중이던 Heap의 Object들은 Refere가 유지되므로 OOM 발생이 될 수 있다.
              2. 기타 원격지 연계시스템(결제, 승인, 실명확인 등)의 경우에도 동일한 증상으로 인하여 OOM 발생위험이 있다.
            3. 마구잡이 개발
              1. DB Cache 객체를 사용하는데 적절한 통제 없이 마구 저장할 경우 절대적인 heap 사이즈가 부족해진다.
              2. 잘못된 코드로 대량 객체를 생성하고 해당 객체를 JSP등에서 세션 범위에서 사용하는 경우 사용자가 늘어나면 OOM이 발생한다.
    3. Promotion 이란  
        1. New 영역은 사용자 호출에 의해 처음으로 생성된 객체(Object = 실 메모리를 점유하는)가 만들어지는 1차 작업 공간입니다.
        2. 이 공간의 영역은 제한적(-Xmn)이므로 지속적으로 사용될 것 같은 Object들은 절차에 따라 Old 영역으로 넘어가게 되며 이 절차를 Promotion이라고 합니다.
        3. GC에서 사용되는 단어 설명
          1. Mark : Object가 현재 사용되고 있는지에 대한 검사, 기준은 Referrer가 있는가, 즉 이 Object가 Applicaiton Code상에서 연결된 것이 아직 사용되고 있는가 (Minor GC)
          2. Sweep : Mark 대상이 된 Object를 불용처리합니다, 실제 메모리를 지우는 작업은 아니고 File 삭제시 FAT에서 정보만 지우듯이 Object 메모리 주소번지만 제거됩니다. (Minor GC)
          3. Compact
            1. 조각모음이라고 보시면 됩니다. 이 작업은 평소에는 수행 되지 않으며 Full GC 시에 수행됩니다. 이 작업의 기본컨셉은 STW(Stop The World)
            2. sweep 된 Object들이 차지하던 공간을 다른 Object들을 이동시켜 메꾸어 단편화를 정리합니다.
            3. JVM의 Heap 공간의 메모리 관리는 Object가 생성 될때 해당 Object가 차지 하는 공간이 연속된 주소공간으로 확보되어야 합니다.
            4. 100M의 여유공간이 있더라도 단편화 되어 연속된 빈 공간이 없다면 Compact를 통하여 정리하게 됩니다.  (Major GC)
        4. Promotion의 진행 순서는 아래와 같이 진행됩니다.  (GC 알고리즘에 따라 조금씩 다르지만 기본 사항으로 이해 하시면 됩니다. G1은 완전 다름...)

          1. 그림은 처음 영역을 표현 합니다 Eden(NEW) 영역에 각자 다른 크기의 Object들이 존재합니다.
            From, To 영역은 Eden 영역의 작은 Object가 OLD로 바로 Promotion이 되지 않고 몇 번의 이동 작업(MaxTenuringThreshold)을 거치다가 sweep 되도록 유도합니다.
            그림에서는 Eden에 있던 일부 객체들은 From 영역으로 이동 되어 있습니다.
        5. 마이너 GC가 발생 되는 순간의 그림입니다.
          1. Yonung 영역에서 Referer가 없는 object는 제거 되고 사용 중인 경우 Survivor space로 이동 됩니다. (From,To의 이동은 통째로 이동 됩니다.  그래서 두 개의 영역의 사이즈는 동일하고, survivor로 들어가는 Obj도 이번 차수에 이동될 영역으로 들어갑니다.)
          2. From 영역에서 Referer가 없는 객체가 제거 됩니다.
          3. From, to를 수 회 왔다 갔다(-XX:MaxTenuringThreshold=32) 한 Obj가 아직 referer가 살아 있다면 Old로 넘어갑니다.
          4. From에 저장되어 있던 obj 중에서 아직 Old로 넘어갈 카운트가 안된 경우 To로 이동 됩니다. (MaxTenuringThreshold 수치까지 왔다리 갔다리 합니다.)
          5. Old에는 앞서 단계를 거치고 살아남은 Obj가 저장되어 있습니다.
        6. 마이너 GC가 수행 되고 나면 다음과 같이 정리 된 상태가 됩니다.

        7. 아래는 Compaction(Full GC)의 그림입니다.
          1. Referer가 없는 Obj는 Mark 됩니다.
          2. Mark 된 Obj는 Sweep 됩니다.  (실제 삭제 작업은 이루어 지지 않으나 Stack에 정보를 삭제)
          3. 주변의 Obj를 순차적으로 이동하여 fragment를 제거합니다.
          4. 이 작업이 수행되는 동안은 STW 입니다.
  5. Full GC & GC Type
    1. 란?
      1. Old 영역 부족, Perm 영역 부족에 의하여 발생
      2. JVM이 상대적으로 느린 것은 어쩔 수 없고, 결국 STW(Stop The World)의 최소화가 관건이다.
    2. 가 일어나면?
      1. 처리 되는 기간 동안 JVM은 동작을 멈춘다 
      2. 일반적인 기준으로 JVM의 가용율에서 STW는 5% 미만으로 통제하여야 한다. 
      3. 24시간 운영시 ( 86400초 * 0.05 = 4320초 ) 최대 72분 내로 통제 (웹서비스 에서는 이것도 너무 러프 하다)
      4. 다만 연속적이면 무조건 안 된다. (말도 안되기는 하지만 72분 동안 WAS가 정지하면 누가 이해 하겠어?)
      5. 간격으로 이야기 하자면 허용 Duratiuon Time이 5Sec 라면  되도록 균등해야 하므로 
        1. 하루의 5%를 GC허용 시간으로 가정하면 = 72분 
        2. GC허용 시간을 GC수행 허용 시간(duration) 나누면 =  864회(72분 / 허용시간 = 4320sec / 5sec) 이하 발생해야 하므로
        3. 1일 기준 가용시간 = 86400sec - 4320sec  =  859680sec ( = 1일 - 허용GC시간)  
        4. 허용 발생회수를 나누면  = 859680sec / 864회 = 995초(약 17분) 간격을 평균 간격으로 이야기 할 수 있다.
    3. 실패하면
      1. VM입장에서는 메모리를 정리해야 다음 처리가 가능하므로 무한 Full GC가 반복된다. =지속적 STW
      2. APP 입장에서는 Out Of Memory Exception이 발생하고 처리가 중지된다.
      3. 간혹 JVM이 죽어버리는 경우도 발생한다. 
      4. 결과적으로 Full GC가 발생하는 것은 인정하지만 실패는 발생하면 안된다.
    4. CMS에서의 Full GC(CMS는 Full  GC를 예방하는 방식이지만 한번 발생하면 대책이 없다...)
      1. CMS는 기본 구조에서 Old 영역에 대한 Compaction 작업을 수행하지 않습니다. (메모리 단편화가 증가함)
      2. JAVA의 Heap 구조에서 Obj는 연속된 메모리 주소공간이 확보 되지 않으면 객체 생성에 실패합니다.  (단편화 되어 100M가 있어봐야 Obj는 생성에 실패할 수 있다)
      3. 이러한 이유로 Old 영역이 실 사용량 보다 적거나 너무 타이트하게 할당될 경우 CMS 무한 Full GC가 발생할 수 있습니다.
      4. 해결하기 위한 컨셉은 아래와 같은 옵션으로 접근한다.
        1. -XX:SurvivorRatio : From, To 영역의 사이즈를 키워서 작은 obj(단편화 원인)를 Old로 Promotion 되지 않도록 유도(From, To 에서 GC 되기를 기대할 뿐 늘린다고 해결 되지 않는다)
        2. -XX:MaxTenuringThreshold : Promotion 조건인 From, To 영역의 이동 카운트값을 늘려서 더 많이 이동(왔다리 갔다리)하게 만들어서 Old로 Promotion 되지 않도록 유도
        3. -XX:CMSInitiatingOccupancyFraction : CMS 동작의 트리거를 좀 더 빨리 동작하도록 한다, 예를 들어 사용율 60%부터 동작한다면 30%로 줄여서 미리 CMS를 구동해서 단편화를 제거한다(compact를 하는것이 아니기때문에)
        4. -XX:+UseCMSInitiatingOccupancyOnly :항상 CMS를 점진적으로 사용하도록 합니다. 
    5. STW 개선방안은?  (GC 알고리즘)
      1. JVM의 GC에서 메모리를 정리하는 것은 JVM 내에 있는 APP(HotSpot)이다. 이 APP는 Thread로 동작한다.
        1. Serial GC(-XX:+UseSerialGC) : 기본적은 GC는 1개의 Core가 있는 시스템등에 적용하기 위한 GC로 PC Application등에는 가능하나 서버에는 적용해서는 안된다.
        2. Parallel GC(-XX:+UseParallelGC) : JDK6에서는 기본 GC, N 개의 GC Thread가 있으면 전체 STW Time은 1/n 이다 (이론적으로 하지만 좀 더 걸린다.) 
        3. Parallel Old GC(-XX+UseParallelOldGC) :  JDK5 update 6부터 제공되었으며 Parallel GC와 동일하지만 Old 영역 GC 구조가 변경되어  Mark-Summary-Compaction 단계를 거친다. (XX:+UseParallelGC를 적용하면 기본 활성화 됨)
        4. Concurrent Mark&Sweep GC(-XX:+UseConcMarkSweepGC) : N개의 Thread + 계속적인 GC를 통하여 STW이 발생하지 않도록 최소화 하는 방법도 있다. (CMS라고 부른다)
        5. Minor GC발생시 Old도 덤으로 GC하는 Train GC(-Xincgc) = Incremental GC 도 있다.  (컨셉은 훌륭한데....거의 사용 안함), JDK8에서 Deprecate 됨
        6. G1 (Garbage First)GC(-XX:+UseG1GC) : JDK 6에서 early access로 제공했으며 JDK 7 update4 에서 정식으로 적용되었다. Server style GC라고 부른단다 ^^
          http://www.oracle.com/technetwork/java/javase/tech/g1-intro-jsp-135488.html
          1. CMS가 Old 영역의 Fragement에 대응하지 못하고 무한 Full GC를 수행하는 문제점이 있고 이를 해결 하기 위한 방안으로 제시되었다  
          2. Multi Process + Lage Memory 시스템을 대상으로 한다.  (Heap 1~2G 시스템에 적용하면 Overhead로 오히려 성능 문제가 발생할 수 도 있을 듯....이건 추정임)
          3. New,Old 영역에 연속된 메모리 주소(물리적) 에 대한 구조적 개념을 버리고 메모리 영역을 통으로 관리 함으로써 프로모션이라는 것 자체가 없어졌다. 
          4. 전체 메모리를 Region(지방,부문) 이라고 부르는 대략 1Mbyte단위(-XX:G1HeapRegionSize=size)의 블럭형식 단위로 분할 하고 이 영역에 객체를 생성한다. 
            1. JDK 8 기본 사이즈는 JVM이 상황 봐서 정의 한답니다. The default region size is determined ergonomically based on the heap size.
            2. JDK 6 u26에서는  init heap size / 2048 이였다.  (아마도 JDK8도 동일할 듯)
          5. New,Old 가 없으므로 Promotion이 없으며 메모리 할당 제어를 Evacuation(이바큐에이션-소개,비우다) 이라고 부른다. (개념은 비슷함)
          6. 내부적으로 GC동작에 대한 기준은 STW 시간에 대한 목표치를 가지고 동작한다.  –XX:MaxGCPauseMillis=<n>, default value = 200ms.  (거의 실시간으로 봐야할 듯)
          7. 목표치 시간에 대한 GC가 될 수 있도록 내부적으로 추정해서 동작한다.(알고리즘은 잘 모르겠어요....) 즉 짧게 지정할 수 록 GC가 빨리 동작하고 = 자원을 많이 먹는다
          8. 기존 Old 영역에서 참조하는 New 영역의 객체 정보(referrer)를 관리하던 Card Table이 전체 region에 대한 객체 referrer에 대한 관리형태로 변경되었다.(Remembered Sets 이라고 한다)
          9. 2014년 Q1 현재 G1을 공식적으로 지원하는 JVM은 ORACLE JDK(Sun JDK) 뿐이다.
          10. 현재 G1 GC로그를 분석할 수 있는 툴은 개발되어 있지 않다. log를 보고 직접 분석해야 한다. (-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps  -XX:+PrintHeapAtGC)
            1. -XX:+UnlockExperimentalVMOptions 옵션은 JVM에 실험적 옵션을 활성화 하는 옵션이다.
            2. JDK7 update4 부터는 위 옵션을 넣지 않아도 된다.  (jdk6, jdk7 u3이하에 사용)
          11. Option and Default Value
            Description
            -XX:+UseG1GCUse the Garbage First (G1) Collector
            -XX:MaxGCPauseMillis=nSets a target for the maximum GC pause time. This is a soft goal, and the JVM will make its best effort to achieve it.
            -XX:InitiatingHeapOccupancyPercent=nPercentage of the (entire) heap occupancy to start a concurrent GC cycle. It is used by GCs that trigger a concurrent GC cycle based on the occupancy of the entire heap, not just one of the generations (e.g., G1). A value of 0 denotes 'do constant GC cycles'. The default value is 45.
            -XX:NewRatio=nRatio of old/new generation sizes. The default value is 2.
            -XX:SurvivorRatio=nRatio of eden/survivor space size. The default value is 8.
            -XX:MaxTenuringThreshold=nMaximum value for tenuring threshold. The default value is 15.
            -XX:ParallelGCThreads=nSets the number of threads used during parallel phases of the garbage collectors. The default value varies with the platform on which the JVM is running.
            -XX:ConcGCThreads=nNumber of threads concurrent garbage collectors will use. The default value varies with the platform on which the JVM is running.
            -XX:G1ReservePercent=nSets the amount of heap that is reserved as a false ceiling to reduce the possibility of promotion failure. The default value is 10.
            -XX:G1HeapRegionSize=nWith G1 the Java heap is subdivided into uniformly sized regions. This sets the size of the individual sub-divisions. The default value of this parameter is determined ergonomically based upon heap size. The minimum value is 1Mb and the maximum value is 32Mb.
          12. G1의 동작 (기존과 다르게 G1은 GC가 시작되면 Young region 정리(MinorGC)후 Evacuation 과 Compaction(MajorGC)가 연속으로 진행된다.)
            1. 기동
              1. G1으로 설정한 JVM은 New/SS/Old 로 구분되는 물리적 메모리 구분 없이 region으로 불리는 메모리 블럭을 구성하면서 기동 된다.
              2. 논리적으로 New/SS/Old는 존재 하지만 물리적으로 주소번지로 구분 되지 않는다.
              3. 초기 Object들은 임의의 region에 생성되며 해당 obj의 referrer 정보는 Remember set(전체 Heap에서 5%수준을 사용)에 저장된다.
              4. region 크기보다 큰 obj가 생성되어야 한다면 몇 개의 region에 걸쳐서 Object를 생성하게 되고(인접해 있는) 이러한 region 집합을 Humongos라고 부른다. 이 정보도 remember set에 저장된다.
            2. ᅟYoung GC = Minor GC
              1. 수행단계 (Marking -> Remarking -> Evacuation )
                1. Concurrent Mark : Single Thread로 진행, 정지없음, remember set의 referrer 정보를 참조하여 live가 아닌것만 빠르게 마킹한다.
                2. Remarking : 병렬로 진행, 정지 없음, Region마다 live obj의 밀도(전체 Obj중에서 Live 비율)를 계산하고 만약 UnReachable Obj만 있을 경우 Region 자체를 폐기한다.
                3. Evacuation : 병렬로 진행, 정지시간 있음. region의 live obj 밀도가 낮은 region에 대하여 Evacuation을 실행한다.
                  1. 정리 대상 region에서 live obj는 새로운 region(Promotion age에 따라 ss 또는 old region) 으로 복사 된다.
                  2. 논리적으로 Serviver 영역(SS)인 다른 region으로 복사 거나 Live Obj만 있는 region(논리적으로 Old영역)으로 복사된다.
                  3. 이동 후에 unReachable obj만 있는 region은 폐기된다.
                  Icon
                  Marking 작업은 snapshopt-at-the-begining(SATB) Marking 알고리즘을 사용한다. 
                  1. GC 실행시 remember set의 reference 정보를 기준으로 모든 Live Obj의 reference를 추적하고, referrrer가 없는 Obj를 mark한다.
                  2. 이때 Mark 작업은 병행수행(Concurrent)되므로 remember set이 지속적으로 변경된다(비교기준이 없다) 그렇기 때문에 GC 시작시의 remeber set의 snapshot을 기준으로 변경된 내용에 대해서 Marking 작업을 수행하게 된다.(전체 Scan이 아니므로 빠르다)
              2. 설명
                1. 시간이 지나면 referrer가 없는 obj들이 증가 되게 된다. (remeber set을 참고하여 지속적으로 region에 대하여 Concurrent Mark가 수행됨)
                2. Minor GC는 실시간으로 지속적으로 수행 되나 전체에 대한 GC는 아니고 region단위로 수행되며 Live Obj가 없는 region은 폐기함으로써 메모리를 정리하게 된다.  (전체적으로는 메모리가 정리되지만 단편화가 증가한다.)
            3. Old GC = Major GC
              1. 수행단계 (Evacuation -> Compaction)
                1. Evacuation
                  1. yong GC의 Evacuation과 동일한 방식으로 시작한다.
                    1. 앞서 Scan한 정보를 기반으로 region의 live obj 밀도가 낮은 region에 대하여 Evacuation을 실행한다.
                    2. 정리 대상 region에서 live obj는 새로운 region(Promotion age에 따라 ss 또는 old region) 으로 복사 된다.
                    3. 논리적으로 Serviver 영역(SS)인 다른 region으로 복사 거나 Live Obj만 있는 region(논리적으로 Old영역)으로 복사된다.
                    4. 이동 후에 unReachable obj만 있는 region은 폐기된다.
                  2. 이때 앞서 진행하면서 Survivor region으로 지정된 영역과 Old region으로 지정된 영역이 이동 되어 메모리 앞쪽으로 정리된다.
                2. Compaction
                  1. Evacuation을 거치고 나면 전체 메모리에서 Live Obj가 있는 young region에 해당하는 영역들이 듬성듬성(단편화) 존재하게 된다.(위의 그림 우측)
                  2. 메모리가 부족하거나 GC 수행시간이 설정보다 길어질 것으로 판단되면 GC를 다시 수행하면서 region들을 앞쪽으로 이동 시켜 정리하게 된다.
              2. 설명
                1. Evacuation작업은 Minor(yongGC)와 동일한 작업을 수행하지만 정리된 region을 이동시키는 부분이 조금 다르다.
                2. G1의 Compaction 작업은 region 단위로 이루어지며
                3. 해당 region을 참조하는 Thread가 잠시 느려지기는 하지만  
                4. 전체적으로 서비스는 진행 중이므로 STW은 발생하지 않는다. (아주 짧은 정지는 있다)
  6. Garbge Collection strategy
    1. Throughput VS Response Time trade-off
      1. 단위 시간당 일량(Throughput)을 증가시키려면 GC소요시간=횟수를 줄여야 하고 GC를 줄이기 위해 CMS나 병렬GC를 사용하는 경우 CPU자원을 더 사용하게 되고 
      2. 정해진 자원에서 더 많은 CPU를 사용한다는 것은 응답시간의 증가와 같으므로 Response time과 반비례 하게 된다.(라고 문서상에 표현한다.)
        1. 하지만 최근에는 워낙 장비의 CPU Power들이 좋기 때문에 GC를 줄이기 위해 복잡한 GC 알고리즘을 사용한다고 Response time과 반비례 하지는 않는다.
        2. GC를 실시간으로 처리하는 경우  비교적(GC를 한꺼번에 하는 것 보다는) Response Time이 증가하지만 성능상 영향은 미미하므로 무시할 수준이라고 판단하면 됩니다.
      3. 쓰루풋 중심 튜닝 (WEB Service는 요고이 중요하다)
        1. 응답시간을 조금 늘이더라도 GC가 최대한 발생하지 않도록 한다.
        2. Parallel Algorithm 
          1. 여러 개 Thread 가 Full GC 를 최대한 빨리 끝낸다.
          2. CMS에 비하여 안정성 높음 
        3. Concurrent Algorithm (CMS)
          1. 여러 Thread + 실시간으로 Mark & Sweep = Full GC 최대한 방지
          2. CPU 자원 가장 많이 사용
          3. Parallel과 Serial에 비하여 안정성에 문제가 있다. Object Type(small or big size)JVM 및 OS 마다 조금씩 다르다
        4. G1
          1. 메모리 영역을 순차적으로 관리하지 않고 1Mbyte 단위의 Region이라는 블럭들을 사용하고 Compact를 배제 시킴으로써
          2. GC의 발생을 줄이는 것 과 함께 GC 수행시간을 개선시킴
          3. 메모리상의 region에 대한 연관관계(referrer)를 관리하기 위한 Overhead가 있으므로  작은 heap 영역을 사용하는 경우 오히려 좋지 않을 수 도 있다(Xmx 2G 이하 등)
      4. 응답성능 중심 튜닝 
        1. Default(Serial) Algorithm
          1. Full GC가 발생하더라도 속도가 중요하다.
          2. 단독 APP의 경우 기본이 차라리 나을때가 있다.
    2. 업무 형태에 따른 튜닝
      1. 포털 VS 업무시스템
        1. 포털
          1. 다수의 사용자가 짧은 방문시간을 유지하며 많은 페이지를 호출한다.
          2. 이 경우 JVM에서는 Old 보다는 New영역에 대한 객체 생성 관리가 중요하다.
          3. 최대한 Old영역으로의 Promotion을 적게 하도록 하여 Full GC로 인한 정지시간이 작아지도록 하고
          4. 작은 Obj들이 old에 저장됨으로써 발생하는 단편화가 작아지도록 적용해야 한다.
          5. 관련 옵션
            1. -XX:NewRatio=3 (default 2) : heap에서 New영역에 대한 비율 정의,  New 영역을 크게(Old보다는 작아야 한다)하여 더 많은 객체를 저장하도록 하여 Old Promotion을 줄인다.(Ratio 가 아닌 -Xms= -Xmx= -XX:NewSize= -XX:MaxNewSize= -XX:SurvivorRatio=  를 조합해도 된다.)
            2. -XX:SurvivorRatio=2 (default 8): New영역에서 Survivor 영역에 대한 비율, 기본 사이즈보다 크게 해서 Old Promotion을 줄인다.
            3. -XX:TargetSurvivorRatio=90 : SS 영역정리 기준을 기존 50%에서 90%로 올려 Old Promotion을 줄인다.
            4. -XX:MaxTenuringThreshold=64 (default 15/CMS = 4): SS에서 새로 만들어졌고 , 작은 크기의 Obj들이 SS1,SS2를 더 많이 채류하도록 하여 Old Promotion을 줄인다.
        2. 원장조회, 매출실적 조회
          1. 정해진 인원이 오랜시간동안 대량의 데이터를 조회
          2. 일반적으로 비정형화 된 데이터에 대한 조회를 수행하는 경우 New 영역의 사용빈도가 낮다.
          3. New 영역보다 큰 데이터 사이즈가 빈번하게 저장되므로 주로 Old로 바로 프로모션되는 케이스가 많다.
          4. 이러한 경우 실시간 계열의 GC는 큰 효용성이 없다.
          5. Old 영역을 크게 잡아주고 GC는 단순하게 하는것이 좋다(그래도 single 보다는 Para를 적용한다. CMS는 비추천)
          6. 대량 장표 조회는 WAS에서는 어렵고 최근에는 BI로 거의 넘어갔으며  Bigdata 쪽으로 트렌드를 가지고 간다.
  7. CASE Study
    1. Mass traffic web site Heap Tuning 
      1. JVM Option
        Icon
        Open Market Front Web Site Heap
        -server / 서버운영에 맞도록 자동설정, 최대한 class loading이 처리 된 다음 구동 되도록 한다. 부팅 시간은 오래 걸리지만 서비스 aging time이 짧다
        -Xms2700m / 최소 Heap
        -Xmx2700m / 최대 Heap
        -XX:NewRatio=3 / Heap에서 NEW의 비율
        -Xss128k / 스텍사이즈
        -XX:SurvivorRatio=2 / Edne에서 SS영역의 비율
        -XX:TargetSurvivorRatio=90 / SS 영역의 90%까지만 유지하도록 노력
        -XX:InitialCodeCacheSize=64m / JIT 코드케쉬영역 지정(Native Area)
        -XX:ReservedCodeCacheSize=128M / JIT 코드케쉬영역 최대사이즈 할당 (Native Area)
        -XX:PermSize=350m / Perm사이즈
        -XX:MaxPermSize=400m /최대사이즈 (일반적으로 PermSize와 동일하게 하지만 지속적인 증가를 모니터링하기 위해 좀 더 크게 잡았음)
        -XX:MaxTenuringThreshold=64 64회 SS1,2를 이동하면 OLD로 프로모션
        -XX:+UseParallelGC : 병렬GC
        -XX:ParallelGCThreads=6 : Thread수
        -XX:-UseAdaptiveSizePolicy : New/SS 비율 자동변경 중지
        -XX:+DisableExplicitGC : System.gc()를 통한 수동 GC 트리거 방지  -XX:+ExplicitGCInvokesConcurrent 도 있다. CMS에서 GC 트리거를 방지한다.
        아래 것들은 덤프 분석을 위한
        -XX:+HeapDumpOnCtrlBreak
        -XX:+HeapDumpOnOutOfMemoryError
        -verbosegc
        -XX:+PrintGCDetails
        -XX:+PrintGCTimeStamps
        -XX:+DisableExplicitGC
        -Xloggc:/log/weblogics/${SERVER_NAME}/${SERVER_NAME}_gc_`date +'%y%m%d%H%M%S'`"
      2. 설명
        New Old 비율은 성능에 큰 영향을 줍니다. 일반적으로 비율은 2, 3 에서 이론적 수치가 가장 잘 나옵니다.
        다만 실제 Production에서는 다양한 형태의 Object들이 생성되기 때문에 이론적 TEST결과와 부합되지 않으므로 비율 설정에 따른 모니터링 결과를 반영해야 합니다. 
        Icon
        NEW영역 과 OLD영역 의 계산
        NewRatio 3 = NEW Generation : Old Generation = 1:3
        2700M 이면 2700 / 4 = 675M(NEW) : 2025M(OLD)
        SurvivorRatio 2 = New에서 Eden 의 SS1,2와의 비율 = SS1 : SS2 : Eden = (1:1):2
        675M 이면 675 / 4 = 168M 168M : 504M = (84M:84M):504M

    2. Back Office 에서 Full GC
      1. 기업의 back office applicaiton이라 함은 ERP나 벌크성 데이터를 수집 가공하는 업무가 많음
      2. 이런 경우 너무 많은 SQL 결과값에 의하여 Heap 영역이 부족함으로 인한 문제가 종종 발생함
      3. Full GC가 일어나는 순서는 아래와 같다.
        1. 너무 많은 SQL 결과값 조회
        2. New 영역에 저장 되기에도 크다 OLD로 그냥 프로모션 된다.
        3. 아직 처리가 안 끝났다 = 레퍼런스가 살아 있다. GC대상이 되지 못한다.
        4. Full GC
      4. 해결방안은
        1. Heap 크기를 늘려서는 대부분 이 문제가 해결 되지 않는다.(늘리면 늘리는대로 더 많이 조회함)
        2. Application에서 조회 조건을 추가하여 한번에 조회 되는 데이터량을 제한하고 
        3. 꼭 필요한 대량의 조회건이 필요하다고 한다면 해당 조회에 따르는 데이터량(결과값을 받아서 저장하고 크기를 확인하고 * 동시 사용예상 인원 + 30%)
    3. Permanent 영역의 Full GC
      1. 서비스의 필요에 의하여 지속적으로 JSP를 배포하는 경우가 있다
      2. 그리고 JSP의 변경을 즉시 반영하도록 (hotdeploy) 설정한 경우 해당 class의 메타데이터가 permanent에 지속적으로 추가되며
      3. Perm 영역은 기본 컨셉이 GC를 하지 않도록 구성되어 있으므로 결국 가득 차면서 GC가 발생된다.
      4. JSP가 바뀌면 기존 JSP 정보가 unload 되면 좋겠지만 jsp가 컴파일된 class 파일은 상위 contextLoader가(WAR Context) referrer를 가지고 있기 때문에 Context의 unload(즉 이건 WAR를 내렸다가 올린다는 말이다...WAS재구동해도 되고 WAR만 내렸다 올릴 수 도 있다.)가 되지 않으면 해결이 안된다.
      5.  hotDeploy로 인한 Perm 영역의 누수는 대부분 기존 referrer가 활성 상태로 체크 되어 GC 대상이 못 되는 경우가 많아서 해결이 되지 않는다.
      6. Full GC가 일어나는 순서는 아래와 같다.
        1. JSP를 지속적으로 배포한다.
        2. JSP 안에는 많은 Method가 포함된다. 기존 정보는 그대로 있으면서 
        3. 바뀐 JSP정보가 Permanent 로딩 된다.
        4. 계속 바뀐다. Perm이 점점 줄어든다. 결국은 없다.
        5. Full GC (Unloading 이라고 한다)
    4. Applicaiton이 느린 경우 Full GC
      1. 순서는 이러하다
        1. APP가 객체를 만든다.
        2. APP가 계속 돌고 있다 = GC 대상이 아니다.
        3. APP가 바보라 처리가 끝이 않난다.
        4. 해당 APP 호출이 계속있다 = GC는 안되는 메모리에 객체가 계속 생성된다
        5. Full GC
    5. SQL이 느린 경우 Full GC
      1. 순서는 이러하다.
        1. SQL이 느리다 
        2. 1개당 5초 걸린다.  (getConnection  부터 recordSet 사용 완료까지)
        3. 해당 APP의 요청량이 50TPS 이라면 초당 50개 요청인데 DB Pool 꽉 찬다.  (Pool 갯수를 늘려봐야 필요없다. 조금 느리게 발생할 뿐)
        4. DB Pool이 꽉차면 모든 APP는 Connection을 대기한다.
        5. 모든 대기중인 APP가 메모리를 점유한다 = 아직 끝나지 않았다= GC 대상이 아니다.
        6. Full GC
  8. What's new JDK 8
    1. 2014년 Q1 JDK8이 출시되고 바뀐것이 무엇일까 해서 보았습니다.
    2. 개발환경 부분에서 새로운 코드스타일과 객체에 대한 지원등에 대한 내용이 추가되어 있습니다만.. 우리(미들웨어 제품)와 큰 관계 없는 이야기로 링크만 추가합니다.
    3. http://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html
    4. 툴 부분에서
      1. jedps(정적 의존성 검색-can understand the static dependencies of their applications and libraries) 도구 추가
        1. pkg(jar,class)의 단순한 포함 내용
        2. pkg와 연관(참조)된 다른 pkg와 해당 pkg의 내용까지 검색하여 출력
        3. pkg 의존성을 찾아볼때 사용하면 좋을 것 같음
          1. a.jar 라는 파일이 있는데 이 jar와 같이 넣어둬야 하는 다른 jar 파일을 찾을때 등
    5. HotSpot (http://docs.oracle.com/javase/8/docs/technotes/guides/vm/)
      1. AES 하드웨어 암호화 지원을 위한 함수지원....별관계 없는
      2. -Xincgc  (incremental gc) 더 이상 지원 안함
      3. -XX:MaxPermSize 설정이 사라지고 -XX:MaxMetaspaceSize  로 변경되었습니다.
      4. -XX:PermSize 설정이 사라지고 -XX:MetaspaceSize  로 변경되었습니다.
        Icon
        JDK 8 Deprecated and Removed Options
        -Xincgc
        Enables incremental garbage collection. This option was deprecated in JDK 8 with no replacement.
        -Xrunlibname
        Loads the specified debugging/profiling library. This option was superseded by the -agentlib option.
        -XX:CMSIncrementalDutyCycle=percent
        Sets the percentage of time (0 to 100) between minor collections that the concurrent collector is allowed to run. This option was deprecated in JDK 8 with no replacement, following the deprecation of the -XX:+CMSIncrementalMode option.
        -XX:CMSIncrementalDutyCycleMin=percent
        Sets the percentage of time (0 to 100) between minor collections that is the lower bound for the duty cycle when -XX:+CMSIncrementalPacing is enabled. This option was deprecated in JDK 8 with no replacement, following the deprecation of the -XX:+CMSIncrementalMode option.
        -XX:+CMSIncrementalMode
        Enables the incremental mode for the CMS collector. This option was deprecated in JDK 8 with no replacement, along with other options that start with CMSIncremental.
        -XX:CMSIncrementalOffset=percent
        Sets the percentage of time (0 to 100) by which the incremental mode duty cycle is shifted to the right within the period between minor collections. This option was deprecated in JDK 8 with no replacement, following the deprecation of the -XX:+CMSIncrementalMode option.
        -XX:+CMSIncrementalPacing
        Enables automatic adjustment of the incremental mode duty cycle based on statistics collected while the JVM is running. This option was deprecated in JDK 8 with no replacement, following the deprecation of the -XX:+CMSIncrementalMode option.
        -XX:CMSIncrementalSafetyFactor=percent
        Sets the percentage of time (0 to 100) used to add conservatism when computing the duty cycle. This option was deprecated in JDK 8 with no replacement, following the deprecation of the -XX:+CMSIncrementalMode option.
        -XX:CMSInitiatingPermOccupancyFraction=percent
        Sets the percentage of the permanent generation occupancy (0 to 100) at which to start a GC. This option was deprecated in JDK 8 with no replacement.
        -XX:MaxPermSize=size
        Sets the maximum permanent generation space size (in bytes). This option was deprecated in JDK 8, and superseded by the -XX:MaxMetaspaceSizeoption.
        -XX:PermSize=size
        Sets the space (in bytes) allocated to the permanent generation that triggers a garbage collection if it is exceeded. This option was deprecated un JDK 8, and superseded by the -XX:MetaspaceSize option.
        -XX:+UseSplitVerifier
        Enables splitting of the verification process. By default, this option was enabled in the previous releases, and verification was split into two phases: type referencing (performed by the compiler) and type checking (performed by the JVM runtime). This option was deprecated in JDK 8, and verification is now split by default without a way to disable it.
        -XX:+UseStringCache
        Enables caching of commonly allocated strings. This option was removed from JDK 8 with no replacement.
이상.