java6 / java7을 쓰면 안되는 이유

개요

kth 내부 서비스 또는 kt 용역 서비스 중 상당수는 호환성이라는 명목 하에 java6 / java7 로 개발/유지보수하는 프로젝트들이 많이 있습니다.

물론 java6 / java7 로 개발한다고 잘 돌던 서비스가 당장 멈추거나 하는 일은 없을겁니다만

서비스 품질은 다음과 같은 측면에서 경쟁사에 뒤쳐진다고 보시면 됩니다.

1) 보안

2) 가용성

3) 호환성

4) 기술 역량

 

보안

oracle java6 의 End of Public Update 는 2013년 2월, java7은 2015년 4월에 종료되었습니다.

무슨 말인고 하면, 누군가가 java의 새로운 보안 결함을 발견한다면 java6 / java7 로 개발된 서비스는 더이상 보안 업데이트가 없다는 뜻입니다.

다음 사이트(oracle jre 링크)를 참고하시면, 지금까지 알려진 보안 결함 리스트를 보실 수 있는데요.

java6 은 대략 200여 개, java7은 대략 100여 개 정도의 보안 결함 업데이트가 없었습니다.

물론 네트워크 방화벽이라던지 정기 OS 패치 등으로 이중 삼중 보안 장치를 마련해 두고 있지만

때때로 이러한 모든 보안 장치를 무력화할 만한 대형 결함이 발견되기도 하는데, 그럴 때 동작하는 서비스가 java6 / java7 기반이라면 대책이 없습니다.

 

가용성

Interned String 문제

java6을 쓰면서 서비스에 특별한 장애 요소도 없는데 이상하게 보름에서 한달 정도 지나면 서비스가 내려가는 경험이 있으셨다면 십중팔구는 Interned String 문제입니다.

java6 과 java7/8 은 String pool 저장소가 근본적으로 다릅니다.

java6 이하 버전의 경우 신규 생성된 String은 PermGen 에 위치하며, 동일한 String의 경우 pooling 합니다.

 

PermGen 사이즈는 고정이므로(java8은 좀 다릅니다만),

1) 100bytes 사이즈의 서로 다른 값을 가진 String(e.g. 임시 발급 key, UUID 등등등)이

2) 100Mbytes 사이즈 PermGen

에 채울 수 있는 최대값은 100 * 1000 * 1000 = 100M 이므로

최대 100만 개의 String 이상 String이 신규로 생성되면 PermGen 영역이 가득차게 되고, 아래와 같은 익셉션과 함께 프로그램이 제대로 동작하지 않을겁니다.

exception

java.lang.OutOfMemoryError: PermGen space

 

java7부터는 String.intern() 메소드를 명시적으로 호출하지 않는 한, PermGen 영역에 String을 Poolling 하지 않습니다.

단지 jvm 버전을 올리는 것 만으로도 가용성 및 장애 요소를 한 가지 줄일 수 있습니다.

 

Fixed PermGen size 문제

허나, java7 이하 버전에서 여전히 PermGen size 는 고정이라는 문제가 존재합니다.

대개의 경우 String이 PermGen space를 잡아먹는 주된 요인이겠지만,

본래 PermGen의 주된 목적은 어플리케이션에서 사용되는(=load한) class 정보의 저장입니다.

java7에서 PermGen 사이즈를 적당히 크게 잡아줄 경우, PermGen이 고갈되는 경우는 왠만해선 발생하지 않겠습니다만

다음과 같은 시나리오에서는 PermGen이 고갈됩니다.

1) classloader 가 동적으로 신규 class를 지속적으로 load

2) 프로그램 사이즈가 정말 커서 많은 class가 필요

PermGen 사이즈는 고정이라는 원죄가 있기 때문에 jvm 옵션으로 PermGen 사이즈를 조정하더라도 항상 문제가 발생할 여지가 있습니다.

java8 에서는 PermGen 이 사라진 대신 해당 역할을 metaspace가 대체합니다.

차이점은 다음과 같습니다.

1) metaspace의 메모리 영역은 native 입니다.

2) memory가 부족하면 동적으로 할당 가능합니다.

 

cf) PermGen?

2015년도 신입사원 교육자료 중 2일차, dependency hell 작성할 때 그려둔 native application 의 memory 모델입니다.

물론 java와 디테일에는 차이가 있지만, Heap / Stack / Data / Code 섹션에 대한 포괄적인 개념은

java나 native나 혹은 이후 여러분들이 접하게 될 어떤 언어라도 대동소이합니다. 하나만 제대로 알고 있으면 되겠죠?

위 메모리 모델은 내가 짠 프로그램이 실제로 어떻게 작동하는지 알고 싶은 개발자라면 반드시 대가리헤또에 필수 탑재되어 있어야 합니다.

메모리 모델

stack : 프로그램의 흐름(=function call), local 변수 등을 저장

heap : 프로그램 내에서 동적으로 할당한 데이더를 저장

data : 전역변수를 저장

code : 프로그램 메타정보(=function meta) 등을 저장

각 메모리 영역별로 역할이 주어져 있지만, 가장 중요한 핵심은

1) 어플리케이션 시작 전에 사이즈를 결정할 수 있는 영역과(code / data)

2) 어플리케이션 실행 도중에 사이즈가 변경되는 영역(stack / heap)

이 분리되어 있다는 점입니다.

 

디테일은 다르지만 자바 메모리모델도 어플리케이션 시작 전에 사이즈를 결정할 수 있는 영역과 그렇지 않은 영역으로 구분됩니다.

다만, PermGen 영역의 정체성이 모호한데요.

본래 의도대로라면 PermGen 영역은 런타임에 증가되어선 안되는 영역입니다만 몇 가지 경우에 예외를 두었고

그 예외 때문에 자바 어플리케이션은 지금까지 고통받아 왔습니다.

 

java memory model

아래 그림은 어떤 존잘님께서 그린 java 메모리 모델입니다. (출처 : http://javarevisited.blogspot.com/2011/04/garbage-collection-in-java.html)

1) java7 이하 메모리 모델

2) java8 메모리 모델

 

Compressed Ordinary Object Pointer default enabled

jvm에는 Ordinary Object Pointer, 줄여서 OOP(객체지향 프로그래밍과 혼동 금지!, 보통 hotspot oop 라고 부릅니다.)에 대한 압축을 enable / disable 하는 옵션이 있습니다.

hotspot oop 는 기회가 된다면 나중에 따로 다루겠지만, 간단히 요약하면

데이터의 주소 정보를 효율적으로 쓰기 위한 꼼수

라고 보시면 됩니다.

compressed oop 옵션은 java7부터 default enabled 입니다.

만일 64bit 플랫폼 환경에서 java6을 쓰신다면 어플리케이션 실행 시 이 옵션을 enable 하여야 메모리를 좀 더 효율적으로 쓸 수 있습니다.

 

호환성

신규 버전의 java 에는 보안 / 기능 / 성능 / 정책 위배 등 여러가지 사유로 과거 버전중 deprecated 되는 API들이 발생합니다.

java6 또는 java7에서 java8로 올리지 못하는 여러 가지 이유중에는 deprecated API에 대한 호환성 문제가 꽤 비중이 높은 편인데요.

당장 deprecated API를 수정할 여력 없이 운영만 하는 서비스는 현실적으로 java 버전을 높이기 어려운 것이 사실입니다.

허나 신규 프로젝트에서 deprecated API 를 사용하거나, 해당 API를 사용한 library 를 쓰는 일은 없어야 합니다.

이미 배포한 API를 없앤다는 건 정말 어려운 일입니다. 그래서 보통은 왠만하면 해당 API를 없애지 않고 구현을 변경하거나 다른 더 좋은 구현을 만들어내 해당 API 사용률을 낮추도록 유도합니다.

그럼에도 불구하고 API를 없애는 결정을 했다는건 정말 그 API를 쓰지 말아야 할 중대한 이유가 있기 때문에 없애는 겁니다.(쓰지 말라면 쓰지 마루요)

아래 링크는 oracle에서 제공하는 java7 / java8 의 deprecated 된 api 리스트 및 java8 호환성 guide 문서입니다.

 

기술역량

modern language 열풍이 분지 올해로 10년 쯤 지났습니다.

무수히 많은 modern language가 생겨나기도 하였지만, 기존 language들이 modern language 의 철학을 담는 경우도 종종 있었습니다.

java는 다른 언어에 비해 modern language의 주요 개념, 기능 등을 담아내는 시점이 매우 늦은 편입니다.

심지어 java보다 30년은 오래된 c++이 오히려 java보다 100만배는 modern 합니다.

 

현대의 소프트웨어 개발 환경은 몇 가지 특징이 있습니다.

1) 과거에 비해 어플리케이션의 규모 / 복잡도가 기하급수적으로 높아졌습니다.

2) 난립하는 하드웨어에 효율적으로 대응하기 위한 수단이 필요합니다.

3) 더이상 수직적인 하드웨어 성능은 높아지지 않습니다. 허나 처리해야 할 데이터의 양은 엄청나게 늘었습니다.

 

과거, 구조적 프로그래밍의 한계를 객체지향 프로그래밍으로 극복한 시절이 있었습니다.

현재는 객체지향 프로그래밍의 한계에 다다랐다고 보아도 과언이 아닙니다.

우리가 쓰는 대부분의 CPU 는 멀티코어 프로세서로 설계되었습니다.

허나 객체지향 언어로 멀티코어 성능을 온전히 내는 어플리케이션을 만들기는 매우 어렵습니다. 디버깅은 100만배 더 어렵습니다.

 

과거, 비동기 네트워킹은 시스템 프로그래머만의 전유물이던 시절이 있었습니다.

현재는 클라이언트 프로그래머도 비동기 처리의 동작 원리를 반드시 이해하여야 합니다.

비동기 처리는 반드시 OS의 지원 / 프로그램 언어의 지원이 필요합니다.

 

modern language 에는 다음과 같은 몇 가지 공통적인 특징이 있습니다.

1) 함수형 프로그래밍 패러다임 수용

2) 불필요한 코드 노가다 지양

3) 강력한 type 추론

4) lazy execution 을 구현하기 위한 효율적인 수단 제공

5) REPL(Read – Evelauation – Print – Loop) 또는 준하는 어플리케이션 확인 수단 제공

6) thread local stack 에 대한 디버깅 수단 제공

 

java8 도 많이 늦은 편인데 이러한 소프트웨어 개발 환경의 변화를 java6 / java7 로 대응한다? 쉽지 않습니다.

지금으로부터 약 40여 년 전, 프로그래밍 세계를 평정하던 cobol이라는 언어가 있었습니다.

당시 두터운 사용자/커뮤니티층을 형성하던 cobol 개발자들은 굳이 OOP 를 학습할 필요성을 느끼지 못하였습니다.

c++이 출시되고 채 10년이 못되어 cobol 어플리케이션은 씨가 말랐고, OOP는 대세가 되었습니다.

요즘의 java를 보면서 과거 cobol의 역사가 자꾸 오버랩되는 것은 우연의 일치일까요?

 

요약

java8 써라. 두번 써라.

java6 / java7을 쓰면 안되는 이유”에 대한 1개의 생각

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중