17년 3월 30일,31일

새로 집 장만해서 이사.
회사 회장님 육친 별세.
박근혜 구속 수감.
2017/03/31 19:54 2017/03/31 19:54
이 글의 관련글
    이글의 태그와 관련된 글이 없습니다.
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

뭐? 몽고DB랑 Elasticsearch도 랜섬웨어에 당한다고?

2017/01/19 09:49

서비 Tip&Tech

몽고DB의 취약점을 이용한 랜섬웨어가 있다고합니다. 근데.. 그걸 모방해서 Elasticsearch도 당하고 있다네요.
당하면 데이터를 삭제하고 비트코인 요구..
이미지 출저 - zdnet

이미지 출저 - zdnet



몽고DB측 기사는 이렇습니다.
https://www.mongodb.com/blog/post/how-to-avoid-a-malicious-attack-that-ransoms-your-data

zdnet의 elasticsearch 관련 기사는 다음과 같고요..
http://www.zdnet.com/article/first-came-mass-mongodb-ransacking-now-copycat-ransoms-hit-elasticsearch/(새 창으로 열기)

예방책은 몽고DB나 elasticsearch의 서비스 port를 public으로 열어놓지말고
사용자 접근제어 설정을 하고 방화벽, VPN, 프록시 서버 등을 이용해 접속하는것을 권고합니다.
2017/01/19 09:49 2017/01/19 09:49
이 글의 관련글
    이글의 태그와 관련된 글이 없습니다.
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

나란 인간

사용자 삽입 이미지



“저는 하루에도 몇 번씩 변화합니다. 아침에 눈을 뜨면 한 사람이 있습니다. 그리고 잠을 청하러 갈 때면 거기엔 확실히 또 다른 한 사람이 있습니다.”

밥 딜런

ISFP형 사람은 일반적으로 사람들이 생각하듯 야외 정원에서 앙증맞은 나무 그림을 그리고 있는 그런 유형의 예술가는 아니지만, 진정한 예술가 축에 속하는 이들입니다. 실상 상당수 많은 이들이 그러한 능력을 충분히 갖추고 있기도 합니다. 이들은 그들의 심미안이나 디자인 감각, 심지어는 그들의 선택이나 행위를 통하여 사회적 관습이라는 한계를 뛰어넘고자 합니다. 실험적인 아름다움이나 행위를 통해 전통적으로 기대되는 행동양식이나 관습에 도전장을 내미는 이들은 "저를 가둬두려 하지 마세요!"라고 수없이 외쳐댑니다.

자기 자신에 대한 만족

이들은 다양한 아이디어나 사람들로부터 영감을 받아 다채로우면서도 감각적인 삶을 살아갑니다. 그들이 받은 영감을 본인만의 시각으로 재해석하여 새로운 것을 발견하고 탐험함으로써 즐거움을 느끼기도 하는 이들은 그 어떤 유형의 사람보다 탐험이나 실험 정신이 뛰어납니다. 어디로 튈지 모르는 즉흥적인 성향으로 간혹 이들을 예측하는 것이 어려운데, 이는 가까운 친구나 사랑하는 사람들 역시 예외가 아닙니다.

그럼에도 불구하고 단연 내향적(I) 성향을 가지고 있는 이들은 스포트라이트를 벗어나 재충전을 위해 혼자만의 시간을 갖곤 하는데, 이는 간혹 주위 사람들을 놀라게 하기도 합니다. 하지만 이들이 혼자 있다고 게으르게 넋 놓고 앉아 있다는 말은 아닙니다. 이 시간은 그들이 가진 원리원칙을 재고하는 자기 성찰을 위한 시간으로, 과거나 미래에 집착하지 않고 순전히 그들이 누구인지 자신을 들여다보는 시간입니다. 그리고는 이들은 곧 언제 그랬냐는 듯이 사람들 앞에 변화된 모습으로 '짠'하고 나타납니다.

넘치는 열정을 쏟아부으며 정열적인 삶을 살아가는 ISFP형 사람은 다른 유형의 사람들에 비해 도박이나 익스트림 스포츠와 같이 위험성이 내재한 활동을 즐기는 경향이 있습니다. 그나마 다행인 것은 그들의 상황 조율 능력과 환경으로 말미암아 대부분의 사람보다 이에 소질이 있다는 것입니다. 다른 이들과 어울리는 것을 좋아하기도 하는 이들은 거부할 수 없는 그들만의 매력을 가지고 있습니다.

타인의 작은 칭찬에도 쉽게 자극받아 무책임하고 무모한 행동을 일삼을 수 있음을 그들 자신 역시 잘 알고 있습니다.

반대로 ISFP형 사람은 누군가로부터 비판을 받을 경우, 상황을 안 좋게 몰고 갈 수도 있습니다. 타인의 적절한 비판은 오히려 다른 관점으로 받아들여 새로운 방안을 모색하는 가치 있는 용도로 활용하기도 하는 반면, 신랄하거나 진중치 못한 비판은 자칫하면 그들의 화를 돋우어 그리 아름답지만은 않은 모습으로 분노를 표출하게 하기도 합니다.

ISFP형 사람은 타인의 감정을 잘 살피며 조화를 중요시 여깁니다. 그러한 이유로 이들이 만일 비판을 받는 경우, 분노에 사로잡혀 화가 누그러지기까지 꽤 오랜 시간이 걸립니다. 하지만 좋은 일이건 나쁜 일이건 영원히 계속되는 것은 없듯이, 일단 분노의 감정이 사그라지면 이들은 과거는 과거일 뿐이라고 치부하며 마치 아무 일도 없었다는 듯이 다시금 그들의 삶을 살아갑니다.

작은 것 하나하나 모두 인생의 의미

ISFP형 사람이 가장 어려워하는 것 중 하나가 미래를 설계하는 일입니다. 더 나은 미래를 위해 목표를 설정하고 이를 달성케 하는 건설적인 이상향을 찾는다는 게 그리 생각만큼 간단한 일이 아닙니다. 그럼에도 불구하고 관리자형 사람들과 달리 이들은 미래를 구체적인 자산이나 은퇴 계획이라는 틀 안에서 세우는 것이 아닌 다양한 경험을 통해 자아를 찾는 데 필요한 행동 계획을 세우는 데에 더 많은 투자를 하는 경향이 있습니다.

만약 이러한 목표나 믿음이 순수함에서 기인한 것이라면 이들은 누구보다도 사심 없는 마음으로 선행을 실천할 것입니다. 하지만 이는 반대로 말하면 누구보다도 자기중심적이며 속임수를 일삼으며 자기애에 사로잡혀 행동하는 이들로 비추어질 수도 있음을 의미합니다. ISFP형 사람은 그들이 하고자 하는 대로 그냥 내버려 두는 것이 가장 현명한 방법입니다. 물론 새로운 취미를 발견하고 실행하는 것이 생각처럼 쉬운 일은 아니지만, 하루하루 서두르지 않고 원하는 것이 무엇인지 곰곰이 생각하고 되새겨 본다면 그것이 무엇이 되었든 ISFP형 사람이 진정 좋아하는 것이 무엇인지 찾을 수 있을 것입니다.

ISFP형에 속하는 유명인

사용자 삽입 이미지
2016/12/15 17:55 2016/12/15 17:55
이 글의 관련글
    이글의 태그와 관련된 글이 없습니다.
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. Blog Icon
    서비2

    님 , 저도 이름에 섭자가 들어가 서비라고 불려요,

    근데 제가 사용하는 아이디로 atom* 이 붙어요

    근데 더 신기한건 제 성격 검사 결과도 자유로운 예술가였어요....

    개발관련한 포스팅 보다가 최근글에 댓글 남겨봅니다 ㅎㅎ

자축 10/2000 달성

2016/12/01 12:06

서비 낙서장

10/2000

자축~

2016/12/01 12:06 2016/12/01 12:06
이 글의 관련글
    이글의 태그와 관련된 글이 없습니다.
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

2016년 대한민국. 정운호에서 최순실까지...

1. 정킷방을 운영하던 범서방파 구속

2. 검찰 조사중에 '네이처 리퍼블릭'의 정운호 대표의
100억대 도박 혐의 발견(삼성 선수들 도박도 발견)

3. 정운호가 변호사로 부장판사 출신 최유정 선임.

4, 이와중 정운호가 롯데그룹 면세점 선정 로비의혹이
드러남. 롯데에 검찰 조사가 들어가고 대규모 비자금
여부를 파헤침. (롯데그룹 이인원 부사장 자살)

5. 정운호와 최유정이 변호사 수임료 문제로 다툼
최유정 변호사법 위반으로 구속됨

6. 정운호의 이전 도박사실을 동업자 김모씨가 폭로
그 사건은 홍만표가 맡았던 걸 알게되고 홍만표 조사 시작
홍만표의 전관예우로 막대한 이득을 취한게 포착

7. 홍만표가 정운호에게 청와대 민정수석 우병우를 잡아놨으니 염려말라고 했던걸 발견. 우병우 게이트 시작

8. 넥슨에게 거액의 주식을 뇌물로 받은 진경준 게이트 조사중에 조선일보가 넥슨과 우병우의 부동산 비리 의혹을
제기함

9. 청와대가 빡쳐서 조선일보에게 '부패 기득권 세력'이라고 어그로 시전

10. 우병우를 놓고 청와대와 조선일보의 싸움이 계속되는데 빡친 조선일보가 K스포츠와 미르재단에 청와대가 압력을 넣어 기업들로부터 상납금을 내도록 했다는 기사를 냄.

11. 청와대는 이석수 특검으로 국면을 전환하는 한편
친박 김진태 의원이 조선일보의 송희영주필이 대우조선해양 사장에게 접대를 받았다고 폭로 박수환 게이트 터짐.
(청와대의 역공)

12. 송희영 주필이 사임하고 조선일보는 일단 꼬리를 내림으로써 일단락 되는 듯 했으나 한겨레가 조선일보가 꺼냈던
K스포츠와 미르재단의 중심에 최순실이 있다고 터뜨림으로써 최순실 게이트가 시작됨.

13. 한겨레와 조선일보의 이상한 좌우 콜라보레이션으로
최순실과 미르재단의 관계 최순실의 딸 정유라의 이대 부정입학 의혹이 제기됨. 또한 최순실 아버지 최태민과 박근혜,최순실과 박근혜의 관계들이 언론을 통해 대중에 퍼짐.
일설에는 박근혜 아바타설을 제기하며
'최순실이 박근혜 연설문까지 고쳐주는 사이다'라는 말을 했으나 다들 개소리로 치부함.

14. 박근혜가 최순실 어머니 생신 때 축가를 불렀다는 의혹 제기. 그리고 어제 JTBC가 최순실 컴퓨터에 박근혜의 연설문 파일이 수십개 발견됨으로써...

이 모든건 정운호가 도박질한 나비효과

2016/10/25 21:08 2016/10/25 21:08
이 글의 관련글
    이글의 태그와 관련된 글이 없습니다.
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

골핑 골프데이 2016년 10월 19일

제 업무와 관련있는 회사에서 10월19일 골프용품 할인행사를 한다고...
현재는 비공개 상태인 상품들의 가격을 어깨너머로 봤는데 골프 즐기는 사람에게는 가격 매리트가 꽤 있을것 같음.

http://golping.golfzon.com/event/Discount/blackDayEvent.do(새 창으로 열기)




사용자 삽입 이미지
2016/10/13 14:35 2016/10/13 14:35
이 글의 관련글
    이글의 태그와 관련된 글이 없습니다.
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

함수형 언어에서 UML은 어떻게 사용하나?

함수형 언어 개발자는 일반적으로 다이어그램을 사용하지 않는다. (전부는 아니지만) 대부분의 함수형 언어 개발자는 OOP 언어 개발자가 UML을 통해 표현하는 객체사이의 관계를 types를 통해 기술하곤 한다.
이유는 함수형 프로그래밍에서 변경가능한 object 가 존재하지 않기때문에  "변경가능" 이란 상황이 극히 드물기때문에 객체사이의 관계를 다이어그램으로 표현하는게 필요하나거나 도움이된다거나 하지않기때문이다.
또한 한 function에서 다른 function을 호출할때 속성(property)은 설계된 디자인보다는 function이 호출하는 기능의 구현에 더 영향을 받는게 일반적이기때문이다.

함수형 언어에서의 UML표현이 꼭 필요한 상황이라면 types나 function의 개념을 설명할 수 있는 concept map(새 창으로 열기) 을 확인해 보기 바란다.



2016/10/11 15:43 2016/10/11 15:43
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

아파치 kafka 0.10.0 offset 초기화 현상

최근 프로젝트를 하나 진행하면서 데이터 파이프라인으로 아파치 카프카 0.10.0을 도입하였다.
기존 프로젝트에서 이미 0.8.1을 도입하여 진행한적이 있어 도입 자체는 부담이 없었고.. 0.9를 거치면서 producer, consumer API가 많이 정비되었고 0.10.0에 와서는 stream process 지원이 강화된 부분이 마음에 들어서이다.

개발 완료 후 QA를 진행하는데 특이한점이 나타났다. 카프카 토픽의 데이터가 일정주기로 다시 읽어지는 현상이 나타난 것이다. 토픽으로 새로운 데이터의 유입이 없는것과 다시 읽어지는 데이터가 과거 데이터인것을 확인하는 순간.. '머지 이건?!!'

0.8.1을 사용하는 이전 프로젝트에서는 consumer로 subscription을 하면 점검, 장애의 이유가 아니라면 브로커와 연결을 지속한 형태로 구현했는데, 이번에는 컨슈머가 짧은주기로 subscription, unsubscription을 반복하는 구성이 다른점이다.

현상만으로 보면 어떤 이유에서 컨슈머그룹의 offset 정보가 초기화 되는것 같았고 이를 토대로 코드와 카프카 설정을 몇 번을 리뷰했지만 특이사항을 찾지못하고 수일이 흘렀다. 한가지 특이사항이라면 offset이 리셋되는 주기가 일정한듯 한 현상이 보였다.

주말에 StackOverflow에서 카프카 관련주제를 검토하다가 드디어 해결의 단초를 찾았다.
결국 작성한 코드의 이슈는 아니고.. 0.9버전부터 변경된 오프셋 관리방식(0.8.x까지는 주키퍼가, 0.9부터는 카프카측에서 관리)과 새 버전 카프카 브로커  설정 기본값으로 인한 현상이었다.
키워드는 브로커 설정의 offsets.retention.minutes. 기본값이 1440분, 즉 24시간 유지라네...  0.10 문서 충분히 읽고 검토했다고 생각했는데... 이런 중요한 설정을 놓쳤을 줄은 상상도 못했다.

이와 관련한 이슈와 메일링 리스트
https://issues.apache.org/jira/browse/KAFKA-3806
https://mail-archives.apache.org/mod_mbox/kafka-dev/201606.mbox/%3CJIRA.12976894.1465398960000.46560.1465511841061@Atlassian.JIRA%3E
2016/08/02 09:18 2016/08/02 09:18
이 글의 관련글
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

MSSQL jdbcType javaType 매핑 정보

myBatis 로 개발 시 간혹 입출력 변수의 javaType 이나 jdbcType을 명시해 줘야 할 때가 있다.
이럴 때 참고하기위해 기록 해 둠.
참고로, myBatis의 jdbcType enum 정의는 http://www.mybatis.org/mybatis-3/apidocs/reference/org/apache/ibatis/type/JdbcType.html 에서 확인 가능.

https://msdn.microsoft.com/ko-kr/library/ms378878(v=sql.110).aspx
SQL Server 형식 JDBC 형식(java.sql.Types) Java 언어 형식
bigint BIGINT long
binary BINARY byte[]
bit BIT boolean
char CHAR String
date DATE java.sql.Date
datetime TIMESTAMP java.sql.Timestamp
datetime2 TIMESTAMP java.sql.Timestamp
datetimeoffset(2) microsoft.sql.Types.DATETIMEOFFSET microsoft.sql.DateTimeOffset
decimal DECIMAL java.math.BigDecimal
float DOUBLE double
image LONGVARBINARY byte[]
int INTEGER int
money DECIMAL java.math.BigDecimal
nchar CHAR

NCHAR(Java SE 6.0)
String
ntext LONGVARCHAR

LONGNVARCHAR(Java SE 6.0)
String
numeric NUMERIC java.math.BigDecimal
nvarchar VARCHAR

NVARCHAR(Java SE 6.0)
String
nvarchar(max) VARCHAR

NVARCHAR(Java SE 6.0)
String
real REAL float
smalldatetime TIMESTAMP java.sql.Timestamp
smallint SMALLINT short
smallmoney DECIMAL java.math.BigDecimal
text LONGVARCHAR String
time TIME(1) java.sql.Time(1)
timestamp BINARY byte[]
tinyint TINYINT short
udt VARBINARY byte[]
uniqueidentifier CHAR String
varbinary VARBINARY byte[]
varbinary(max) VARBINARY byte[]
     
varchar VARCHAR String
varchar(max) VARCHAR String
xml LONGVARCHAR

LONGNVARCHAR(Java SE 6.0)
String

SQLXML
2016/07/25 09:26 2016/07/25 09:26
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

output parameter not allowed as argument list prevents use of rpc

2016/06/29 14:50

서비 JAVA

jTDS Driver + OUTPUT 파라메터가 있는 + Stored Procedure 를 호출하는 경우 발생할 수 있는 데이터 바인딩 이슈.
jTDS Driver 의 경우 OUTPUT 파라메터가 있는 SP 를 수행할 때 RPC 방식을 이용하여 실행 성능 향상을 꾀하는데…
이 때는 SP 의 모든 변수는 바인딩 변수를 사용해야 하며, { call sp_name ( ?, ?, ‘value’, ? , ? OUTPUT ) } 처럼 
바인딩 변수와 값 직접 할당을 동시에 기술 할 수 없습니다.

공식 문서에는 혼용해서 사용은 가능하지만 그렇게 할 경우 RPC모드가 아닌 프로시저 일반실행 모드로 동작한다고 기술되어 있지만, 실제는 output parameter not allowed as argument list prevents use of rpc 익셉션이 발생하는 경우가 있음...
이건 DBMS나 JDBC 접속 설정에 따라 달라지는것 같긴한데... 거기까진 확인 못했음.
2016/06/29 14:50 2016/06/29 14:50
이 글의 관련글
    이글의 태그와 관련된 글이 없습니다.
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

apache kafka, zookeeper 재기동 후 Unexpected exception, exiting abnornally java.io.EOFException 발생.

정기 점검으로 인해 운영중인 카프카/주키퍼를 재기동했더니  Unexpected exception, exiting abnornally java.io.EOFException 이 발생하면서 브로커가 정상적으로 동작을 하지 못하는 현상이 발생하였다.
원인은 Disk Full로 주키퍼의 트랜젝션 파일을 온전히 저장하지 못해서 발행하는 것이었다.

다음과 같은 조치를 통해 정상화 할 수 있다.

우선 카프카용 주키퍼의 데이터 경로 [KAFKA_HOME]/zookeeper-data/version2 에서
$ ls -lat 
명령으로 가장 최근에 만들어진 로그와 스냅샷 파일을 확인한 후
사이즈가 0이거나 마지막에 작성된 로그를 삭제하고 재기동하면 된다.

후속조치로는 [KAFKA_HOME]/logs 아래에 빼곡히 들어차 있는 controller.log , server.log, state-change.log 들을 주기적으로 삭제하는 스크립트를 만들고 크론으로 등록했다.
http://heyo.net/xe/prog_tip/1984(새 창으로 열기)
 #!/bin/sh
 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
  
 cd [KAFKA_HOME_PATH]/logs
 find ./* \( -name 'controller.log.*' -o -name 'server.log.*' -o -name 'state-change.log.*' \) -mtime +30 -exec rm -f {} \;
 find ./* \( -name 'controller.log.*' -o -name 'server.log.*' -o -name 'state-change.log.*' \) ! -name '*.Z' -mtime +7 -exec compress {} \;
 




2016/06/03 13:27 2016/06/03 13:27
이 글의 관련글
    이글의 태그와 관련된 글이 없습니다.
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

PoolingHttpClientConnectionManager 를 xml기반 Spring bean으로 등록하기.

개발한 서비스 중 commons httpclient 로 서버 <-> 서버 간 rest api 호출하는 부분에  부분에서 간헐적으로 NoHttpResponseException : The target server failed to respond 예외가 발생하기 시작했다. 이를 해결하기위해 자료를 좀 찾아봤더니 HttpClient 4.4에서 존재하던 버그였고 4.4.1에서 해결된 문제( https://issues.apache.org/jira/browse/HTTPCLIENT-1610 )라고 하는데... 개발한 서비스에는 4.5.1을 쓰는데?

현상의 이유는 HTTP/1.1의 Keep-Alive로 인해 httpclient는 통신이 끝난 connection을 종료하지 않고 동일host:port에 대해 동일한 커넥션을 이용하려하기 때문이다.

비록 서버측은 통신이 완료되어 해당 연결을 close 할지라도 client 측은 커넥션 객체가 여전히 열여있고 데이터가 인입되길 기다리고 있게된다.  ( close()의 실제 의미는 소켓의 단절이 아닌 "나는 더 이상 보낼 데이터가 없습니다."로 상대측에서는 해당 커넥션을 단절하지 않는 이상 여전히 데이터가 인입될 수 있음을 의미한다. )
이때를 half-closed connection 으로 표현하며 이는 TCP가 그렇게 동작하게끔 설계되었기 때문으로 버그가 아니다. 이런 상황이 되면 JVM상의 connection 객체는 당연히 살아있지만 내부 소켓은 CLOSE_WAIT 상태가 된다.

문제는 httpclient가 이 CLOSE_WAIT 상태에있는 connection 객체를 다시 사용하려고 할때 앞에서 설명한것과 같이 서버 측은 이미 연결을 끊어버렸기 때문에 NoHttpResponseException - The target server failed to respond 예외를 발생한다.
이를 해결하기위해서는 httpclient의 connectionManager에서 통신이 완료된 connection을 적절하게 제거할 필요가 있다.

Spring 4.X 환경에서 commons HttpClient 4.5.x 를 소켓 설정과 KeepAlive 설정등을 포함하여 xml로 설정하는 방법.

PoolingHttpClientConnectionManager를 통하여 CloseableHttpClient 를 사용하는 과정에 ConnectionManager의 closeIdleConnections 설정 통해 특정시간 idle인 커넥션을 종료하고 싶은 경우 java 코드가 아닌 spring xml 설정정으로 bean을 등록하려 할 때. 

사용은 당연히
@Autowired
private CloseableHttpClient httpClient;

 <!-- ===================================================================== -->
 <!-- =======================   HttpClient 4.5.X   ======================== -->
 <!-- ===================================================================== -->        
 <bean id="requestConfigBuilder" class="org.apache.http.client.config.RequestConfig" factory-method="custom">
         <property name="socketTimeout" value="10000" /> 
         <property name="connectTimeout" value="12000" /> 
         <property name="connectionRequestTimeout" value="12000" />
 </bean>
 
 <bean id="requestConfig" factory-bean="requestConfigBuilder" factory-method="build" />
 
 <bean id="socketConfigBuilder" class="org.apache.http.config.SocketConfig" factory-method="custom">
     <!-- 소켓이 연결된후 InputStream에서 읽을때 timeout -->
     <property name="soTimeout" value="10000" /> 
     <!-- SO_KEEPALIVE를 활성화 할 경우 소켓 내부적으로 일정시간 간격으로 heartbeat을 전송하여, 비정상적인 세션 종료에 대해 감지.
     unix 계열 : /etc/sysctl.conf
     windows : \HKEY_LOCAL_MACHINE\SystemCurrentControlSet\Services\TCPIP\Parameters
     -->
     <property name="soKeepAlive" value="true" /> 
     <!-- 비정상종료된 상태에서 아직 커널이 소켓의 bind정보를 유지하고 있을 때 해당 소켓을 재사용 할 수 있도록 -->
     <property name="soReuseAddress" value="true" /> 
     <!-- nagle 알고리즘 적용 여부 -->
     <property name="tcpNoDelay" value="true" /> 
     <!-- socket이 close 될 때 버퍼에 남아 있는 데이터를 보내는데 기다려주는 시간(blocked)-->
     <property name="soLinger" value="2000" /> 
 </bean>
 
 <bean id="poolingHttpClientConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager" destroy-method="shutdown">
     <constructor-arg value="2000" type="long" index="0" /> <!-- pool에 있는 커넥션 제거 idle time -->
     <constructor-arg value="MILLISECONDS" type="java.util.concurrent.TimeUnit" index="1" />
     <property name="maxTotal" value="60" />
     <property name="defaultMaxPerRoute" value="15" />
     <property name="defaultSocketConfig"><bean factory-bean="socketConfigBuilder" factory-method="build" /></property>
 </bean>
 
 <bean id="connectionKeepAliveStrategy" class="com.http.client.HttpShortKeepAliveStrategy" />
 
 <bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create">            
     <property name="defaultRequestConfig" ref="requestConfig" />
     <property name="connectionManager" ref="poolingHttpClientConnectionManager" />
     <property name="userAgent" value="Mozilla/5.0 (Windows NT 6.1; WOW64) CUSTOM-CLIENT" />
     <property name="keepAliveStrategy" ref="connectionKeepAliveStrategy" />
 </bean>

 <bean id="httpClient" factory-bean="httpClientBuilder" factory-method="build" destroy-method="close" />
 


HttpShortKeepAliveStrategy 클래스는...
 package com.http.client;
 
 import org.apache.http.HeaderElement;
 import org.apache.http.HeaderElementIterator;
 import org.apache.http.HttpResponse;
 import org.apache.http.conn.ConnectionKeepAliveStrategy;
 import org.apache.http.message.BasicHeaderElementIterator;
 import org.apache.http.protocol.HTTP;
 import org.apache.http.protocol.HttpContext;
 
 /**
  * HttpShortKeepAliveStrategy (UTF-8) created : 2016. 5. 25
  *
 
  */
 public class HttpShortKeepAliveStrategy implements ConnectionKeepAliveStrategy {
 
     /**
      *
      * @param response
      * @param context
      * @return
      */
     @Override
     public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
         // Honor 'keep-alive' header
         HeaderElementIterator it = new BasicHeaderElementIterator(
                 response.headerIterator(HTTP.CONN_KEEP_ALIVE));
         while (it.hasNext()) {
             HeaderElement he = it.nextElement();
             String param = he.getName();
             String value = he.getValue();
             if (value != null && param.equalsIgnoreCase("timeout")) {
                 try {
                     return Long.parseLong(value) * 100;
                 } catch (NumberFormatException ignore) {
                 }
             }
         }
 
 
         HttpHost target = (HttpHost) context.getAttribute(HttpClientContext.HTTP_TARGET_HOST);
         if ("www.mydomain.com".equalsIgnoreCase(target.getHostName())) {
             // Keep alive for 5 seconds only
             return 5 * 1000;
         } else {
             // otherwise keep alive for 1 seconds
             return 1 * 1000;
         }
     }
 
 }
 


코드로 표현하면 대강 다음과 같음.
static final CloseableHttpClient httpClient;
 static {
         PoolingHttpClientConnectionManager pooledManager = new PoolingHttpClientConnectionManager(20L,java.util.concurrent.TimeUnit.MILLISECONDS);
         pooledManager.setMaxTotal(15);
         pooledManager.setDefaultMaxPerRoute(5);
         pooledManager.closeIdleConnections(20L, TimeUnit.MILLISECONDS);
         pooledManager.setDefaultSocketConfig(SocketConfig.custom()
                 // nagle 알고리즘 적용 여부
                 .setTcpNoDelay(true)
                 // SO_KEEPALIVE를 활성화 할 경우 소켓 내부적으로 일정시간 간격으로 heartbeat을 전송하여, 비정상적인 세션 종료에 대해 감지.
                 // unix 계열 : /etc/sysctl.conf
                 // windows : \HKEY_LOCAL_MACHINE\SystemCurrentControlSet\Services\TCPIP\Parameters
                 .setSoKeepAlive(true)
                 // socket이 close 될 때 버퍼에 남아 있는 데이터를 보내는데 기다려주는 시간(blocked)
                 .setSoLinger(200)
                 // 비정상종료된 상태에서 아직 커널이 소켓의 bind정보를 유지하고 있을 때 해당 소켓을 재사용 할 수 있도록
                 .setSoReuseAddress(true)
                 //소켓이 연결된후 InputStream에서 읽을때 timeout
                 .setSoTimeout(10000)
                 .build()
         );
         httpClient = HttpClients.custom()
                         .setConnectionManager(pooledManager)
                         .setUserAgent("Mozilla/5.0 (Windows NT 6.1; WOW64) API-CLIENT")
                         .setRedirectStrategy(new DefaultRedirectStrategy() {
                                 @Override
                                 public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) {
                                         boolean isRedirect = false;
                                         try {
                                                 isRedirect = super.isRedirected(request, response, context);
                                         } catch (ProtocolException e) {
                                                 logger.error(null, e);
                                         }
                                         if (!isRedirect) {
                                                 int responseCode = response.getStatusLine().getStatusCode();
                                                 if (responseCode == 301 || responseCode == 302) {
                                                         return true;
                                                 }
                                         }
                                         return false;
                                 }
                         })
                         .setKeepAliveStrategy(new ConnectionKeepAliveStrategy() {
                                 @Override
                                 public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
                                         // Honor 'keep-alive' header
                                         HeaderElementIterator it = new BasicHeaderElementIterator(
                                                         response.headerIterator(HTTP.CONN_KEEP_ALIVE));
                                         while (it.hasNext()) {
                                                 HeaderElement he = it.nextElement();
                                                 String param = he.getName();
                                                 String value = he.getValue();
                                                 if (value != null && param.equalsIgnoreCase("timeout")) {
                                                         try {
                                                                 return Long.parseLong(value) * 100;
                                                         } catch (NumberFormatException ignore) {
                                                         }
                                                 }
                                         }
                                         HttpHost target = (HttpHost) context.getAttribute(
                                                         HttpClientContext.HTTP_TARGET_HOST);
                                         if ("www.mydomain.com".equalsIgnoreCase(target.getHostName())) {
                                                 // Keep alive for 5 seconds only
                                                 return 5 * 1000;
                                         } else {
                                                 // otherwise keep alive for 0.1 seconds
                                                 return 1 * 100;
                                         }
                                 }
                         })
                         .build();
 }
 


2016/05/25 15:28 2016/05/25 15:28
이 글의 관련글
    이글의 태그와 관련된 글이 없습니다.
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. Blog Icon
    개발 김

    해당 글 너무나도 잘 봤습니다!! ㅎㅎ 해결하신 방법은 일정한 타임 아웃을 주고 해당 시간동안 아무런 반응이 없으면 해당 커넥션을 없애는 방식인데 그렇다면 사용자가 잠깐 아무 입력없이 가만히 있게 되면 커넥션이 죽게 될 텐데 이 부분에 대해서는 어떻게 생각하시는지요???

  2. Blog Icon
    서비

    개발 김님 안녕하세요.
    질문 내용은 일반적인 연결 지향인 소켓 상황과 헷갈리신것 같습니다.
    http 역시 소켓에 기반하고있습니다만 아무입력없이 대기 시 커넥션이 죽는
    현상은 일반적인 http 에서는 해당되지 않는 사항입니다.
    http 프로토롤 자체가 필요 시 연결, 데이터 송수신하고 연결을 끊는 컨셉이기 때문입니다.
    keep-alive 는 비교적 짧은 리드타임으로 송수신을 반복할 경우 접속 오버헤드를 줄이고자하는 기법의 하나입니다.

  3. Blog Icon
    개발 김

    너무 감사합니다~ 최근 이부분을 좀 관심있게 보고 있는 중이여서요!!
    HttpShortKeepAliveStrategy 클래스에서
    위에 while문이 어떤 부분을 하는 건가요??
    밑에는 해당 도메인이면 keep alive 시간을 조금 더 주는 건가요??
    직접 이 에러를 발생시켜보고 싶은데 잘 안돼네요 일부러 버전도 4.3.6 쓰는데 close_wait인 커넥션은 자기가 알아서 피해가네요;;

  4. Blog Icon
    서비

    @개발 김님
    링크의 기술문서가 도움이 되지 않을까해서 소개 드립니다.
    http://tech.kakao.com/2016/04/21/closewait-timewait/

Spring Framework 5.0

2017년 이후를 겨냥한 다음 세대 Spring 프레임워크 소식이 들립니다.
프레임워크의 전체 코드를 java 8 기반( lambda , stream api , nio2 등..)으로 작성.
JDK 9 포괄적 지원과 HTTP/2에 집중하며 Spring-style의 reactive 아키텍처를 목표로 개발 진행 중.
5.0 milestone 1 : 2016년 중순
5.0 RC1 : 2016년 12월
최소 사양
JDK 8+, Servlet 3.0+, JMS 2.0+, JPA 2.1+, JUnit 5
주요 기반
JDK 9 과 Jigsaw ( 모듈러 java를 구현하기 위한 java key feature )
Servlet 4.0 과 HTTP/2
Reactive 아키텍처

2016/04/07 14:57 2016/04/07 14:57
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

MSSQL Procedure 변경이력 확인

SELECT * 
FROM sys.sql_modules sm 
inner join sys.all_objects ao 
on sm.object_id = ao.object_id 
order by modify_date desc
 
2016/03/23 14:57 2016/03/23 14:57
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

Executable jar 를 메이븐 exec:exec 로 실행 하기

Executable JAR 빌드 후 메이븐 exec:exec 로 실행하고 싶다면 exec-maven-plugin 을 사용할 수 있다.
<plugin>
   <groupId>org.codehaus.mojo</groupId>
   <artifactId>exec-maven-plugin</artifactId>
   <version>1.4.0</version>
   <executions>
     <execution>
       <id>default-cli</id>
       <goals>
           <goal>exec</goal>
       </goals>
       <configuration>
         <executable>java</executable>
         <!-- optional -->
         <workingDirectory>/tmp</workingDirectory>
         <arguments>
           <argument>-jar</argument>
           <argument>${basedir}/target/${project.artifactId}-${project.version}.jar</argument>
         </arguments>
       </configuration>                        
     </execution>
   </executions>
 </plugin>


mvn exec:exec 가 아닌 mvn exec:java 로 컴파일 output 디렉토리에서 main class를 바로 실행하고 싶다면 다음과 같이 설정한다.
<plugin>
   <groupId>org.codehaus.mojo</groupId>
   <artifactId>exec-maven-plugin</artifactId>
   <version>1.4.0</version>
   <executions>
     <executions>
       <execution>
         <goals>
             <goal>java</goal>
         </goals>
       </execution>
       <configuration>
         <mainClass>com.app.MainClass</mainClass>
         <arguments></arguments>
       </configuration>
     </executions>
   </executions>
 </plugin> 
2016/02/18 14:35 2016/02/18 14:35
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다