2015년 4월 27일 월요일

대통령이 아프단다

대통령이  아프단다...
그래서 이삼일 국정공백은 어쩔 수 없고...
고생하는 대통령을  위로해줘야한다며
명바기는  개드립이다...
해도해도  너무하지 않느냐
국가수반이 아프다고... ?
아마도 평소라면  기밀이라며 말도 안해줄 터
회사에서 나 하나 아프다고 회사가 쉬나
내가 회사 그만  둔다고 일이 않되면 그게  회사냐
그게 조직이냐
특히나
대통령하나  아프다고 일도 못하는  비서진과  그 조직은 존재 가치가 있기는 한것이냐
막말로 김정은 세끼가  오늘  밀고 내려와도
아프니 내일  보자고  할것이냐
하긴  그 큰일이 있고도 7시간 잠적에
한참있다 나타나서 구명정 드립이나 치던 인간이니
뭔 짓을 할  지 알 수가 없지
약  처먹고 내일부터 출근해라!
회사다니는놈년들 다 그러고 산다 
씨발

2015년 3월 18일 수요일

JAVA8 Permanent 영역은 어디로 가는가

JDK 8이 발표 된지도 좀 되었다.

얼마전에 그 여파로 GC 내용도 좀 정리해봤는데
(http://yckwon2nd.blogspot.kr/2014/04/garbage-collection.html)

포스팅 말미에 Java8 부터 Permanent 영역에 대한 설정

-XX:PermSize=350m / 기동시 Perm사이즈
-XX:MaxPermSize=400m /최대사이즈

두 가지가 사라지고

-XX:MaxMetaspaceSize=
-XX:MetaspaceSize=

가 등장했다.

java 개발자들이 바보가 아니고서야 쓸데 없이 이름을 왜 바꾸었을까 싶었는데

보다 보니 이래저래 Perm 에 대한 전략이 수정된것 같아서 정리해 본다.



java7 까지의 permanent(영속적, 이하 perm) 영역에는  다음과 같은 정보들이 저장되었다.

1. Class 의 Meta정보 (pkg path 정보라고 보면 됨, text 정보)
2. Method의  Meta 정보
3. Static Object
4. 상수화된 String Object
5. Class와 관련된 배열 객체 Meta 정보
6. JVM 내부적인 객체들과 최적화컴파일러(JIT)의 최적화 정보

-Methods of a class (including the bytecodes)
-Names of the classes (in the form of an object that points to a string also in the permanent generation)
-Constant pool information (data read from the class file, see chapter 4 of the JVM specification for all the details).
-Object arrays and type arrays associated with a class (e.g., an object array containing references to methods).
-Internal objects created by the JVM (java/lang/Object or java/lang/exception for instance)
-Information used for optimization by the compilers (JITs)

해깔려들 하시는게 static이 어떻게 저장되느냐 인데
변수의 경우 그냥 값 자체가 perm에 들어갑니다. 만약 Object 라면 Object 자체가 저장되지요
static int i = 1; //the value 1 is stored in the permgen section

요즘의 거의 이런일은 없지만 개발자가 별생각없이 Collection Object를 Static 으로 선언하고 값을 계속 추가하다보면 Perm 이 가득차서 OOM이 발생하기도 했지요...


Class의 경우 JVM기동시 사용되는 모든 Class와 Method Meta 정보가 Perm에 저장되고
Code 상에 아래와 같이 static으로 정의되면 해당 메타 정보도 Perm에 들어가게 되지요
static Object o = new SomeObject(); //the reference(pointer/memory address) is stored in the permgen section, the object itself is not.


결국 Perm에 저장되는 위 여섯가지 중에서 Perm 부족을 일으키는 상대는
1. Static Object의 잘못된 사용 (개발자가 원인)
2. Class, Method Meta data의 증가   (hotDeploy가 원인)

두 가지가 가장 큰 문제였고 Perm 구조를 가지는 Sun JVM  계열 (Open JDK, HP JDK 등)에서는 Perm 누수는 운영에 큰 불편함을 감수하도록 했습니다.

그래서 결국 결정은 이겁니다.

"Permanent 영역을 없에 버리자!!!"

특히나  Oracle의 경우

BEA 라는 회사(Weblogic을 개발했고 자체 JVM 으로 JRockit 을 개발한)를 인수해서 JRockit 을 가지고 있다가 Sun의 JAVA 팀을 먹은 이후로

JRockit의 지향점 (대용량 Heap 지원을 위한 구조, Perm 없음, Survive 영역없음, NEW/OLD 만 있음)을 Java 8에 적용하게 되었고 Perm 영역이라는 개념을 제거해 버립니다.
G1 알고리즘도 지향점은 동일 합니다.

그럼....

거기 저장되던 것들은 어떻게 되는데????
(아래에서 Native 는 Metaspace를 의미함)

1. Class 의 Meta정보 (pkg path 정보라고 보면 됨, text 정보)  --> Native 영역으로 이동
2. Method의  Meta 정보--> Native 영역으로 이동
3. Static Object --> Heap 영역으로 이동
4. 상수화된 String Obejct  --> Heap 영역으로 이동
5. 클레스와 관련된 배열 객체 Meta 정보  --> ???? (아티클 봐서는 모르겠는데 Native로 간듯)
6. JVM 내부적인 객체들과 최적화컴파일러(JIT)의 최적화 정보 --> ???   (아티클 봐서는 모르겠는데 Native로 간듯)


정리하면 java7  까지는
new / survive / old / perm /  native  로 구분했다면
java 8에서는
new / survive / old / metaspace 로 아키텍쳐가 변경되었고

기존의 perm에 저장되어 문제를 유발하던
static obect는 heap으로 옮겨서 GC 대상이 최대한 될 수 있도록 하고 (Final 로 해놓으면 나두 모름)

기타 정말 수정이 될 일 없어보는 정보는
Native(Metaspace) 로 몰아넣고 사이즈는 자동적으로 조정되도록 개선 되었다고 정리하면 되겠습니다.

.....

여기서 개인적으로 두려운것은...

사실 최근에는 Framework의 대중적인 사용 및 개발자 수준향상(?)으로 미친 Static 사용문제는 거의 발생하지 않고 있고
Perm의 가장 큰 문제로 JSP를 지속적으로 HotDeploy 하는 회사에서 발생하는 Perm 누수문제 인데...
(Production 에서 Class 까지 Hotdeploy 하지는 않겠찌?????)

이게... Perm을 Max를 정해놓고 할때는 Perm이 꽉 차면 OOM이 발생
“java.lang.OutOfMemoryError: PermGen space” error 

하고 장애로 확인되면 설명을 해주고 대응방안으로

1. JSP Hot Deploy 하지 마라  (서비스 요건상 해야 되면 어쩔 수 없다면...)

2. Perm을 적절히 늘리자
어쩔 수 없이 JSP hostdeploy를 해야 한다면 늘어나는 추이를 분석해서 최소한 3일 이상 버티도록 = (금요일퇴근, 토,일 은 버텨야 하지 않겠는가) 설정을 늘려준다

3. 정기적으로 재구동
요건상 누수를 안고 가야 하므로 배포 주기나 일정기간 마다 통제된 환경에서 재구동 해주는 운영상의 방법 사용

을 설명해준다.
(Perm 을 GC할 수 있도록 해달라고 땡깡 부리는 사람들이 있는데....제기랄....난 모른다. Context 개념도 없는 사람에게 Perm의 Meta 정보가 쌓이는 메커니즘을 설명 할 방법이 없다)


그런데 이제는 이 문제를 Native 영역으로 옮겨버린단다...
거기다 -XX:MaxMetaspaceSize 설정을 하지 않으면 JVM이 알아서 사이즈를 조정한다고 하는데....

알다시피 JVM 장애시 Native Memory 영역의 누수는 분석이 불가능하다 (dump를 생성해도 Native 영역 정보는 생성 되지 않는다)

이렇게 되면 새로운 어려움이 생기는데...

Core  파일을 생성해서 gdb로 누수 현상에 대해서 분석해야 하는...????

난 모르겠다...  이건 내 수준을 벗어나는 부분이라 어찌될지...
(어짜피 Perm도 분석대상이 아니였으니 그다지 문제가 되지 않을 지도...)


여하간  아래 4개의 값을 어떻게 잡고 갈지가 아직 오리 무중이다.

일단 기본적으로 Perm에 적용하던 기본값 (min 256m, max 512m)으로 잡고 GC정보를 보면서 경험치를 늘려 가는 방법뿐일 듯

  • -XX:MetaspaceSize=<NNN> where <NNN> is the initial amount of space(the initial high-water-mark) allocated for class metadata (in bytes) that may induce a garbage collection to unload classes. The amount is approximate. After the high-water-mark is first reached, the next high-water-mark is managed by the garbage collector
  • -XX:MaxMetaspaceSize=<NNN> where <NNN> is the maximum amount of space to be allocated for class metadata (in bytes). This flag can be used to limit the amount of space allocated for class metadata. This value is approximate. By default there is no limit set.
  • -XX:MinMetaspaceFreeRatio=<NNN> where <NNN> is the minimum percentage of class metadata capacity free after a GC to avoid an increase in the amount of space (high-water-mark) allocated for class metadata that will induce a garbage collection.
  • -XX:MaxMetaspaceFreeRatio=<NNN> where <NNN> is the maximum percentage of class metadata capacity free after a GC to avoid a reduction in the amount of space (high-water-mark) allocated for class metadata that will induce a garbage collection.


참고
https://blogs.oracle.com/poonam/entry/about_g1_garbage_collector_permanent
http://java.dzone.com/articles/java-8-permgen-metaspace
http://www.infoq.com/articles/Java-PERMGEN-Removed




common DBCP 사용시 Thread lock 문제 - CASE2

또다른 CASE는 아래 링크 클릭하면 볼 수 있다. (두개 다 동일한 문제라고 보면 됨)
http://yckwon2nd.blogspot.kr/2014/04/common-dbcp-thread-lock.html

1. 증상
WAS의 Thread가 모두 소진되어 서비스가 되지 않거나 그에 의한 여파(처리가 안되면 모든 객체가 대기 되므로)로 Full GC가 발생하여 서비스 지연 또는 안되는 현상

2. 원인
Apache org에서 제공되는 Common DBCP module은 Thread 안정성을 위해서 Single Thread로 동작합니다.
간략하게 설명하면
Connection 하나를 APP가 받아서 사용할 때 Pool 자체에 대한 접근을 차단 하게되며
APP가 느릴 경우 다른 Connection을 요구하는 모든 APP가 정지 되는현상 (Thrad Lock wait)이 발생합니다.
보내준 내용을 보면 1Thread에 의해 670개의 요청이 대기 상태가 됨을 알 수 있음
<0x00000000c00c6070> (a org.apache.commons.dbcp.AbandonedObjectPool):    0 Thread(s) sleeping, 670 Thread(s) waiting, 1 Thread(s) locking

3. 해결
Tomcat의 경우 Common DBCP가 아닌 tomcat에 포함된 Tomcat DBCP를 사용하거나
Jboss, Weblogic 등의 엔터프라이즈 WAS를 사용할 경우 해당 제품에서 제공되는 DB Pool을 사용하여 해결 가능함

{
PC에서 똑딱거리면서 하겠다고 DBCP로 개발하는건 좋은데 
제발 Production환경으로 가면서 WAS Pool안쓰고 버티는 똥배짱좀 부리지 말자 
Framework 쓰자나... conf 파일 하나 바꿔서 JNDI  Lookup만 맞춰주면 되는데
대체  왜그래....
}

4. 설명
아래 thread를 보면 APP가 Altibase DB로 쿼리 수행 후 시간이 지연되어 대기 중인 상태임
이때 볼드 처리된 라인을 보면 DB Connection Pool에 대하여 Lock을 획득했는데 처리가 늦어지면서 해당 객체를 돌려주지 못함
(common DBCP는 single thread로 동작하기 때문에 이렇게 됨)
일반적으로 Common DBCP를 사용하면
- locked <0x00000007957d27d8> (a org.apache.commons.dbcp.BasicDataSource)
와 같이 BasciDatasource가 lock되나 아래에 보면
- locked <0x00000000c00c6070> (a org.apache.commons.dbcp.AbandonedObjectPool)
으로 이름이 다름

이유는 DBCP에서 Connection 의 비정상 회수 시 일정시간 후에 Connection을 폐기하도록 하는 Abandone설정을 활성화하면
다른 Class가 사용되므로 Thread 정보에서 다르게 보일 수 있으나 원인과 증상은 동일함

Thread-1184" daemon prio=10 tid=0x00007fa2b8010000 nid=0x2112 runnable [0x00007fa24d2d0000]
   java.lang.Thread.State: RUNNABLE
        at sun.nio.ch.FileDispatcherImpl.read0(Native Method)
        at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
        at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:218)
        at sun.nio.ch.IOUtil.read(IOUtil.java:186)
        at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:359)
        - locked <0x00000000c0659998> (a java.lang.Object)
        at Altibase.jdbc.driver.cmnTCP.recv(cmnTCP.java:276)
        at Altibase.jdbc.driver.cmp.flush(cmp.java:294)
        at Altibase.jdbc.driver.cmp.writeDirectExecuteAndFetchReq(cmp.java:1227)
        - locked <0x00000000c0619b78> (a Altibase.jdbc.driver.cmp)
        at Altibase.jdbc.driver.ABConnection.writeDirectExecuteFetchReq(ABConnection.java:624)
        at Altibase.jdbc.driver.ABStatement.executeQuery(ABStatement.java:321)
        - locked <0x00000000ce0fe9b8> (a Altibase.jdbc.driver.ABStatement)
        at org.apache.commons.dbcp.DelegatingStatement.executeQuery(DelegatingStatement.java:208)
        at org.apache.commons.dbcp.DelegatingStatement.executeQuery(DelegatingStatement.java:208)
        at org.apache.commons.dbcp.PoolableConnectionFactory.validateConnection(PoolableConnectionFactory.java:332)
        at org.apache.commons.dbcp.PoolableConnectionFactory.validateObject(PoolableConnectionFactory.java:312)
        at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:855)
        - locked <0x00000000c00c6070> (a org.apache.commons.dbcp.AbandonedObjectPool)
        at
org.apache.commons.dbcp.AbandonedObjectPool.borrowObject(AbandonedObjectPool.java:84)
        at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:96)
        at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:880)
        at devonframework.persistent.connection.LJndiDataSource.if(Unknown Source)
...이하 생략


PS. 피해자들 과 잘못된 접근시 삽질 Sequence

{
아래같은 Thread가  670개 대기중 --> 
제니퍼에서 보면 Active Eq에 670개 쌓여서 뻘겋게 보임 --> 
670개 요청이 메모리를 잡아먹고 버티니 WAS Heap이 남아도는 사이트가 아니라면 Full GC가 지속적으로 발생 --> 
Full GC 정보 보고 Heap memory 부족한거 아니냐고 개드립시작함....  --> 
(기타 : WAS Thread 가 모자라다, DB Connection이 부족하다 등의 개드립도 있음)
메모리 덤프떠서 메모리 분석 한다 -->
메모리에 보면 졸라 다양한 APP들이 이상한 객체를 만들고 있고 DB Connection 관련 Object가 엄청 많다(메모리 내용으로는 뭐가 문제인지 알 수 가 없다.)  -->
DB Connection 또는 Pool이 버그라고 개드립 -->
제품 버그 찾는다고 구글링 십년....  -->
잘못하면 삼천포에 빠져죽는다...

약은 약사에게 병은 의사에게....
}

"Thread-1730" daemon prio=10 tid=0x00007fa2b0103800 nid=0xc29 waiting for monitor entry [0x00007fa23c1c1000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at org.apache.commons.pool.impl.GenericObjectPool.getNumIdle(GenericObjectPool.java:911)
        - waiting to lock <0x00000000c00c6070> (a org.apache.commons.dbcp.AbandonedObjectPool)
        at org.apache.commons.dbcp.AbandonedObjectPool.borrowObject(AbandonedObjectPool.java:78)
        at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:96)
        at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:880)
        at devonframework.persistent.connection.LJndiDataSource.if(Unknown Source)
        at devonframework.persistent.connection.LDataSourcePool.getJNDIConnection(Unknown Source)
        at devonframework.persistent.connection.LDataSourcePool.getConnection(Unknown Source)
        at devonframework.persistent.dao.LConnectionManager.getConnection(Unknown Source)
        at devonframework.business.transaction.LConnectionMapper.getConnection(Unknown Source)
        at devonframework.persistent.autodao.LAutoDao.getConnection(Unknown Source)
        at devonframework.persistent.autodao.LCommonDao.executeQueryForSingle(Unknown Source)
        at devon.batch.core.persistence.BatchDao$JobInfo.retrieveSingleJobGroup(Unknown Source)
        at devon.batch.core.persistence.BatchDao$JobInfo.retrieveSingleJobGroup(Unknown Source)
        at devon.batch.core.persistence.BatchDao$JobInfo.retrieveJobGroupDescriptor(Unknown Source)
        at devon.batch.scheduler.trigger.JobGroupExecOrder.beforeSend(JobGroupExecOrder.java:106)
        at devon.batch.scheduler.trigger.AbstractTransferOrder.send(AbstractTransferOrder.java:93)
        at devon.batch.scheduler.manager.SchedulerManager.sendJobGroupExecOrder(SchedulerManager.java:179)
        at devon.batch.scheduler.manager.LSchedulerItem.doIt(LSchedulerItem.java:70)
        at devonframework.service.scheduler.job.LJob$1.run(Unknown Source)



2015년 3월 1일 일요일

유리창 밖의 세상...


세상을

창 안에 앉아 느긋하게 바라본다는것은

여유일까 방관일까..



연일 터지는 사고와 사건

대통령의 정통성, 대의명분, 국정원의 비 윤리, 대기업의 횡포, 미친 갑들의 발악, 이상한 총리, 노무현음해, 전단지살포, 서울의 시위...

프레임안에 잡히기 싫어서 밖에서 바라본다는 시각은

결국 나를 안으로 가두고 있는것이 아닐까

누군가는 게으르다, 해야할 의무를 방임하고 있다, 책임감이 없다고 하겠고

사실 맞는 말이라 반박도 못한다.

열심히 달려가는 사람들을 숨어서 빼꼼~ 한 눈으로 바라보는 나는

비겁함을 변명하고

게으름을 속이며

결국 나 자신을 가두고 살아가고 있다.

이 안락한 유리창의 문을 열면 쏟아져들어올 비바람을 감당하고 싶지 않다.

내가 그 상황을 감당하기 싫고

나에게 의존하는 사람들에게 까지 그 짐을 씌우기 싫다는 변명으로

이렇게 살아가고 있다.


세상이 상식적으로 돌아가는대 꼭 사람의  피가 필요한가

"자유라는 말에는 피 냄새가 난다" 라고 누군가 했었더랬는데

비릿한 내음이 싸늘한 봄 바람을 타고 흐른다


2015년 2월 16일 월요일

자유로부터 자유롭기 위해...


Unless a man has the talents to make something if himself, 
freedom is an irksome burden...
인간이 스스로 어떤 것을 만들어 낼 수 있는 재능을 갖고 있지 못할 경우, 

자유는 성가신 부담이 된다...

-에릭 호퍼, 맹신자들, 1951-

책 내용은 나치를 비교해서 국수주의, 인종주의에 비교해서 이야기 하지만

사실 많은 곳에 통용된다.

사회에서 자신의 위치가 만족 스럽지 못 할 때 사회현상과 대중운동에 목을 매어 그곳에서 자기정체성(identity)을 찾고자 노력하는 모습을 볼 수 있다

일간베스트, 오늘의 유머, 각종 게시판, 개인들로는 변모씨 같은 사람들

검사조직같아도 노대통령 시절 "평검사와의 대화" 를 TV로 보면서 배웠다는 인종들이 질문 수준이 왜 저런가...생각했을때 개개인의 문제는 아니라고 생각했었다

단지 그들은 공부를 잘 했지 창의적 재능은 없거나 없어졌거나 현실에 익숙해진것이고 덜컥 주어진 자유는 성가시거나 부담됨을 넘어서 공포로 다가왔지 않을까 생각해본다.

여행중 숙소에서 처음만난 학생들과 한 잔 술이 돌고 나면 자신의 위치에 대한 어려움, 극복 불가능할 것 같은 사회에 대한 불만들이 터져나온다

여행을 하면서 그런 것 들이 찾아지지는 않는다.
보통 힐링 이라고 하는 자기위안은 가능하지만...

무엇이든 해 볼 수 있는 20대의 자유로움은 사회적, 경제적 환경으로 탄압받는다
쓸모 없어 보이는 이 자유(젋음)를 대체 어떻게 해야 하는가
극복할 것인가, 익숙해 질 것인가 이도 저도 아니면 애써 지우려고 노력할 것인가

"그래서 어쩌라고!!!?"  하며 분노하는 사람들도 있다

나도 이야기 한다 "그래서 어쩌라고?"  나이 좀 처먹었다고 다 알고 돈이 그냥 벌어지나?  나도 잘 모른다.

다만 그때 하지 말아야할...또는 할 수 없는 이유
십이만사천이백이십한가지를 주절 거리며
회사에서 월급이나 받아먹던 그 시절이 지금은 아까워 이야기 할 뿐이다.
(이런 인간들을 "형"이라 쓰고 "꼰대"라고 부른다.)

회사에서 상급자가 자유로운 분위기 안에서 톡톡튀는 부서를 만들고 싶어서 이런 저런 처방을 해보지만 서로가 서로를 안다.... 잘 안된다.

위가 문제든 아래가 문제이든 보장해 줄 수 있는 자유와 요구하는 자유에 대한 의미가 서로 맞지 않으니 진행 되기 힘든건 당연하지 않겠는가?


나는 스스로 판단할때 재능은 없다

약간의 잔머리와 어려서 부터 잘 훈련된(?) 눈치가 재능이라면 재능이겠다

그럭저럭 운도 따라 80년대 학번의 이념을 패스(뭔지도 모른다)하고

94학번의 행복(IMF부터 온갖 사고와 미친 정권까지)을 경험하면서

날이 갈 수록 젊은 친구들 등쳐먹는 스킬은 향상되고 있는중이다.



나에게 주어진 자유....

먼청한 20대를 보냈지만 최근들어 내 자유라고 생각하는것은

최대한 빼앗기지 않기 위해 30대 중반 부터 노력 하고 있다

집도없고 차도 10년이 넘은것을 끌고 직접 수리를 해 가면서 돈을 아끼고

전세집은 80% 대출로 땜빵을 하면서

최대한 회사를 쿨 하게 때려칠 수 있는 수준을 유지하기 위해 노력한다

집을 사거나....차를 사거나...

웬지 나는 그렇게 되면 내 영혼을 팔아버리는 느낌일 것 같아서 망설인다.

허핑턴포스트의 글을 보다가 쓸대 없는 생각이 들었다.

결국 난 보라색 소가 되고 싶지 않다는 말을 하고 싶었다.

http://www.huffingtonpost.kr/mintae-kim/story_b_6689564.html?utm_hp_ref=tw