반응형

최근 작업중 unix date를 파싱해야는 경우가 있어서 아무렇지 않게


String unixDate = "1498906817.357"

String[] parseDate = unixDate.split(".");

String parsedDate = Long.parseLong(parseDate[0]);


다음과 같이 썼는데 파싱된 데이터에 값이 안들어있다는...


확인해보니 split의 인자로 들어가는  .(dot)이 정규식이기 때문이었다. 

정규식에서는 .(dot)은 무작위의 한글자를 의미하므로 모든 문자가 토큰이 되기 때문에 배열에 남는게 없게 되는 것이다.

그렇기 때문에 이를 피하기 위해서는 이스케이프(\\)를 문자앞에 써줘야 한다.



String unixDate = "1498906817.357"

String[] parseDate = unixDate.split("\\.");

String parsedDate = Long.parseLong(parseDate[0]);


뭔가 split 메서드를 사용해 parsing을 했는데 값이 정상적으로 나오지 않는다면 정규식을 의심하자.



[ 참고 ]

there are 12 characters with special meanings: the backslash \, the caret ^, the dollar sign $, the period or dot ., the vertical bar or pipe symbol |, the question mark ?, the asterisk or star *, the plus sign +, the opening parenthesis (, the closing parenthesis ), and the opening square bracket [, the opening curly brace {, These special characters are often called "metacharacters".

반응형
반응형


 안녕하세요. 오늘은 프로세스와 스레드에 대해서 알아보도록 하겠습니다. 많은 분들이 실제로 프로세스와 스레드를 알고 계시면서도 막상 물어보면 대답하기 막막해하시는 경우도 많이 있고 저도 실제로 프로세스&스레드에 대해서 명확히 설명하기 힘들어 했던 경험이 있어 이번 기회에 한 번 간단히 개념적인 부분에 대해서 정리하고 넘어가려고 합니다. 이제 막 2년차에 접어드는 현업 개발자지만 요즘 느끼는 것은 새로운 기술들에 관심을 가지는 것도 중요하지만 개발을 함에 필요한 '기본적인 내용들과 지식을 좀 더 단단히 쌓아야 겠다'는 생각이 많이 들곤 합니다. 포스팅 시작하도록 하겠습니다.



[ PROCESS ]

 먼저 프로세스란 간단히 설명해서 실행중인 프로그램에 대한 인스턴스를 프로세스라고 합니다. 실제로 프로세스가 생성되게 되면 해당 프로세스는 운영체제로부터 주소공간, 파일, 메모리 등을 할당받게 됩니다. 그리고 메모리 공간은 CODE, DATA, HEAP, STACK영역으로 나뉘어지게 됩니다. 실제로 프로세스가 처리해야 될 일을 각각의 메모리 영역들 위에서 처리하게 되게 됩니다.

프로세스는 다음과 같은 독립된 메모리공간을 프로세스별로 가지게됩니다. (스레드 설명할 때 설명하겠지만 스레드는 STACK 부분만 독립적으로 가지게 됩니다.) 그렇기 때문에 특정 PROCESS가 다른 PROCESS 메모리에 직접 접근하기 힘듭니다.


[ THREAD ]

 스레드란 프로세스 안에서 동작되는 여러 실행의 흐름이라고 보시면 됩니다. 간단히 말해서 프로세스 내부에서 실제로 일을 하는 녀석들을 스레드라고 합니다. 우리 몸으로 치면 몸은 프로세스 손,발은 스레드 정도가 되지 않을까요?(단순한 제 생각) 기본적으로 하나의 프로세스가 생성되면 하나의 스레드가 같이 생성이됩니다. 이를 메인 스레드라고 부르며, 스레드를 추가로 생성하지 않는 한 모든 프로그램 코드는 메인 스레드에서 실행이 된다고 생각하시면 됩니다. 또한 프로세스는 메인 스레드 외에도 여러개의 스레드를 가질 수 있는데요. 이를 멀티스레드라고 합니다.

 스레드의 경우에도 프로세스와 같이 메모리 공간을 할당 받게 되는데요. 프로세스가 각각의 독립적인 메모리 공간을 할당받는 반면에 스레드의 경우는 Stack영역만을 독립적으로 할당 받게 됩니다. 실제로 Code, Data, Heap영역은 프로세스의 공간을 공유받아 사용하게 됩니다. 이렇듯 프로세스 내에서 생겨나는 모든 스레드의 경우 Stack이외의 영역은 프로세스의 영역을 공유받아 사용하게 되고 이러한 이유로 인해 스레드간 Context Switching(아래에 간단히 설명)이 발생했을 경우 Stack 영역의 데이터들만 switching되면 되므로 프로세스 스위칭보다 훨씬 빠르게 진행이 됩니다. 스레드의 장점으로는 시스템의 Throughput(처리량)이 향상 되며, 자원 소모가 줄어들고 스레드간의 스위칭 시간이 줄어들면서 일을 처리할 때 응답 시간이 단축되는 점이 있습니다. 반면에 여러 개의 스레드를 사용할 때는 프로세스가 가지고 있는 메모리 영역의 자원 공유의 문제가 발생할 수 있고 디버깅이 힘들다는 점이 있습니다. 마지막으로 프로세스의 메모리 영역(Data, heap)을 공유함으로써 전역 변수와 동적 할당 딘 메모리 공간을 공유하게 되고 이를 통해 쓰레드간 통신이 쉽게 가능하게 됩니다.


[ THREAD가 스택을 독립적으로 할당하는 이유 ]

 스택은 함수 호출 시 전달되는 인자, 되돌아갈 주소 값 및 함수 내에서 선언하는 변수 등을 저장하기 위해 사용되는 메모리 공간입니다. 따라서 스택 메모리 공간이 독립적이라는 것은 독립적인 함수 호출이 가능하다는 것이고, 이는 독립적인 실행흐름을 가질 수 있다는 것입니다. 결과적으로 실행 흐름의 추가를 위한 최소 조건이 독립된 스택을 제공하는 것이라고 볼 수 있습니다.


[ Context  Switching 이란? ]

 프로세스를 이것저것 우선 순위에 따라 변경하기 위해서는 실제로 작업에 사용되는 프로세스 데이터를 레지스터와 메모리 사이를 왕복하며 값을 복사해야 합니다. 보통 cpu에 의해 프로세스가 일을 처리하게 되는데 스케줄링 방식에 따라 특정 프로세스가 일을 진행하고 있다가 다른 프로세스에게 cpu사용권을 넘겨주게 될 때 어디까지 작업을 했고 다음부터는 어디서부터 작업을 해야하는지에 대한 정보를 보관할 수 있는 곳이 필요하고 이러한 정보들을 프로세스에 맞게 변경해주고 처리하는 것을 말합니다. 실제로 CPU는 동시에 한 개씩만 스레드를 실행시킬 수 있는데 스레드가 여러개가 생성되게 되면 CPU는 각각의 스레드를 번갈아가며 실항하게 되는데, 이 때 이전 스레드의 문맥 정보(레지스터 값, 실행중인 스택 정보 등)을 백업받고 백업 받아놓았던 다음 스레드의 문맥정보를 로딩하는 과정을 거치게 됩니다. 이 과정을 Context Switchig이라고 합니다. 이러한 스레드가 많아질 수록 Context Switching에 많은 부하가 걸리기 때문(메모리와 레지스터 사이의 데이터 이동도I/O이다)에 잘 고려해서 사용해야 되겠습니다.  


오늘 포스팅은 여기까지 하도록 하겠습니다. 잘못된 부분이나 설명이 부족한 부분은 댓글로 남겨주시면 참고하도록 하겠습니다. 감사합니다.




반응형
반응형

 


 [ REST API 제대로 알고 사용하기 ]

 어느 날 뜬금없이 대학교 친구에게 전화가 왔습니다. 그러더니 ‘야, REST API가 정확히 뭐 어떤 거야?’ 하는 질문에 가슴에 비수가 날아와 꽂힌 듯한 느낌을 받았습니다 . 며칠 전 카톡으로 요즘 보통 웹서비스들은 ‘REST API형태로 서비스를 제공한다’고 아는 척을 조금 했던 기억이 머릿속을 빠르게 스쳐 지나갔고 그 순간 대충 얼버무리며 ‘아, 그거 REST하게 클라이언트랑 서버간에 데이터를 주고 받는 방식'을 말한다며 얼렁뚱땅 마무리 지었던 기억이 납니다.  실제로 REST API의 서비스를 직접 개발도 해보고 사용도 해봤는데도 막상 설명을 하자니 어려움을 겪었던 적이 있으셨을텐데요. 그래서 이번에 REST API에 대해 정리하게 되었습니다. 기본적인 REST API에 대한 내용 외에도 REST API를 설계하실 때 참고해야 할 몇 가지 TIP들에 대해 공유해보도록 하겠습니다. 


1. REST API의 탄생

   REST는 Representational State Transfer라는 용어의 약자로서 2000년도에 로이 필딩 (Roy Fielding)의 박사학위 논문에서 최초로 소개되었습니다. 로이 필딩은 HTTP의 주요 저자 중 한사람으로 그 당시 웹(HTTP) 설계의 우수성에 비해 제대로 사용되어지지 못하는 모습에 안타까워하며 웹의 장점을 최대한 활용할 수 있는 아키텍쳐로써 REST를 발표했다고 합니다.


2. REST 구성

쉽게 말해 REST API는 다음의 구성으로 이루어져있습니다. 자세한 내용은 밑에서 설명하도록 하겠습니다.

자원(RESOURCE) - URI

행위(Verb) - HTTP METHOD

표현(Representations)


3. REST 의 특징

1) Uniform (유니폼 인터페이스) 

: Uniform Interface는 URI로 지정한 리소스에 대한 조작을 통일되고 한정적인 인터페이스로 수행하는 아키텍처 스타일을 말합니다.


2) Stateless (무상태성) 

: REST는 무상태성 성격을 갖는다. 다시 말해 작업을 위한 상태정보를 따로 저장하고 관리하지 않는다. 세션 정보나 쿠키정보를 별도로 저장하고 관리하지 않기 때문에 API 서버는 들어오는 요청만을 단순히 처리하면 된다. 때문에 서비스의 자유도가 높아지고 서버에서 불필요한 정보를 관리하지 않음으로써 구현이 단순해진다.


3) Cacheable (캐시 가능) 

: REST의 가장 큰 특징 중 하나는 HTTP라는 기존 웹표준을 그대로 사용하기 때문에, 웹에서 사용하는 기존 인프라를 그대로 활용이 가능하다. 따라서 HTTP가 가진 캐싱 기능이 적용가능하다. HTTP 프로토콜 표준에서 사용하는 Last-Modifyed태그나 E-Tag를 이용하면 캐싱 구현이 가능하다.


4) Self-descriptiveness (자체 표현 구조) 

: REST의 또 다른 큰 특징 중 하나는 REST API 메시지만 보고도 이를 쉽게 이해 할 수 있는 자체 표현 구조로 되어 있다는 것이다.


5) Client - Server 구조 

: REST 서버는 API 제공, 클라이언트는 사용자 인증이나 컨텍스트(세션, 로그인 정보)등을 직접 관리하는 구조로  각각의 역할이 확실히 구분되기 때문에 클라이언트와 서버에서 개발해야 할 내용이 명확해지고 서로간 의존성이 줄어들게 된다.


6) 계층형 구조 

: REST 서버는 다중 계층으로 구성될 수 있으며 보안, 로드 밸런싱, 암호화 계층을 추가해 구조상의 유연성을 둘 수 있고 PROXY, 게이트웨이 같은 네트워크 기반의 중간매체를 사용할 수 있게 한다.



4. REST API 디자인 가이드

! REST API 설계시 가장 중요한 항목은 다음의 2가지로 요약할 수 있습니다.

첫 번째, URI는 정보의 자원을 표현해야 한다.

두 번째, 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE)로 표현한다.

다른 건 다 잊어도 위 내용은 꼭 기억하시기 바랍니다.


4-1  REST API 중심 규칙

1) URI는 정보의 자원을 표현해야한다. (리소스명은 동사보다는 명사를 사용)

GET /members/delete/1

 

위와 같은 방식은 REST를 제대로 적용하지 않은 URI입니다. URI는 자원을 표현하는데 중점을 두어야 합니다. delete와 같은 행위에 대한 표현이 들어가서는 안됩니다.


2) 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE 등)로 표현

 위의 잘못 된 URI를 HTTP Method를 통해 수정해 보면

DELETE /members/1

로 수정할 수 있겠습니다. 회원정보를 가져올 때는 GET, 회원 추가시의 행위를 표현하고자 할 때는 POST METHOD를 사용하여 표현합니다.

 

회원정보를 가져오는 URI

GET /members/show/1     (x)

GET /members/1          (o) 

 

회원을 추가할 때

GET /members/insert/2 (x)  - GET 메서드는 리소스 생성에 맞지 않는다.

POST /members/2       (o)

 

**[참고]HTTP METHOD의 알맞은 역할 **

POST, GET, PUT, DELETE 이 4가지의 Method를 가지고 CRUD를 할 수 있다. 

| POST | POST를 통해 해당 URI를 요청하면 리소스를 생성합니다. |

| GET | GET를 통해 해당 리소스를 조회 합니다. 리소스를 조회하고 해당 도큐먼트에 대한 자세한 정보를 가져온다. |

| PUT | PUT를 통해 해당 리소스를 수정 합니다. |

| DELETE | DELETE를 통해 리소스를 삭제합니다. |

다음과 같은 식으로 URI는 자원을 표현하는데에 집중하고 행위에 대한 정의는 HTTP METHOD를 통해 하는 것이 REST한 API를 설게하는 중심 규칙입니다.



4-2 URI 설계시 주의할 점

1) 슬래시 구분자(/)는 계층 관계를 나타내는 데 사용

EX )  * http://restapi.example.com/houses/apartments

         * http://restapi.example.com/animals/mammals/whales


2) URI 마지막 문자로 슬래시(/)를 포함하지 않는다 

: URI에 포함되는 모든 글자는 리소스의 유일한 식별자로 사용되어야 하며 URI가 다르다는 것은 리소스가 다르다는 것이고, 역으로 리소스가 다르면 URI도 달라저여한다. REST API는 분명한 URI를 만들어 통신을 해야하기 때문에 혼동을 주지 않도록 URI 경로의 마지막에는 /를 사용하지 않는다.

http://restapi.example.com/houses/apartments/ (X)

http://restapi.example.com/houses/apartments  (0)


3) 하이픈(-)은 URI 가독성을 높이는데 사용 

: URI를 쉽게 읽고 해석하기 위해, 불가피하게 긴 URI경로를 사용하게 된다면 하이픈을 사용해 가독성을 높일 수 있다.


4) 밑줄(_)은 URI에 사용하지 않는다. 

: 글꼴에 따라 다르긴 하지만 밑줄은 보기 어렵거나 밑줄 때문에 문자가 가려지기도 한다. 이런 문제를 피하기 위해 밑줄 대신 하이픈을 사용하자(가독성)


5) URI 경로에는 소문자가 적합하다. 

: URI 경로에 대문자 사용은 피하도록 하자. 대소문자에 따라 다른 리소스로 인식하게 된다. RFC 3986(URI 문법 형식)은 URI 스키마와 호스트를 제외하고는 대소문자를 구별하도록 규정하기 때문이지요.

(*RFC 3986 is the URI (Unified Resource Identifier) Syntax document)


6) 파일 확장자는 URI에 포함시키지 않는다.

http://restapi.example.com/members/soccer/345/photo.jpg (X)

REST API에서는 메시지 바디 내용의 포맷을 나타내기 위한 파일 확장자를 URI 안에 포함시키지 않는다. Accept header를 사용하도록 합시다.

GET / members/soccer/345/photo HTTP/1.1 Host: restapi.example.com Accept: image/jpg



4-3 리소스간의 관계를 표현하는 방법

: REST 리소스 간에는 연관 관계가 있을 수 있고 다음과 같은 표현방법으로 사용하자.

/리소스명/리소스 ID/관계가 있는 다른 리소스명

ex) GET : /users/{userid}/devices  (일반적으로 소유 ‘has’의 관계를 표현할 때)

만약에 관계명이 복잡하다면 이를 서브 리소스에 명시적으로 표현하는 방법이 있다. 예를 들어 사용자가 ‘좋아하는’ 디바이스 목록을 표현해야 할 경우 다음과 같은 형태로 사용될 수 있다.

GET : /users/{userid}/likes/devices (관계명이 애매하거나 구체적 표현이 필요할 때)



4-4 자원을 표현하는 Colllection과 Document

: Collection과 Document에 대해 알면 URI 설계가 한 층 더 쉬워집니다. DOCUMENT는 단순히 문서로 이해해도 되고, 한 객체라고 이해하셔도 될 것 같습니다. 컬렉션은 문서들의 집합, 객체들의 집합이라고 생각하시면 이해하시는데 좀 더 편하실 것 같습니다. 컬렉션과 도큐먼트는 모두 리소스라고 표현할 수 있으며 URI에 표현됩니다. 예를 살펴보시도록 하겠습니다.

http:// restapi.example.com/sports/soccer

위 URI를 보시면 sports라는 컬렉션과 soccer라는 도큐먼트로 표현되고 있다고 생각하시면 됩니다. 좀 더 예를 들어보자면

http:// restapi.example.com/sports/soccer/players/13

sports, players 컬렉션과 soccer, 13(13번인 선수)를 의미하는 도큐먼트로 URI가 이루어지게 됩니다. 여기서 중요한 점은 컬렉션은 복수로 사용하고 있다는 점입니다. 좀 더 직관적인 REST API를 위해서는 컬렉션과 도큐먼트를 사용하실 때 단수 복수도 지켜주신다면 좀 더 이해하기 쉬운 URI를 설계하실 수 있을 것 같습니다.
 


5. HTTP 응답 상태 코드

마지막으로 응답 상태코드를 간단히 살펴보도록 하겠습니다. 잘 설계된 REST API는 URI만 잘 설계된 것이 아닌 그 리소스에 대한 응답을 잘 내어주는 것 까지 포함되어야 합니다. 정확한 응답의 상태코드만으로도 많은 정보를 전달할 수가 있기 때문에 응답의 상태코드 값을 명확히 돌려주는 것은 생각보다 중요한 일이 될 수도 있습니다. 혹시 200이나 4XX관련 특정 코드 정도만 사용하고 계시다면 처리 상태에 대한 좀 더 명확한 상태코드 값을 사용하실 수 있기를 권장하는 바입니다.

상태코드에 대해서는 몇 가지지만 정리하도록 하겠습니다.



200 - 클라이언트의 요청을 정상적으로 수행함

201 - 클라이언트가 어떠한 리소스 생성을 요청, 해당 리소스가 성공적으로 생성됨(POST를 통한 리소스 생성 작업시)


400 - 클라이언트의 요청이 부적절 할 경우 사용하는 응답 코드

401 - 클라이언트가 인증되지 않은 상태에서 보호된 리소스를 요청했을때 사용하는 응답 코드 (로그인 하지 않은 유저가 로그인했을 때 요청 가능한 리소스를 요청했을 때)

403 - 유저 인증상태와 관계 없이 응답하고 싶지 않은 리소스를 클라이언트가 요청했을 때 사용하는 응답 코드 (403 보다는 400이나 404를 사용할 것을 권고. 403자체가 리소스가 존재한다는 뜻이기 때문에)

405 - 클라이언트가 요청한 리소스에서는 사용 불가능한 Method를 이용했을 경우 사용하는 응답 코드


301 - 클라이언트가 요청한 리소스에 대한 URI가 변경 되었을때 사용하는 응답 코드 (응답시 Location header에 변경된 URI를 적어 줘야 한다.

500 - 서버에 문제가 있을 경우 사용하는 응답 코드


[ 글을 마치며 ]

그래서 'REST API가 정확히 뭐 어떤 거야?'라고 다시 묻는 다면 'HTTP METHOD와 자원을 표현하는 URI를 이용해 서비스의 데이터에 접근하는 것' 라고 제 나름의 정의를 내려보았습니다. 물론 비전공자인 친구에게는 추가적인 설명이 필요할 것 같습니다. 


RESTFul한 API를 설계하실 때 도움이 될 만한 내용들을 제 나름의 우선순위를 가지고 정리해 보았습니다. 정리를 하면서 다시 한 번 느낀 것은 정확히 알지 못하면 '설명할 수 없다'는 것입니다. 누군가가 그런 말을 하였습니다. '당신이 어떤 것을 할머니에게 설명해 주지 못한다면, 그것은 진정으로 이해한 것이 아니다.' 저 문구를 항상 가슴 깊이 새기고 앞으로 무엇인가 새로운 지식을 학습해 실무에 적용할 때에도 '대충'이 아닌 '정확한 이해'를 바탕으로 문제를 해결해 나가도록 해야겠다'는 다짐과 함께 글을 마무리 짓도록 하겠습니다.


마지막으로 REST API는 정해진 명확한 표준이 없기 때문에 REST API를 사용함에 있어 '무엇이 옳고 그른지'가 아닌 개발하는 서비스의 특징과 개발 집단의 환경과 성향 등이 충분히 고려되어 설계되어져야 할 것입니다

 

 

긴 글 읽어주셔서 감사합니다.


[ Reference ]

- 일관성 있는 웹 서비스 인터페이스 설계를 위한 REST API 디자인 규칙(한빛미디어)

https://ko.wikipedia.org/wiki/REST

http://blog.remotty.com/blog/2014/01/28/lets-study-rest/

https://yangbongsoo.gitbooks.io/study/content/restc758_c774_d574_c640_c124_acc4.html

http://spoqa.github.io/2012/02/27/rest-introduction.html


#NHN엔터테인먼트가 만드는 IT 서비스를 소개하고, 개발 경험을 공유하는 기술 커뮤니티 이고 해당 페이지에 게시한 글입니다.

많은 구독부탁드립니다:)

https://www.facebook.com/toast.nhnent/?fref=ts 


반응형
반응형


 

안녕하세요. 오늘은 작년 신입 교육 때, 딱 1년 전 읽었던 책 ( 열혈강의, 자바 웹 개발 워크북 )에 대해 정리해 보는 시간을 갖도록 하겠습니다. 책상 옆에 놓여있길래 막상 꺼내 펼쳐 보니 잊고 있었던 내용들도 있고 다시 한 번 상기할만한 내용들이 있어 이렇게 정리하게 되었습니다. 이제 막 웹을 시작하시는 분들이 보시기에 좋은 책인 것 같습니다. 정리라는게 챕터별로 정리하는 게 아닌 개인적으로 메모해놓고 다음에 다시 상기해 볼 만한 내용들이나 괜찮은 내용이다 싶은 부분만을 추려 정리하는 것이기 때문에 자세한 내용을 알고 싶으실 경우 책을 사서 보시길 추천해드립니다.

 

 

[ 프록시 서버 (Proxy Server) ]

클라이언트와 서버 사이에서 통신을 중계해 주는 컴퓨터나 프로그램을 말합니다. 프록시 서버의 주된 용도 중 하나는 빠른 전송을 위하여 서버의 응답 결과를 캐시에 저장해 두는 것입니다. 프록시 서버를 두는 두 번째 이유는 보안적인 부분인데, 첨단 기술을 다루는 회사의 경우 내부 사용자의 기밀 유출에 민감할 수밖에 없습니다. 이런 경우 프록시 서버를 이용하면 외부로 전달되는 데이터를 검사하여 특정 단어가 포함된 자료의 송.수신을 차단하거나 보안 팀에 경고 메시지를 보낼 수 있습니다.

 

[ 멀티 프로세스와 멀티 스레드 ]

멀티 프로세스 방식은 클라이언트가 연결 요청을 하면 서버 프로그램은 자신을 복제하여 클라이언트에 대응하게 하고, 자신은 다른 클라이언트의 요청을 기다립니다. 이 방식은 원본 프로세스의 메모리를 모두 복제하기 때문에 자원 낭비가 심합니다. 그에 비해 멀티 스레드 방식은 클라이언트 요청을 처리하는 일부 코드만 별도로 분리하여 실행하기 때문에 전체 메모리를 복제할 필요가 없어, 멀티 프로세스 방식보다 메모리 낭비가 적습니다.

 

[ 요청 헤더 ]

헤더에는 세 가지 종류가 있는데 요청이나 응답 모두에 적용할 수 있는 '일반 헤더(General-header)'와 요청 또는 응답 둘 중 하나에만 적용할 수 있는 '요청 헤더 또는 응답 헤더(Request-header/Response-header)', 보내거나 받는 본문 데이터를 설명하는 '엔티티 헤더(Entity-header)'가 있습니다. 요청 헤더가 담는 헤더명중 User-Agent가 있는데 클라이언트의 정보를 서버에게 알려주는 헤더입니다. 웹 서버는 이 헤더를 분석하여 요청자의 OS와 브라우저를 구분합니다.

 

[ CGI(Common Gateway Interface) ]

웹 서버와 프로그램 사이의 데이터를 주고받는 규칙을 CGI(Common Gateway Interface)라고 합니다. 이렇게 웹 서버에 의해 실행되며 CGI 규칙에 따라서 웹 서버와 데이터를 주고 받도록 작성된 프로그램을 'CGI 프로그램'이라고 합니다.

 

[ 서블릿 컨테이너 ]

서블릿의 생성과 실행, 소멸 등 생명주기를 관리하는 프로그램을 '서블릿 컨테이너(Servlet Container)'라 합니다. 서블릿 컨테이너(Jave EE 기술 중에서 서블릿, JSP 등 웹 관련 부분만 구현한 서버로 아파치 재단의 톰캣, Jetty등)가 서블릿을 대신하여 CGI 규칙에 따라 웹 서버와 데이터를 주고받습니다.

 

[ WebContent/Web-INF ]

웹 애플리케이션의 설정과 관련된 파일을 두는 폴더로 이 폴더에 있는 파일은 클라이언트에서 요청할 수 없다. 따라서 HTML이나 JavaScript, CSS 등 클라이언트에서 요청할 수 있는 파일을 이 폴더에 두어서는 안 됩니다.

 

[ GET 요청으로 넘어온 매개변수 값의 인코딩 설정 ]

GET 요청은 매개변수 값이 URL에 포함되기 때문에 setCharacterEncoding()으로는 문자 집합을 설정할 수 없다. 톰캣 서버에서 server.xml을 열어 <Connector>태그에 URIEncoding 속성을 추가하고, 값은 UTF-8로 설정한다. 웹 브라우저가 웹 서버로 데이터를 보낼 때는 웹 페이지의 기본 문자집합으로 인코딩하여 보내기 때문에 사용자가 입력한 값은 UTF-8로 인코딩되어 서버에 전달된다. 반면 서블릿은 UTF-8(한글 한 자를 3바이트로 표현) 3바이트를 하나의 문자로 인식하지 않고 각각의 바이트를 개별 문자로 취급하여 유니코드로 변환한다. 이렇기에 server.xml에 설정을 해주지 않을 경우 한글이 깨지게 된다.

 

[ SeverletContext 보관소 ]

웹 애플리케이션이 시작될 때 생성되어 웹 애플리케이션이 종료될 때까지 유지된다. 이 보관소에 데이터를 보관하면 웹 애플리케이션이 실행되는 동안에는 모든 서블릿이 사용할 수 있다.

 

[ HttpSession 보관소 ]

클라이언트의 최초 요청 시 생성되어 브라우저를 닫을 때까지 유지됩니다. 보통 로그인할 때 이 보관소를 초기화하고, 로그아웃하면 이 보관소에 저장된 값들을 비웁니다. 따라서 이 보관소에 값을 보관하면 서블릿이나 JSP 페이지에 상관없이 로그아웃하기 전까지 계속 값을 유지할 수 있습니다. JSP에서는 session변수를 통해 이 보관소를 참조할 수 있습니다.

 

[ ServletRequest 보관소 ]

클라이언트의 요청이 들어올 때 생성되어, 클라이언트에게 응답 할 때까지 유지됩니다. 이 보관소는 포워딩이나 인클루딩하는 서블릿들 사이에서 값을 공유할 때 유용합니다. JSP에서는 request변수를 통해 이 보관소를 참조할 수 있습니다.

 

[ JspContext 보관소 ]

JSP 페이지를 실행하는 동안만 유지됩니다. JSP에서는 pageContext 변수를 통해 이 보관소를 참조할 수 있습니다.

 

[ HttpSession ]

HttpSession 객체는 클라이언트 당 한 개가 생성됩니다. 웹 브라우저로부터 요청이 들어오면, 그 웹 브라우저를 위한 HttpSession 객체가 있는지 검사하고, 없다면 새로 HttpSession 객체를 만듭니다. 이렇게 생성된 HttpSession 객체는 그 웹 브라우저로부터 일정 시간 동안 Timeout 요청이 없으면, 삭제됩니다.

 

[ JspContext의 활용 ]

JSP 페이지를 작성하다 보면 <jsp:include>와 같은 특별한 태그를 사용하게 됩니다. 이런 태그들은 JSP 엔진이 서블릿 클래스를 생성할 때 특정 자바 코드로 변환됩니다. 이때 이 태그의 값을 다루는 객체를 '태그 핸들러'라고 부릅니다. 바로 이 태그 핸들러에게 데이터를 전달하고자 할 때 JspContext 보관소를 사용하는 것입니다.  JSP 페이지에 선언된 로컬 변수는 태그 핸들러에서 접근할 수 없습니다. 따라서 태그 핸들러에게 전달할 데이터가 아니라면 JspContext에 값을 보관할 필요가 없습니다.

 

[ EL(Expression Language) ]

EL(Expression Language)은 콤마(.)와 대괄호([])를 사용하여 자바 빈의 프로퍼티나 맵, 리스트, 배열의 값을 보다 쉽게 꺼내게 해주는 기술로 스태틱(static)으로 선언된 메서드를 호출 할 수도 있습니다. EL은 ${}와 #{}를 사용하여 값을 표현합니다. ${표현식} 으로 지정된 값은 JSP가 실행될 때 JSP 페이지에 즉시 반영됩니다. 그래서 ${}을 '즉시 적용(immediate evaluation)'이라 부릅니다. #{}을 '지연 적용(deferred evaluation)'이라 부르는데 UI를 만들 때 사용된다고 합니다.

 

[ DI(Dependency Injection) ]

작업에 필요한 객체를 외부로부터 주입 받는 것으로 다른 말로 역제어(IoC, Inversion of Control)'라고도 부릅니다.

 

[ mybatis ]

mybatis는 반복적이고 지루한 JDBC 프로그래밍을 단순화하기 위해 클린턴 비긴이 만든 작은 라이브러리에서 출발하였다. 이 라이브러리는 iBATIS라는 이름으로 2004년 아파치 소프트웨어 재단에 기부되면서 알려지게 되었다. 좀 더 효율적인 개발 관리를 목표로 2010년 6월 아파치 재단에서 구글 코드로 이사하였고 프로젝트 이름도 mybaits로 바뀌었다. mybatis의 핵심은 개발과 유지보수가 쉽도록 소스 코드에 박혀있는 SQL을 별도의 파일로 분리하는 것이다. 또한 단순하고 반복적인 JDBC 코드를 캡슐화하여 데이터베이스 프로그래밍을 간결하게 만드는 것이다.

 

[ mybatis javaType속성 ]

<result>에서 javaType을 사용하면, 칼럼의 값을 특정 자바 객체로 변환할 수 있다. 다음과 같이 'STA_DATE'칼럼에 대해 javaType을 java.sql.Date으로 설정하면, 칼럼 값을 꺼낼 때 그 객체로 변환된다.

<result column="STA_DATE" property="startDate" javaType="java.sql.Date"/>

 

[ mybatis <id> 엘리먼트 ]

SELECT 문을 실행하면 레코드 값을 저장하기 위해 결과 객체가 생성되는데, SELECT문을 실행할 때마다 매번 결과 객체를 생성한다면 실행 성능이 나빠질 것입니다. 이를 해결하기 위해 SELECT를 통해 생성된 결과 객체들은 별도의 보관소에 저장(캐싱, caching)해두고, 다음 SELECT를 실행할 때 재사용합니다. 이때 보관소에 저장된 객체를 구분하는 값으로 <id>에서 지정한 프로퍼티를 사용합니다.

 

[ mybatis의 SELECT 결과 캐싱 ]

SELECT를 실행할 때마다 결과 레코드에 대해 매번 객체를 생성한다면, 속도도 느리고 메모리도 낭비됩니다. 이를 개선하기 위해 mybatis는 객체 캐싱을 제공합니다. 즉 한 번 생성된 객체는 버리지 않고 보관해 두었다가, 다음 SELECT를 실행할 때 재사용하는 것입니다. 첫 번째 질의를 수행할 때 생성된 결과 객체는 풀(pool)에 보관해 둡니다. 두 번째 질의에서는 질의 결과에 대해 새로 객체를 생성하기 전에, 객체 풀에 보관된 객체 중에서 해당 칼럼의 값과 일치하는 객체를 먼저 찾습니다. 있다면 기존 객체를 사용하고 없다면 새로 객체를 생성합니다. 이것이 mybatis의 객체 캐싱 기법입니다.

 



반응형
반응형



 안녕하세요. 오늘은 ENUM을 JSP에서 받아 사용하는 방법에 대해 포스팅하려고 합니다. 많은 분들이 공통적으로 자주 사용하는 코드 값들이나 타입들을 ENUM에 넣어서 주로 사용하실 텐데요. ENUM을 값 그대로 가져와서 JSP에서 쓸 수 있는 좋은 방법이 있어 포스팅을 하려고 합니다. 저 또한 최근에 ENUM값을 JSP에서 사용해야 하는 기능 개발 건이 있었는데 오늘 포스팅 하는 내용을 통해 쉽게 해결할 수 있었습니다.


먼저 ENUM을 어떻게 JSP에서 사용할 수 있었는지에 대해 간단한 절차를 적어보도록 하겠습니다.1. 사용하고자 하는 ENUM 클래스를 작성합니다.2. web.xml에 Context-param으로 해당 enum 클래스를 등록해 줍니다.3. EnumContextListner를 web.xml에 등록해 줍니다.4. EnumContextListner 클래스를 작성합니다.5. JSP에서 Context-param으로 등록한 ENUM을 가져다가 사용합니다.


1. 사용하고자하는 ENUM 클래스를 작성합니다.해당 내용은 포스팅을 위해 번호와 이메일을 임의로 작성하였습니다. 잘린 부분은 get,set메서드이기 때문에 생략하도록 하겠습니다.



2. web.xml에 Context-param으로 해당 enum 클래스를 등록해 줍니다.위에서 작성한 SmsServiceType 클래스를 Context-param의 param-value에 등록해 줍니다. 간단히 Context-param에 대해 설명하자면 보통 사용자의 요청(ex, www.nr.com/dongbeom)이 웹서버를 거쳐 웹 어플리케이션 서버(탐캣)에 들어왔을 경우 그에 해당하는 servlet을 생성하게 됩니다. Context-param은 사용자의 요청에 의해 생성되는 모든 servlet에서 Context-param으로등록 된 값을 사용할 수 있도록 하는 존재로 쉽게 전역 변수의 역할과 비슷하다고 생각하시면 될 것 같습니다.

밑의 그림에서는 Context-param의 이름이 enumServletContextConfig이고 com.nhncorp.echo.eme.model.SmsServiceType의 클래스를 값으로 가지고 있는 컨텍스트를 정의하고 있습니다.




3. EnumContextListner를 web.xml에 등록해 줍니다.
리스너는 컨텍스트에 정의되어 있는 것들을 모든 서블릿과 필터가 공유할 수 있도록 해줍니다.밑의 그림에서 EnumContextListener 클래스를 listener-class로 등록하고 있는 것을 볼 수 있습니다. 보통 컨텍스트의 값과 리스너들은 클라이언트에서 요청이 들어오지 않아도 web.xml이 읽혀질 때 호출되게 됩니다. (서버가 시작되는 시점에도 호출되게 됨)



4. EnumContextListner 클래스를 작성합니다.해당 클래스에 대해 간단히 설명하자면 web.xml에서 등록한 Context-param의 값들을 다 가져와서 MAP과 LIST로 만들어 JSP에서 사용할 수 있도록 ServletContext에 set을 해주는 역할을 합니다. 또한 loadEnum이라는 메소드를 보시면 ENUM 을 맵과 리스트로 만들어 Collections.unmodifiableMap, Collections.unmodifiableList로 변환해 read-only MAP과 LIST로 변경해 주는 작업도 진행 합니다. (혹시나 ENUM 값을 다른 곳에서 초기화하거나 값을 변경하는 불상사를 막을 수 있음)





5. JSP에서 Context-param으로 등록한 ENUM을 가져다가 사용합니다.

위와 같은 과정을 거치면 모든 JSP에서 해당 ENUM 값을 가져다가 사용할 수 있습니다. 사용하는 방

법에 대한 가이드를 참고 하셔서 사용하시면 됩니다.

[ 참고 가이드 ] 
1) web.xml에 리스너 등록 
2) web.xml의 context-param으로 enumServletContextConfig를 등록. value값에 사용할 enum클래스명을 기입 
3) jsp에서 등록한 enum을 ${enum명(소문자시작)} 형식으로 호출할 수 있다. ex) ${day.MONDAY} 
4) enum.values()의 경우 ${enum명 + List} 형식으로 호출할 수 있다. ex) ${dayList}


저 같은 경우에는 list형태로 다음과 같이 사용하였습니다. ${smsServiceTypeList}


포스팅은 여기서 마치고 이번 포스팅을 진행하다보니 이번 포스팅을 이해하기 위해 필요한 기본적인 내용들에 대해서(web.xml, servletContext.xml, applicationContext.xml 등등)는 아직 포스팅이 많이 안된 것 같은데 시간 나는 대로 다시 한 번 개념을 정리할 겸 포스팅하도록 하겠습니다.


감사합니다.





반응형
반응형

 


 안녕하세요 이번 포스팅에서는 Xss Filter에 대한 간단한 개념과 이번에 작업을 하다가 헤맸던 JSP에서 폼의 타입이 enctype ="multipart/form-data"일 때 XSS FILTER가 적용되지 않았던 문제에 대해 알아보고자 합니다. Xss Filter를 기존에 써봤다는 가정 하에 포스팅을 진행하겠습니다. ( 기본적인 XSS Filter를 적용하는 법에 대한 설명은 포함되어 있지 않음을 미리 말씀드립니다. )



 ▶ XSS Filter란???


 Xss Filter란 사용자들의 악의적인 스크립트 공격(ex, <script> alert("melong"); </script> )등을 막기 위해 사용하는 filter로 안정적인 웹서비스를 위해서는 필수적인 요소입니다. XSS는 Cross-Site Scripting를 의미한다. 보통 해당 filter를 사용하기 위해서는 web.xml에 필터를 정의해주고 거기에 해당하는 url을 매핑해주고 filter 클래스를 작성해주면 된다.( 이에 대한 내용은 생략합니다.) 



 ▶ 작업 중 문제 발생 ( JSP에서 form의 타입이 enctype="multipart/form-data"일 경우 XSS Filter를 타지 못함)


 보안팀으로부터 페이코 앱 고객센터의 문의를 넣는 페이지에 xss filter가 적용되어 있지 않아 보안에 취약하다는 메일을 한 통 받았습니다. 메일을 받고 가장 먼저 확인한 것은 "web.xml에 해당 문의를 넣을 때의 url이 XSS Filter url에 매핑이 되어있는가" 였습니다. 이를 확인한 결과 해당 url이 XSS Filter에 잘 매핑되어 있는 것을 확인 할 수 있었습니다. 여기서 되게 의아했습니다. 그래서 제가 직접 페이코 앱에서 스크립트( <script> alert("N"); </script> )를 제목 부분에 넣어 문의를 넣어 보았습니다.




 1:1 문의에 들어가서 문의를 넣고 내 문의 보기를 누르자 alert창이 뜨는 것을 볼 수 있었습니다. 도대체 왜 xss filter에 매핑이 되어 있는데 해당 스크립트의 내용이 안 걸러지는지 의아했습니다. 

                                                                           


 


 그림(보안상의 이슈로 모자이크 처리)을 보면 아시겠지만 /~/app/mail/addInquiry.nhn이 문의를 넣을 때 요청되는 url이고 잘 mapping되어 있는 것을 확인하실 수 있습니다. 잘 매핑은 되어 있는데 왜 필터링이 안될까하는 의문과 함께 filter와 wrapper클래스를 디버깅해 본 결과 폼에 의해 전송되는 값들을 제대로 호출해오지 못하는 점을 발견 하였습니다. 그래서 검색을 해본 결과 

 


 그림에서 보는 것과 같이 form 타입을 multipart/form-data로 폼을 넘길 경우 xss filter에서 해당 폼의 request의 값들을 제대로 읽어오지 못하는 것을 알 수 있었습니다. 해당 페이지가 기본적인 제목, 내용을 입력 받고 첨부파일 기능 또한 있는 페이지 이기 때문에 폼의 타입이 multipart/form-data일 수 밖에 없었습니다. 따라서 해당 타입으로 폼이 전송될 때 파일첨부 이외의 값들에 대해 XSS Filter를 통해 스크립트와 악의적인 공격들을 막아주어야하는데 XSS Filter가 폼의 값들을 제대로 읽어들이지 못하고 있었습니다. 문제는 multipart/form-data형식의 경우에는 파라미터를 읽을 때 getPart()와 getParts()라는 메소드를 사용하는데 해당 사용하고 있는 filter 클래스를 보면  getParameter와 getParameterValues()로 요청으로 부터 넘어온 값들에 대해 filter를 적용하는 것을 확인할 수 있었습니다. (밑의 그림)



 ▶ 문제 해결 방법


 위와 같이 form의 타입이 enctype="multipart/form-data"일 경우 XSS Fitler를 타지 못하는 문제를 해결 하기 위해서 XSS Filter 전에 "MultipartFilter"를 적용해 주어 먼저 multipartFile에 대해 필터를 적용해 주고 XSS Filter를 타게 해주어야 합니다. 


 


 그림(혹시나 해서 특정 부분은 모자이크 처리)과 같이 XSS 필터 위에 multipartFilter를 적용한 것을 보실 수 있습니다. 여기서 주의 사항은 multipartFilter에 url에 매핑을 시켜줬다고 해서 XSS Filter에서 url을 제거하면 안됩니다. ( 두 필터 모두에 url이 매핑되어 있어야함!!!! 저는 mutipartFilter에 매핑시켜줬으니까 xss에는 안해도 되나하고 안했다가 많은 시간을 낭비했다는 ㅠ,ㅠ) 이로 인해 form의 타입이 enctype="multipart/form-data"여도 XSS Filter가 잘 작동하는 것을 확인 할 수 있었습니다.



 ▶ multipartFilter를 XSS Filter위에 적용하기 전 requerst를 받아오는 모습과 적용 후 request 비교


먼저 multipartFilter 적용 전 request



다음 web.xml에 multipartFilter를 적용한 후



 request로 넘어오는 값들이 확연히 다른 것을 보실 수 있습니다. multipartParameters를 까보게 되면 해당 페이지에 기입한 여러 값들이 정삭적으로 잘 넘어오는 것을 확인할 수 있었습니다. 이로 인해 제목이나 본문에 스크립트가 들어간다고 해도 XSS Filter를 통해 잘 처리 할 수 있었습니다.

 




반응형
반응형

 JSP/SERVLET 파트에서 SERVLET이 동작하는 흐름에 대해서 알아봤다. 컨테이너에서 서블릿이 초기화되고 그 해당 서블릿이 어떻게 DispatcherServlet에 의해 처리되어 뷰를 반환하게 되는지에 대해 살펴보도록 하겠다.


  DispatcherServlet에 대해 간단히 설명하자면, DispatcherServlet은 Controller로 향하는 모든 웹 요청의 진입점이며 웹 요청을 처리, 결과 데이터를 Client에게 제공하는 역할을 한다.네 맞습니다. DispatcherServlet은 우리가 각각 분리하여 만든 Model 파트와 Controller파트 View 파트를 조합하여 브라우저로 출력해주는 역할을 수행하는 클래스이며 DispatcherServlet으로 인해 web.xml의 역할을 획기적으로 축소시켜 주었다.

예전 DispatcherServlet이 있기전에는 모든 사용자의 요청 url을 일일이 해당 요청을 처리하는 servlet과 매핑시켜주는 작업을 지정해 주었어야만 했다.예를 들어, 기본URL/happy, 기본URL/contents, 기본URL/subject 등의 요청이 들어왔을 때 이에 해당하는 서블릿과의 매핑 작업을 web.xml에 모두 정의해주고 사용했어야 했던 만큼 web.xml 도 복잡해지고 손수 작업에 필요한 서블릿 정의와 매핑작업을 해줘야 했기 때문에 여간 귀찮은 일이 아니였다.

하지만 지금은 web.xml에

이렇게 DispacherServlet을 정의해주고 모든 URL에 대해 매핑을 해주게 되면 DispatcherServlet이 요청 url에 해당하는 컨트롤러를 찾아 매핑해주게 된다. 얼마나 고마운 일인가. 위의 소스코드에 대해 이해가 안가시는 분은  http://blog.naver.com/kim3zz/220273028176 servlet 매핑에 대한 설명 부분을 참고하시길 바란다.


DispatcherServlet은 이렇게 web.xml 을 획기적으로 축소시켜주었고 개발자에게 요청에 따른 컨트롤러를 일일이 매핑해야하는 번거로움 또한 덜어주었다. 이제 그럼 DispatcherServlet이 어떻게 동작하는지에 대해 알아보자.

[ 그림 1 ] 사용자가 특정 URL을 요청하게 되고 웹서와 컨테이너를 거쳐 해당 요청이 DispatcherServlet을 타게 된다.

[ 그림 2 ] DispatcherServlet은 요청에 대한 정보를 HandlerMapping에게 보내 요청을 처리할 수 있는 Controller을 찾아 DispatcherServlet에게 다시 반환하게 됩니다. HandlerMapping은 클라이언트 요청을 어떤 Controller가 수행할지의 여부를 결정해 주며 스프링의 디폴트 전략에 의해 BeanNameUrlHandlerMapping이 설정되어 있어 따로 설정을 하지 않아도 요청 url과 동일한 이름을 갖는 Controller을 찾아 매핑시켜 주게 된다.

[ 그림 3 ] DispatcherServlet은 해당 컨트롤러에게 요청에 대한 처리를 부탁하고 컨트롤러는 요청을 처리한 후에 응답받을 ModelAndView를 리턴하게 됩니다.

[ 그림 4, 5 ] ViewResolver는 컨트롤러가 반환한 ModelAndView를 받아 해당 view가 존재하는지 검색하게 됩니다. 해당 View가 있다면 전처리 과정을 거쳐 해당 View를 반환해 줍니다.

InternalResouceViewResolver를 보시면 name="prefix"와 "suffix"를 보실 수 있는데 컨트롤러가 던지 view 앞에 붙여지는 것이 prefix이고 뒤에 붙여지는것이 jsp가 되게 됩니다. 예를 들어 컨트롤러가 "board"라는 뷰 스트링 객체를 던졌다면 리졸버를 통해 /WEB-INF/views/board.jsp 가 되어 해당 뷰에서 요청이 보여지게 됩니다.

다음에는 web.xml에서는 어떠한 작업들이 이루어지는 지에 대해 살펴보도록 하겠습니다.

ref :https://kisukpark.wordpress.com/2013/08/29/spring-mvc-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90/http://egloos.zum.com/springmvc/v/504151




반응형
반응형

 

 안녕하세요. 오늘은 전에 특정 서비스를 기존 빌드 서버에서 다른 빌드 서버로 이전하는 작업을 진행하면서 경험했던 삽질에 대해서 얘기해보도록 하겠습니다. 해당 서비스는 jdk1.7로 빌드가 되어야 하는데 옮기는 서버에는 jdk1.7이 아닌 jdk1.6이 깔려있어 서버에 jdk1.7을 설치하면서 겪었던 에로사항들에 대해 지금부터 포스팅하도록 하겠습니다.


1. 문제 상황

 


 해당 빌드 서버에 프로젝트를 이전하고 빌드를 수행했는데 다음과 같은 에러가 떴다. 살펴보니 서버와 해당 프로젝트 jdk버전이 맞지 않았던 것이다. (프로젝트 jdk1.7 서버 jdk1.6이 설치된 상황) 따라서 문제를 해결하기 위해 서버에 jdk1.7을 설치해야 하는 상황이었다. 



2. wget을 이용한 jdk1.7다운 그리고 또 다른 문제 발생

 jdk1.7 다운로드 페이지에 가서 wget을 하기 위한 url을 얻어와 서버에서 당연하게 wget http://download.oracle.com/otn-pub/java/jdk/7u67-b01/jdk-7u67-linux-x64.tar.gz 을 수행했다. 하지만 문제는 다음 그림과 같았다.

 

 빨간색 라인을 보면 해당 명령어를 수행했고 그 결과 나는 노란색 네모 상자와 같은 에러문구를 받게 되었다. 



ERROR: certificate common name `www.oracle.com' doesn't match requested host name `edelivery.oracle.com'.

To connect to edelivery.oracle.com insecurely, use `--no-check-certificate'. Unable to establish SSL connection.




 3. 문제 해결

wget으로 jdk1.6까지는 그냥 저런 식으로 다운받을 수 있지만 jdk1.7과 jdk1.8을 받기 위해서는 다음과 같은 명령어를 통해 다운 받을 수 있다.

 

  수행 명령 : wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/7u67-b01/jdk-7u67-linux-x64.tar.gz
 위와 같은 명령을 통해 다운이 되는 것을 알 수 있었다.
'--no-check-certificate'와 '--no-cookies -header'가 추가된 것을 볼 수 있는데 --no-check-certificate같은 경우에는 서버의 상당수가 self-signed인증서를 가지고 있는데, 이 경우 증명된 인증서가 아니라고 해서 문서를 읽어오지 못할 때 --no-check-certificate 옵션을 주어 해결할 수 있고 쿠키 값을 disable한다는 --no--cookies 옵션을 주어야 한다고 한다.

JDK 8을 받고 싶다면
RPM의 경우
​wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u5-b13/jdk-8u5-linux-x64.rpm

TAR.GZ의 경우
​wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u5-b13/jdk-8u5-linux-x64.tar.gz
JDK 7의 경우
TAR.GZ
​wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/7u60-b19/jdk-7u60-linux-x64.tar.gz



이상 포스팅을 마치도록 하겠습니다.






반응형
반응형

 


 월 초(15.01)에 현재 팀에 분산 되어 있는 빌드 및 CI 서버 통합 작업을 진행하였다. 이번 포스팅은 서버 통합 작업을 하다가 발생한 java.lang.OutOfMemoryError: PermGen space문제에 대해 알아보도록 하겠다. 먼저 첫 번째로 문제가 발생한 현상에 대해 살펴보고 둘 째, 어떻게 해결했는지 살펴보고 마지막 셋째, java.lang.OutOfMemoryError: PermGen space에 대해 자세히 알아보자.



 1. 서버 작업 중 발생한 현상


 기존 서버에서 빌드 되는 프로젝트들도 많았지만 (약 50개 정도) 해당 부분에 대해서는 많은 문제가 되지 않았다. 왜냐하면 여러 프로젝트(10개 이상)가 동시에 빌드 작업을 진행하는 경우는 제로에 가까웠기 때문이다. 문제는 특정 소스코드가 수행되었을 때 자동으로 빌드되 commit_build와 특정 시간 간격마다 수행되게 하는 배치 빌드 등을 추가하면서 부터 발생하였다. 처음에는 서버 통합작업을 잘 진행하고 있었는데 어느 순간 부터(c_build, i_build)가 여러 개 추가되는 시점부터 서버가 뻗어버리는 현상이 발생하였다. 


 


 다음 그림과 같이 java.lang.OutOfMemoryError: PermGen space 에러가 발생한 것을 볼 수 있다. 이로 인해 서버가 뻗어 버리는 현상이 주기적(약1시간 간격)으로 나타났다. 그래서 일차적으로 주기적으로 빌드 되는 프로젝트들에 대해 주기적으로 빌드 되지 않도록 작업하였다.



  2. 해결한 방법

먼저 해결책을 말하자면 해당 서버의 톰캣/bin catalina.sh 에 들어가서 밑의 그림과 같이 추가해주었다.

 

그림이 잘 안보인다 ㅠㅠ 아무튼

 JAVA_OPTS="-server -Xms2048m -Xmx2048m -XX:MaxPermSize=512m -XX:-UseConcMarkSweepGC"

를 선언해주어 해결하였다. (기존에는 -XX:MaxPermSize가 선언되어 있지 않았다. (기본 20m로 설정되있다고 한다)


# -XX:+UseConcMarkSweepGC

 // 표준 garbage collector가 아닌 perm gen도 gc하는 concurrent collector를 사용하도록 한다.


-XX:+CMSPermGenSweepingEnabled

 // perm gen 영역도 gc의 대상이 되도록 한다.


-XX:+CMSClassUnloadingEnabled

// 클래스 데이타도 gc의 대상이 되도록 한다.


# -XX:MaxPermSize=64m

// 어느정도 크기가되어야 gc가 자주 발생하지 않는다. 기본값이 8M인듯.




  3. java.lang.OutOfMemoryError: PermGen space 관련 정보들에 대해 알아보자. (두서 없이 정리됨을 양해바람)


# java.lang.OutOfMemoryError: PermGen space문제는 기본적으로 동적 클래스를 많이 사용할 경우 빈번히 발생하는 문제로 JSP->SERVLET 변화. SPIRNG에서의 동적 클래스를 많이 사용하는 프레임워크로 인해 발생한다.


# JVM이 새로운 클래스 정의를 로드해야 하는데 이를 수행하기 위한 PerGen 공간이 충분하지 않아 발생한다. 즉, 이미 너무 많은 클래스들이 로딩되어 있으며 서버가 현재 크기의 PermGen이 처리할 수 없을 만큼 많은 클래스들을 사용하고 있기 때문이기도 하다. 


# 보통 Java heap이나 힙의 특정 영역에 객체를 할당 할 수 있는 공간이 충분하지 않을 때 발생


# PermGen space 라는 메시지는 permanent generation 이 가득 찬 상태라는 것을 알려준다. permanent generation은 클래스와 메쏘드 객체가 저장되는 힙의 영역을 나타낸다. 어플리케이션이 많은 수의 클래스를 로드하면, -XX:MaxPermSize 옵션을 사용하여 permanent generation의 크기를 증가시킬 필요가 있다. 


# 보통 톰캣을 사용하다가 이 에러를 보았다면 대체로 웹 어플리케이션을 너무 많이 Update 하거나 Reload 한 것이 원인이 될 수 있다. 톰캣과 JVM은 웹 어플리케이션을 삭제하고 다시 생성할 때 할당한 모든 메모리를 해제하지는 않는다. 톰캣을 여러 번 리로드 하면 할당된 메모리가 바닥나서 동작하지 않게 된다. 


# 톰캣에서 이 에러가 발생했을 경우 해결 방법은 1. 톰캣을 재시작 하는 것(임시적으로 해결) 2. 톰캣이 할당할 수 있는 메모리를 늘려 준다. 3. 메모리 누수가 발생하지 않도록 톰캣을 설정 (불필요한 프로젝트 들이 로딩되지 않도록 정리)


# Heap은 프로그램이 돌아가는 도중에 생성 삭제되는 곳으로 garbage-collected가 일어나는 곳이며 Permenant는 프로그램이 끝날 때까지 영원히 메모리를 차지하고 있는 공간으로 garbage-collected가 일어나지 않는 곳이다. Heap에는 동적으로 생기는 메모리 들이 들어가는 곳이고, Permenanat는 Class names, Internalized strings, Objects 등이 들어가며 PermGen도 이곳에 해당한다. 


참조 :

http://mindasom.tistory.com/96

http://jwchoi85.tistory.com/155#recentComments





반응형

+ Recent posts