블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

Stackdriver profiler

클라우드 컴퓨팅 & NoSQL/google cloud | 2018.04.08 21:44 | Posted by 조대협


Stack driver profiler


조대협 (http://bcho.tistory.com)


얼마전에 구글 클라우드의 모니터링 솔루션인 stack driver에서 profiler 기능이 발표되었다. (https://cloud.google.com/profiler) 

우리가 일반적으로 생각하는 성능 분석을 위한 profiling 도구로, 구글 클라우드 뿐만 아니라, 여러 서버에서 동작하는 Java/node.js/Go 애플리케이션의 성능을 모니터링할 수 있다.(파이썬은 곧 지원 예정)


장점은 코드 수정없이 간단하게 에이전트만 추가함으로써 프로파일러 사용이 가능하고, 프로파일링된 결과를 stackdriver 웹 콘솔에서 바로 확인이 가능하다는 것이다.


JDB등 전통적인 프로파일러가 있기는 하지만 보통 프로파일러가 적용되면, 애플리케이션의 성능이 극단적으로 느려지기 때문에, 운영환경에 적용이 불가능한데, Stack driver profiler의 경우에는 성능 저하가 미비하여 운영환경에도 적용이 가능하다.


"Stackdriver Profiler uses statistical techniques and extremely low-impact instrumentation that runs across all production application instances to provide a complete picture of an application’s performance without slowing it down."


아래는 자바 애플리케이션을 프로파일을 하기 위해서 프로파일러 바이너리를 agentPath에 추가한 형태이다


java \ -agentpath:/opt/cprof/profiler_java_agent.so=-cprof_service=user,-cprof_service_version=1.0.0 \ -jar ./User-0.0.1-SNAPSHOT.jar


아래는 자바 애플리케이션을 프로파일을 하기 위해서 프로파일러 바이너리를 agentPath에 추가한 형태이다

애플리케이션은 http://bcho.tistory.com/1247 에서 사용한 간단한 REST API를 사용하였다.

코드를 실행해서 프로파일링 데이타를 얻고 나면 아래와 같이 구글 클라우드 콘솔에서 프로파일링 결과를 확인할 수 있다.


위의 뷰는 WALL뷰로, 전체 프로그램이 수행되는 중에, 어느 코드가 시간을 얼마나 사용했는지를 프로파일링 해준결과이다.
이 외에도 CPU 시간으로 볼 수 도 있고, 메모리 사용률등 다양한 뷰
대규모 분산 서비스나 MSA 구조에 적합하도록 프로파일 결과를 볼 수 있는 범위를 선택이 가능한데, 상단의 메뉴를 보면 프로파일링 결과를 볼 서비스와, 프로파일 타입 (CPU,WALL:메서드별 실행시간, 메모리 사용률), 그리고 서비스가 배포된 클라우드 존, 서비스 버전 등에 따라서 선택이 가능하다. 아래는 언어별로 지원하는 프로파일 타입이다. 



Profiler의 뷰는 애플리케이션 타입에 상관이 없이 순수 프로그래밍 플랫폼에만 연관된 뷰로만 보여준다.
무슨이야기인가 하면, 보통 웹 애플리케이션은 멀티 쓰레드 타입으로 동작하고, REQUEST가 들어오면 쓰레드가 하나의 요청을 처리하고 빠지는 형태이기 때문에, 쓰레드별로 어떤 메서드가 순차적으로 실행되었는지등의 뷰를 선호하는데, JENNIFER나 오픈 소스 스카우터와 같은 APM (Application Peformance Monitoring)툴이 이러한 뷰를 제공한다. 

위의 샘플을 보더라도, 톰캣서버의 쓰레드들이 대부분 모니터링 될뿐 직접 코딩한 메서드들이 관측 되지는 않는다. (사용자 코드가 적고, 실행시 별로 크게 시간을 소요하지 않는 것도 원인이기는 하지만)

만약에 REQUEST에 대한 메서드별 소요 시간 모니터링 및 병목 구간 확인을 하려면, Stack driver profiler보다는 Stack driver trace를 사용하는 것이 적절하다. http://bcho.tistory.com/1245

그래서 Stack Driver는 성능 모니터링 (APM)제품군을 Trace, Profiler, Debugger 3가지로 묶고 있고, (Debugger는 나중에 시간이 되면 테스트하고 다루도록 하겠다.) 각기 다른 뷰로 상호 보완적인 관점에서 성능 모니터링이 가능하도록 하고 있다.




Classification & Clustering 모델 평가


조대협 (http://bcho.tistory.com)


클러스터링과 분류 모델에 대한 성능 평가 방법은 데이타에 라벨이 있는가 없는가에 따라서 방법이 나뉘어 진다. 사실 클러스터링은 라벨이 없는 데이타에 주로 사용을 하고, 라벨이 있는 경우에는 분류 모델을 사용한다. 클러스터링 모델에 대한 평가는 라벨이 없는 상태에서 클러스터의 응집도등을 평가하는데 대부분 그 정확도가 그리 높지 않기 때문에, 도메인 지식을 가지고 있는 전문가에 의한 휴리스틱한 방식의 평가 방식이 대부분이다.


분류 모델(Classification) 에 대한 모델 평가

라벨이 있는 경우에는 분류 모델에 대한 모델 평가 방법을 사용한다.

Confusion matrix

이진 분류 문제에서 암의 양성과 음성 데이타를 가지고 있는 데이타 가 있다고 하자


만약 모델의 정확도가 100%이면, 양성과 음성 데이타를 100% 잘 구분할것이다. 아래 그림과 같이, 양성으로 분 예측된 영역을 Positive prediction, 음성으로 분리된 영역을 Negative prediction 이라고 한다.


그런데 실제 세계에서는 정확도 100% 모델은 매우 드물고 실제로는 아래 그림과 같이 예측이 되는 경우가 많다.


양성과 음성 데이타가 각각 잘못되는 경우가 있다.

  • 양성인데, 양성으로 제대로 검출된것은 True Positive (TP)

  • 음성인데 음성으로 제대로 검출된것은 True Negative (TN)

  • 양성인데 음성으로 잘못 검출된것은 False Negative (FN)

  • 음성인데 양성으로 잘못 검출된것은 False Positive (FP)


라고 하고 그림으로 표현하면 다음과 같은 그림이 된다.


보통 이를 표로 표시하는데, 다음과 같이 표현이 된다.




P = TP + FN

N = FP + TN


그러면 이 지표를 가지고 무엇을 하느냐? 이 값을 기반으로 다음과 같은 지표들을 계산하여 모델 평가에 사용한다.

Accuracy

가장 대표적으로 사용되는 지표로 전체 데이타중에서, 제대로 분류된 데이타의 비율로


ACC = (TP + TN)  / (전체 데이타 수 = P + N)


모델이 얼마나 정확하게 분류를 하는지를 나타낸다.


Error Rate

Error Rate는 Accuracy 와 반대로, 전체 데이타 중에서 잘못 분류한 비율을 나타낸다


ERR = (FN+FP) / (전체 데이타수 = P+N)


Sensitivity (Recall or True positive Rate)

민감도라고도 하는데, Sensitive 또는  Recall이라고도 하는데, 원래 Positive 데이타 수에서 Positive로 분류된 수를 이야기 한다. 에를 들어 원본 데이타에 암 양성이 100개 있었는데, 모델에 있어서 90개가 분류되었으면, Sensitive Rate = 0.9 가된다.


SN = (TP) / P


모델이 얼마나 정확하게 Positive 값을 찾느냐를 나타낸다.

Recall (as opposed to precision) is not so much about answering questions correctly but more about answering all questions that have answer "true" with the answer "true". So if we simply always answer "true", we have 100% recall.


Precision

Precision (정밀성)은 Positive로 예측한 내용 중에, 실제 Positive의 비율을 뜻한다.


PREC = TP / (TP+FP)


Precision is about being precise. In common English, being precise means: if you give an answer, the answer will very likely be correct. So even if you answered only one question, and you answered this question correctly, you are 100% precise.


Specificity (True negative rate)

Specificity 값은 Negative 로 판단한것중에, 실제 Negative 값의 비율이다.


SP = TN / TN+FP


False Positive rate

원래는 Positive 값인데, 잘못해서 Negative로 판단한 비율로


FPR = FP / N


이 된다. 예를 들어 게임에서 어뷰징 사용자를 검출했을때 정확도도 중요하겠지만, FPR 값이 높으면, 정상 사용자를 비정상 사용자로 검출하는 경우가 많다는 의미가 된다. 어뷰징 사용자에 대해서는 계정 정지등 패널티를 주게 되는데, 모델이 아무리 어뷰징 사용자를 잘 찾아낸다 하더라도 FPR 값이 높게 되면, 정상적인 사용자를 어뷰징 사용자로 판단하여 선의의 사용자가 징계를 받게 되서, 전체적인 게임 충성도에 문제가 생길 수 있다. (어뷰징 사용자를 많이 찾아내는 것보다, 정상 사용자가 징계를 받게 되는 경우가 비지니스에 크리티컬 할때) 이런 경우에 FPR 값을 레퍼런스 할 수 있다.



그러면, Confusion Matrix를 통해서 계산된 결과를 가지고 모델을 어떻게 평가를 할까? 앞에서 나온 지표중에서 일반적으로 Accuracy 지표가 많이 사용되고, 그외에, ROC , Precision Recall Plot, F-Score 등이 많이 사용되는데 각각에 대해서 알아보자

ROC (Receiver Operating Characteristics)

ROC 그래프는 가로축을 FP Rate (Specificity) 값의 비율로 하고 세로축을 TP Rate (Sensitive) 로 하여 시각화 한 그래프이다.


  • Specificity = TN / TN+FP

  • Sensitive (Recall) = (TP) / P




보통 다음과 같은 그래프가 되고



(출처 : http://scikit-learn.org/stable/auto_examples/model_selection/plot_roc.html )


그래프가 위로 갈 수록 좋은 모델이고, 적어도 Y=X 그래프보다 위에 있어야 어느정도 쓸모 있는 모델로 볼 수 있다. 아래 그래프는 3개로 결과를 분류하는 모델에 대한 ROC 그래프 이다.


(출처 : http://scikit-learn.org/stable/auto_examples/model_selection/plot_roc.html )


ROC 그래프가 class 0, class 2, class 1 순서로 높은것을 볼 수 있다. 즉 이 모델은 class 0 을 제일 잘 분류하고 그 다음은 2,1 순서로 잘 분류 한다는 의미가 된다.

ROC는 그래프이기 때문에, 모델을 정확도를 하나의 숫자로 나타내기 어려워서 AUC (Area Under Curve) 라는 값을 사용하는데, ROC AUC값은 ROC 그래프의 면적이 된다. 최대값은 1이 된다. 위의 그래프를 보면 모델 0,2,1의 AUC값은 0.91, 0.79, 0.60 이 된다.

Precision Recall Plot

Precision Recall Plot (이하 PR 그래프)의 경우도 ROC 와 유사한데, 주로 데이타 라벨의 분포가 심하게 불균등 할때 사용한데, 예를 들어 이상 거래 검출 시나리오의 경우 정상 거래의 비율이 비정상 거래에 비해서 압도적으로 많기 때문에 (98%, 2%) 이런 경우에는 ROC 그래프보다 PR 그래프가 분석에 더 유리하다.


PR 그래프는 X 축을 Recall 값을, Y축을 Precision 값을 사용한다.


  • Sensitive (Recall) = (TP) / P

  • Precision = TP / (TP+FP)



다음은 이진 분류 (binary classification)의 PR 그래프의 예이다. 그래프가 위쪽으로 갈수록 정확도가 높은 모델이고, ROC와 마찬가지로 PR 그래프의 AUC (면적)값을 이용하여 모델의 정확도를 평가할 수 있다.



(출처 : http://scikit-learn.org/stable/auto_examples/model_selection/plot_precision_recall.html)


그러면 모델이 쓸만한 모델인지 아닌지는 어떤 기준을 사용할까? ROC 그래프의 경우에는 Y=X 그래프를 기준으로 그래프 윗쪽에 있는 경우 쓸만한 모델로 판단을 했는데, PR 그래프의 경우 Base line이라는 것을 사용한다.


Base line = P / (P+N) 으로 정하는데, P는 데이타에서 Positive 레이블의 수, N 은 전체 데이타의 수이다. 예를 들어 암 데이타에서 암 양성이 300개 이고, 전체 데이타가 700이면 Base line은 300/(700+300) = 0.3 이 된다.  


위의 PR 그래프에 Base line을 적용하여 모델이 좋고 나쁜 영역을 판단하는 그림이다.

아래 그림은 두 모델을 비교한 PR 그래프인데, 두 모델 다 베이스라인을 넘어서 쓸만한 모델이기는 하지만, 모델 A가 B모델보다 확연하게 위에 위치하고 있기 때문에, A 모델이 좋다고 이야기할 수 있다.


(출처 : https://classeval.wordpress.com/introduction/introduction-to-the-precision-recall-plot/)

F-Score

모델의 성능을 하나의 수로 표현할때, ROC나 PR 그래프의 AUC를 사용하면 되지만, AUC를 계산하려면 여러 Throughput에 대해서 Precision, Recall, Specificity 값을 측정해야 한다.

그렇다면 Throughput을 이미 알고 있거나 또는 다양한 Throughput에 대해서 어떤 Throughput이 좋은지를 하나의 수로 모델의 성능을 평가하려면 어떻게 해야할까? 이를 위해서 사용하는 것이 F-Score 라는 값이 있다.


When measuring how well you're doing, it's often useful to have a single number to describe your performance

When measuring how well you're doing, it's often useful to have a single number to describe your performance. We could define that number to be, for instance, the mean of your precision and your recall. This is exactly what the F1-score is.

https://www.quora.com/What-is-an-intuitive-explanation-of-F-score

F Score에 대한 계산은 다음 공식을 이용한다. 큰 의미상으로 보자면 Precision과 Recall에 대한 평균인데, 그냥 평균을 내면, 값의 외곡 현상이 생기기 때문에, 가중치를 주는 평균이라고 이해하면 된다.


특히 β가 1인 경우 (즉 F1)를 F1 Score라고 하고, 모델의 성능 평가 지표로 많이 사용한다.


참고 문서


스파크 성능이 안나오면, 우리 회사 데이타팀 팀장왈. 먼저 파이썬으로 짰는지 확인 부터 해보라길래, 파이썬과 스칼라로 만들어진 스파크 성능 차이가 얼마나 나는지 찾아봤더니 다음과 같은 수치가 나왔다.


http://emptypipes.org/2015/01/17/python-vs-scala-vs-spark/ (원본 출처)


일단 스파크를 할려면 스칼라는 필수인듯 하다. 

간단한 프로토타입핑등에는 파이썬을 사용할 수 있겠지만 결국 프로적션은 스칼라로 최적화해야 할듯.

근데. 자바대 스칼라 성능 비교는 없네

자바스크립트 스터디 노트 #2

프로그래밍/JavaScript | 2014.06.19 16:52 | Posted by 조대협

실습중 코멘트

클래스 내에서 변수

var MyClass = function(){
    var local;                    // 생성자 내에서만 유효
    this.objectvalue;            // 객체 단위로 유효
}
MyClass.prototype.classvalue;    /// 클래스 단위로 유효

text와 html

$(‘#xxx’).html : <BR> 등의 HTML 태그가 반영됨
$(‘#xxx’).text : <BR> 등의 HTML 태그가 문자열로 저장됨 (실제 태그 효과가 없어짐)

JQuery

jqeury 엘리먼트는 생성자에서 객체 변수로 캐슁해서 사용하도록 하는 것이 좋다.

클래스

클내부 변수나 내부 메서드는 _를 사용하거나, _$로 시작하는 것이 좋다.
구글의 자바스크립트 네이밍 컨벤션 참고할것.

자바스크립트 엔진

싱글 쓰레드임을 명시 할것.
콜백은 비동기로 수행된다. 코드 순서대로 수행이 안되기 때문에 주의. 순차 실행이 필요한 경우, 콜백함수내에 정의할것

크롬데브툴

각 기능들에 대해서 간략하게 살펴본다.
자세한 기능은 https://developer.chrome.com/devtools/index

네트워크

헤더, 프리뷰등 리턴값을 볼 수 있고,
필터를 통해서, 헤더,바디,XHR등 특정 부분들만 보는 것도 가능하다.

소스

로딩된 자바스크립트나, CSS등을 볼 수 있다.
중요한 기능 - 소스 파일을 수정해서 반영해서 볼 수 있다. 서버에 있는 소스일지라 할지라도 가능. ADD Folder to workspace 라는 기능을 이용해서 브라우져에서 에디트해서, 추가할 수 있음. (내소스코드와 서버쪽 소스코드를 맵핑/일치 시킬 수 있다.)
디버깅하는 기능이 있음-보통 console.log로 디버깅하는데, 소스에서는 직접 소스를 봐서, 여기서 브레이크 포인트를 걸어서, 일반적인 IDE의 디버거처럼 사용할 수 있다. 브레이크 포인트를 걸때, 오른쪽 마우스 버튼을 누르면 conditional break point를 걸 수 있다. (변수나 특정 조건에 따를때만 브레이크를 거는 기능)
브레이크포인트에 걸렸을때, console에서 console.log 등을 이용해서 값들을 추척해볼 수 있다.

※ Snippet - 코드 조각을 저장하는 기능

엘리먼트

엘리먼트창에서 오른쪽에서 >= 메뉴를 누르면 에뮬레이션이라는 기능이 있음, 폰 종류를 골라서, 폰 형태에 맞춰서 보여줄 수 있음. (중요한 기능. )

타임라인

녹화 버튼을 누르면, 서버와 통신한 기록 내용을 볼 수 있음.
메모리 사용 기록 등

프로파일

CPU,메모리 힘등을 자세하게 프로파일링이 가능함
메모리 릭등을 잡을 때 사용이 가능함. (스냅샷을 여러개 찍어서, 스냅샷등을 비교할 수 있는 기능이 있음)

리소스

웹 SQL,Index SQL등을 살펴볼 수 있음.

Audit(감사)

페이지가 어떤 부분이 안좋다, 문제가 있다는 부분을 자동으로 검출해서 리포트를 출력해줌.
비슷한 기능으로 페이지 스피드라는 플러그인이 있음 (구글에서 만들어짐. )

콘솔

다양한 기능들이 있음. 단순히 console.log 를 찍는 출력이 아니라
CLI 명령을 사용할 수 도 있음.

console.time('111');
console.timeEnd('111');

00.000ms 단위까지 출력해준다. (자바스크립트는 일반적으로 ms 단위 측정만 가능한데, console은 더 미세한 측정이 가능함)

자바스크립트 라이브러리

www.jsdb.io에 들어가면 자바스크립트 라이브러리들이 잘 정리되어 있음.(분류가 잘 되어 있음)

  • 에니메이션 : 모바일에서는 3.js 정도가 유행. 특별하게 주류가 없음 보통 jquery 애니메이터를 사용함
  • 애플리케이션 툴 :
    • Angular.js,Ember,Backbone 들이 MVC 성격,
    • underscore는 유틸성으로 많이 씀.
    • underscore를 좀 더 빠르게 만든게 로우대쉬라는게 있음
    • 템플릿 엔진. Handlebar등 종류가 많음 . 템플릿 엔진은 코드와 뷰를 분리하는 관점에서 거의 필수이다.. 주로 성능이 선택 요소가 됨. (컴파일 방식이 빠름)
    • requirejs : 모듈화 툴
    • Q : Promise 패턴을 구현해놓았음. (async, callback hell등 처리) - 중첩 콜백을 간소화해서 코딩이 가능함.-
  • 오디오 : 사운드 메니져
  • 개발툴 :
    • Bower 유명은 한데, 실제로 적용하기가 어렵다. (패키지 정보등을 개인이 올리는게 아니기 때문에 )
    • JSHint 정적 검사툴 (Strict 하게 검사됨. 오류가 아닌것도 오류로 검색한다.)
    • Grunt 빌드도구
    • Jasmine 테스트
  • DOM 핸들링
    • JQuery : 가장 강력함.
    • Prototype : 도태됩
    • BootStrap : 많이 쓰는 UX
  • 이미지
    • Three JS 3D에서 유명함

자바크립트 테스팅

Jasmine,QUnit,Mocha 등이 사용됨.
Mocha는 Mocha 단독만으로는 안씀. (다른 라이브러리와 섞어 쓰는게 추세, 어떤 라이브러리?) NPM 랭킹으로는 Mocha가 더 높음
※ 자바스크립트 문서와 도구는 JSDOC을 많이 사용함

정적 검사

JSLint (이게 더 스트릭트), JSHint
실제 프로젝트에는 JSHint가 더 적용하기 좋음. 반드시 실제 프로젝트에서는 사용하도록 하자

최적화

자바스크립트도 느리다. IE8 같은것을 해보면, 느리다. 최적화가 필요하다.

Reflow

비용이 크다. (리플로우를 최소화해야 한다.)
개념을 잡을려면 유투브에서 reflow 라는 이름으로 동영상을 찾아보면 실제 화면을 렌더링 하는 동영상들이 있음.
: 화면이 렌더링 되는 과정 주로 언제 발생되냐?

  • 화면에 표시되는 구성요소의 크기,위치,표시 방법등이 변경되는 경우들과 같이 스타일을 지정하거나, 또는 스타일 값을 가져올때

    obj.style.width=
    obj.style.height=

  • 화면에 객체가 추가 제거되는 경우
  • 스크롤과 관련

어떻게 조심 하냐?

  • 객체 추가제거 : 하나씩 append하는게 아니라, body.innderHTML=”문자열” 같이 한방에 추가한다. 효과가 매우 좋음 단 실제로 객체단위로 관리가 안됨
  • documentFragment : 객체 단위로 관리를 하기 위해서 화면에 표시 되지 않는 껍데기 document를 만들어놓고, 사용함 (innerHTML 방식이 더 빠름)

    document.createDocumentFragment

  • CSS 변경 : 화면에 적용되기 전에 element를 만들어서 붙임
    예제 sudo code
    var obj = createElement()
    obj.style.width=xx
    obj.style.width=xx
    document.addElement(obj)
    
  • 캐쉬 : 속성들의 값을 가지고 오는 것을 줄이기 위해서, 캐쉬를 이용하는 방법을 쓰자. DOM 접근 비용도 크다. Parent element를 캐슁하는 것도 방법. 그 dom 까지 찾아가는 시간 까지도 줄일 수 있음.
  • CSS 변경 : 스타일 룰 방식(CSS Rule) : (자세한것은 찾아볼것)
  • CSS 클래스를 잘 활용
    ※ jsPerf라는 사이트를 이용하면, before, after의 코드 성능을 비교해볼 수 있다.
  • HTML collection은 배열처럼 보이지만, Collection은 문서에 정의된 순서대로 변환하기 위해서 그때 마다 DOM 파싱이 발생한다. 대층 객체 목록을 반환하는것 childNode, getElementByTagNames() 등등
  • CSS selector
    • 선택자는 오른쪽에서 왼쪽으로 탐색한다.
    • 선택자는 구체적이기 보다는 간단하게 하는게 더 좋다. (구체적이면 구체적으로 나열한거 다 찾는다.)
    • 아이디는 엘리먼트를 찾는 가장 빠른 방법이다.
    • 검색 범위는 줄여주는게 좋다.

자주 하는 실수

  • HTML element가 로드 되기 전에, javascript가 로드 되어서, 엘리먼트를 참조하는 사례 —> 자바스크립트를 HTML이 로딩된 다음에 로딩 되도록 <script> 태그를 body 아랫부분에 넣으면 됨

box2d 라는 물리 엔진
네이버의 collie라는 게임,에니메이션용 엔진이 있음

Single Threaded Model이라서 더 빠르다? No.!!


Vert.x나 Node.JS와 같은 Single Threaded 모델의 서버들이 내세우는 장점이, Single Thread Model이기 때문에, Context Switching이 없고, 이로 인해서 성능이 더 빠르다. 라는 논리인데, 사실 DB나 File IO가 있을 경우, 뒷단의 Thread Pool에 request & call back 형식으로 처리를 하고 있기 때문에, 이 경우에는 Single Thread Model이 아니라 Multi Thread Model이 되고, 이 Thread Pool들의 Thread로 인한 Context Switching이 발생하게 된다.


이런 IO Call이 없는 경우 (Thread Pool로 작업을 보내지 않는 경우), 당연히 Context Switching 부하가 없기 때문에 빠르겠지만, DB 작업이 들어 갈경우,  http://www.techempower.com/benchmarks/#section=data-r8&hw=i7&test=query

의 자료를 보면, 오히려 Servlet이 더 빠른걸 볼 수 있다.


servlet-raw : resin + mysql

nodejs-mysql : nodejs + mysql



출처 : http://www.techempower.com/benchmarks/#section=data-r8&hw=i7&test=query

Disk나 DB 작업이 비교적 적은 메세징 등에서는 node나 vert.x가 메리트가 있겠지만, 일반적인 DB,FILE TX에서는 역시 WAS가 더 효율성이 높다.


Amazon S3 (Simple Storage Service)

AWS S3 (Simple Stoage Service)는 파일을 저장하기 위한 스토리지이다. 일반적인 파일시스템의 개념과는 약간 다르고, 파일 이름을 대표하는 key와 파일 자체로 구분되는 Object Storage이다.

용량 저장할 수 있는 파일의 크기는 개당 1byte~5TB이고, 총 저장 용량에는 제한이 없다. 디렉토리와 비슷한 개념으로, bucket이라는 개념을 가지고 있다.

기본적으로 3 copy를 지원하여, 데이타를 복제하고, 이 복제는 Amazon availability zone (AZ) 단위로 복제가 되기 때문에 데이타 센터 장애에 대한 대응성을 가지고 있다. region 간 복제는 지원하지 않는다. 복제에 관련된 옵션으로는 RRS (Reduced Redundancy Storage)라는 것이 있는데, 이 옵션을 적용하면, 2 copy (원본 + 백업)만을 저장하기 때문에, 가격이 훨씬 더 저렴하다. 3 copy를 저장할 경우, S3에 대한 데이타 신뢰도는 99.999999999% 보장하고, 서비스에 대한 가용성은 99.99% 보장한다.

S3에 접근하기 위한 인터페이스는 일반적은 file io api등은 사용할 수 없으며, REST/HTTP 기반의 프로토콜만 지원한다. 그래서, 성능이 다른 파일 시스템에 비해서 느리다.

그 외에 기타 부가적인 기능들을 살펴 보면 다음과 같다.

     Retaining 기능 : 다른 주목할만한 기능 은 retain 기간을 지정할 수 있다. 즉 파일의 저장 기간을 지정할 수 있고, 그 기간이 지나면 자동으로 삭제가 된다.

     Versioning : 저장된 파일에 대해서 여러 버전을 저장 및 관리할 수 있다. 참고로 이전 버전으로 저장된 파일 역시 똑같이 과금 되기 때문에, 금액 부분에 대해서 신경을 쓰기 바란다.

     Encryption : S3는 상당히 다양한 형태의 암호화를 지원한다. HTTPS를 이용한 전송단의 암호화에서 부터, Server에서 저장될때 암호화를 적용할 수 있으며, Client에서 전송할때나 받을때, 암호화된 형태로 데이타를 주고 받을 수 있다.

타 시스템과 연동 관점에서 S3 서비스는 AWS 내에서 대용량 데이타를 저장하기 가장 알맞은 저장소이다. 그래서 다른 AWS의 서비스 (EMR CloudFront, Glacier )에 자연스럽게 연동될 수 있는 기능을 제공하며, 다른 서비스들과 상호보완적인 관계를 갖는다. 예를 들어 SQS와 같은 큐 서비스에는 큰 객체(파일)을 저장할 수 없기 때문에 이벤트 메세지는 SQS에 저장하고, 실제 큰 파일은 S3에 저장해서 레퍼런스를 하던가, Dynamo와 같은 NoSQL DB도 레코드당 데이타 한계로 인해서, 메타 데이타는 Dynamo에 저장하고, 파일과 같은 큰 바이너리 데이타는 S3에 저장하고 레퍼런스를 하게 할 수 있다.


Partitioning

S3를 사용하면서 데이타의 양이 늘어나게 되면 성능이 떨어지게 되는 것을 체감할 수 있다.

S3는 내부적으로 여러개의 파일을 저정하기 위해서 물리적으로 파일을 여러개의 디스크에 분할 저장하는데, 이 분할 하는 로직을 파일명을 가지고 해쉬를 사용한다. 그래서 파일명이 유사하게 되면, 같은 파티션(디스크)에 파일이 써지기 때문에, 하나의 파티션에 많은 물리적인 IO를 유발하고 결과적으로 성능이 떨어지게 되는 것이다.

S3는 파일명을 가지고 hashing을 하여 파일을 분산 저장한다고 했다. 더 정확하게 이야기 하면 파일명의 앞부분인 prefix를 가지고 분산 키로 사용한다.

즉 예를 들어 파일명이

server.2012-12-31

server.2012-12-30

server.2012-12-29

server.2012-12-28

과 같이 앞의 prefix가 같다면, 파일은 같은 파티션에 저장될 가능성이 많다.

그래서 앞의 file prefix를 다양한 이름으로 바꿔 주는 것이 좋다.

예를 들어 일정 디렉토리 (디렉토리명으로도 파티셔닝이 된다.)로 다음과 같이 구분한다

a/server.2012-12-31

b/server.2012-12-30

c/server.2012-12-29

d/server.2012-12-28

위와 같은 구조를 취하면, 최소 4개 파티션에 분할 저장된다.

또는 위의 파일명의 경우 맨 마지막이 날짜로 rotation되는 형태이기 때문에, 다음과 같은 파일명으로 저장해도 파티셔닝 효과를 볼 수 있다.

13-21-2102.server

03-21-2102.server

92-21-2102.server

S3에서 내부적으로 어떤 원리로 partitioning을 하는지는 정확하게 나와 있지 않다. 단지 prefix를 이용한다고만 나와 있는데, 최소한 파일명(또는 디렉토리명)을 다른 문자로 시작하게 하면, 골고루 파티션에 분산하여 저장할 수 있다고 가이드 하고 있다.

최소한 50 TPS 이상의 S3 IO를 요구할 경우에는 파티션을 권장하고 있다.

     참고 : http://aws.typepad.com/aws/2012/03/amazon-s3-performance-tips-tricks-seattle-hiring-event.html

이 키 기반의 파티셔닝은 단지 S3 뿐만 아니라, NoSQL이나 HDFS와 같은 분산 파일 시스템에도 동일한 원리로 적용되기 때문에 반드시 참고하기 바란다.


Bucket의 위치에 대해서

성능 관련해서 가장 기본적인 부분인데, 많이 실수하는 부분이 S3 Bucket을 만들때 애플리케이션과 다른 Region Bucket을 만드는 경우가 있는데, 이 경우 성능 저하가 매우 심하게 발생한다.

Bucket을 만들때는 반드시 같은 애플리케이션이 실행되는 region과 반드시 같은 region을 사용하도록 한다.

http://blog.takipi.com/2013/03/20/aws-olypmics-speed-testing-amazon-ec2-s3-across-regions/

문서를 참고해보면, region간의 평균적인 속도가 나오니 참고하기 바란다



Multipart uploading

S3에는 파일을 업로드 할때, multipart uploading이라는 기능을 제공한다. ( http://aws.typepad.com/aws/2010/11/amazon-s3-multipart-upload.html )

파일을 하나의 Connection에서 쭈욱 올리는 것이 일반적인 방법이라면



파일을 여러개의 블럭으로 나눠서 동시에 여러개의 Connection을 통해서 업로드 하는 방법이다. 이 경우 업로드가 Parallel하게 이루어지기 때문에 상당 부분의 성능 향상을 가지고 올 수 있다.



또 다른 장점은 큰 파일 하나를 여러개의 블럭으로 나눠서 전송하기 때문에, 만약에 전송중에 특정 블럭 전송이 실패하면, 전체 파일을 재 전송할 필요가 없이 실패한 특정 블럭만 다시 전송하면 된다. multipart 업로드 기능을 구현은 SDK 형태로 재공되는 라이브러리를 사용하면 된다.

http://docs.aws.amazon.com/AmazonS3/latest/dev/uploadobjusingmpu.html

아마존 가이드에서는 100MB 이상의 파일 전송시에 권장하고 있는데, 사용해본 결과 꼭 100MB가 아니더라도 그 이하의 크기의 파일 전송에서도 충분한 성능 증가를 볼 수 있으니, 대규모의 업로드를 사용하는 경우 single upload vs multipart upload 성능을 테스트해보고 결정하기를 권장한다.

 

사용법이 매우 간단한 서비스이기는 하지만, 쉽고 안전하며, 데이타 저장소로써 필수적인 기능등은 거의 다 갖추고 있으며, 저렴한 가격에, 다른 서비스와 연계성이 높기 때문에, 필히 익혀둬야 하는 서비스이다. S3를 이용한 시스템 설계시에는 일반 파일 시스템과 같은 형태로 접근을 하면 안된다. HTTP 형식으로 접근을 하기 때문에, 성능이 그만큼 나오지 않는다. 이 부분에 대한 고려만 충분히 하면 AWS에서 EC2 다음으로 가장 가치가 높은 서비스가 아닐까 싶다.

매우 기본적인 부분인데, 함정(?)이 있어서 메모해놓습니다.


aws에서는 S3 버킷을 만들때 위와 같이 Region을 정할 수 있습니다.

그런데 US Standard라는 Region이 있는데, 이는 실제 존재하는 region이 아닙니다. Oregon이나 Ireland와 같이 실제 S3가 배포될 region을 명시적으로 정하는 것이 좋습니다. (특히 미국의 경우..)

EC2를 US West Oregon에서 사용하실거면, 반드시 S3도 같은 Region에 생성을 해야 속도가 빠릅니다.


http://blog.takipi.com/2013/03/20/aws-olypmics-speed-testing-amazon-ec2-s3-across-regions/


문서를 보면 region가 S3 속도가 나옵니다.



Tomcat 7.0 Parameter Tuning

성능과 튜닝/WAS 튜닝 | 2013.03.01 00:51 | Posted by 조대협

server.xml

--

<?xml version='1.0' encoding='utf-8'?>

<Server port="8005" shutdown="SHUTDOWN">

  <!-- Security listener. Documentation at /docs/config/listeners.html -->

  <Listener className="org.apache.catalina.security.SecurityListener" checkedOsUsers="root" /> root 사용자로 start 하지 못하게 함

  <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->

  <Listener className="org.apache.catalina.core.JasperListener" />

  <!-- Prevent memory leaks due to use of particular java/javax APIs-->

  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> 메모리 leak detector

  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />


  <!-- Global JNDI resources

       Documentation at /docs/jndi-resources-howto.html

  -->

  <GlobalNamingResources>

    <!-- Editable user database that can also be used by

         UserDatabaseRealm to authenticate users

    -->

    <Resource name="UserDatabase" auth="Container"

              type="org.apache.catalina.UserDatabase"

              description="User database that can be updated and saved"

              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"

              pathname="conf/tomcat-users.xml" />

  </GlobalNamingResources>


  <Service name="Catalina">


    <Connector port="8080" 

protocol="org.apache.coyote.http11.Http11Protocol" BIO 사용

acceptCount="30" back log를 30으로 제안

enableLookups="false" DNS 사용 금지. 

compression="off" 압축 금지 (REST 사용 및 Mobile 고려)

                connectionTimeout="10000" Connection time out 10초

maxConnections="8192" 

maxKeepAliveRequests="1"

maxThreads="100"

tcpNoDelay="true"

               redirectPort="8443" />

    <Engine name="Catalina" defaultHost="localhost">

      <Realm className="org.apache.catalina.realm.LockOutRealm">

        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"

               resourceName="UserDatabase"/>

      </Realm>


      <Host name="localhost"  

   appBase="webapps" <!-- /bin/apps/ -->

            unpackWARs="true" 

   autoDeploy="false">


        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"

               prefix="localhost_access_log." suffix=".txt"

               pattern="%h %l %u %t &quot;%r&quot; %s %b" />


      </Host>

    </Engine>

  </Service>

</Server>


--

Context에서 auto reload 부분 제외 해야 하고..
dbcp connection pool 튜닝 필요 --> dbcp 말고 tomcat pool 사용
context.xml에 설정
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
               maxActive="100" maxIdle="30" maxWait="10000"
               username="javauser" password="javadude" driverClassName="com.mysql.jdbc.Driver"
               url="jdbc:mysql://localhost:3306/javatest"/>

애플리케이션 배포를 쉽게 하기 위해서, 위의 Context.xml은 war/META-INF/context.xml을 사용하는게 좋음


shared lib 처리 필요
JVM은 -server -Xms1024m -Xmx1024m -XX:NewSize=384m -XX:PermSize=128m + ParallelGC, GCThread=3, +PrintGCDetial
디렉토리 처리 (1 server , 1was를 기준으로 함)
tomcat 설치는 /usr/local/tomcat
JVM은 /usr/local/jvm
application은 /applications/war/
log는 /applications/log/access.log catalina.out 기타 application logs
기타 스크립트는 /applications/scripts
설정 파일 /appllications/properties

아니면
/product/j2ee/jdk
/product/j2ee/tomcat

/applications/j2ee/war
/applications/j2ee/logs
/applications/j2ee/scripts
/applications/j2ee/properties

아니면
/product/tomcat
/product/jdk
/product/tomcat7 (link)
/product/jdk1.6 (link)
/applications/tomcat/war
/applications/tomcat/logs/access.log, catalina.out
/applications/tomcat/scripts/deploy/fabfile
/applications/tomcat/scripts/logbackup/fabfile
/applications/tomcat/properties

boot up시 최신 war 파일을 repository에서 읽어오는 부분 추가

튜닝 하려면 한 2일 걸리겠네...




스크립트


from boto.s3.connection import S3Connection

from boto.s3.key import Key

import time


startime=time.time()


conn = S3Connection(XXX','XXX')


bucket = conn.create_bucket('terry-s3-performance-test')

for i in range(1,100):

k = Key(bucket)

k.key = "logfile%s" % i

k.set_contents_from_filename('logfile origin')

conn.close()

endtime = time.time()


print 'Elaped time %s'% (endtime-startime)

 


위의 스크립트를 멀티프로세스로 돌려서 테스트 해본 결과

16K 파일 기준으로 (클라이언트는 같은 region에 ec2에서 수행), 클라이언트당 15TPS 정도가 나옴. 클라이언트(프로세스)수를 늘려도, 개당 15TPS가 일정하게 유지됨. 아마도 QoS를 보장하는 기능이 있는듯함



Amazon RDS 성능은 물리 서버의 30% 정도일 뿐!

Amazon RDS에서 DB 테이블 재구성하는 이슈가 있어서 물리 장비 테스트 후 

Amazon RDS에 적용한 적이 있습니다. 사용하고 있는 Amazon RDS 인스턴스가 성

능이 나쁘지 않은만큼 물리 장비 대비 크게 뒤쳐지지 않을 것이라고 예상을 했습니다.

그러나, 실제 적용해본 결과, 물리 서버 대비 30%정도 퍼포먼스만 발휘하는 결과가 

나왔습니다. 로컬 물리 DB에서 15분 걸리던 작업이, Amazon RDS에서는 45분 이상 

소요가 된 사례가 있습니다. 예상 시간보다 상당히 오래 걸려서 크게 당황을 했었죠.

무엇보다 MySQL은 단일 쓰레드에서 Nested Loop 방식으로 SQL을 처리하기 때문

에, CPU의 성능이 전체적인 DB 퍼포먼스에 직접적인 영향을 미칩니다. 병렬 처리가 

없다는 MySQL 특성이 Amazon RDS에서 가장 큰 병목이 되는 것입니다.


http://dev.kthcorp.com/wp-content/uploads/2012/11/H3_2012_double_sided.pdf

403페이지 내용中

MongoDB 깜빡 잊고 있었다. Read / Write 성능이 빠를 수 밖에 없다는 걸..
Mongo는 Write시에, Memory에 먼저 Write후에, 1분 단위로 Flushing하는 Write Back 방식을 쓴다. 즉 메모리에만 쓰면 되니까는 Write가 무지 빠르다. 반대로 Read시에는 파일의 Index를 메모리에 로딩해놓고 찾는다(memory mapped file). 이러니 성능이 좋을 수 밖에, 단 Flushing전에 Fail이 되면 데이타 유실에 의해서 Consistency 가 깨지는 문제가 발생하고, Configuration 구조상 메모리 사용량이 많으며, 확장성에 제약이 있다.
특히 Write 구조에서는 비동기 식으로 Write를 하기 때문에 Disk 성능에 덜 Sensitive하다. 즉 이 말은 DiskIO성능이 상대적으로 낮은 클라우드에서 더 잘돌아간다는 이야기.

이에 비해서 Cassandra(같은 Dynamo 계열인 Riak도 마찬가지) 는 Write Back이나 Memory Mapped file을 사용하지 않기 때문에 MongoDB에 비해서 성능이 낮을 수 밖에 없다. 더군다나, Write나 Read시 1개 이상의 Node에서 값을 읽거나(R Value) 쓰기 때문에(W Value) Consistency가 mongoDB에 비해서 나으며, 당연히 확장성도 더 높다.

즉 확장성+일관성 vs 성능간의 Trade Off 구조다.
 
한국 내 정도 서비스 할 수준이라면 걍 mongo가 났겠네.. 대규모 서비스라면 Cassandra 고민해봐야 할듯 하고.

새로운 GC Collector G1.

성능과 튜닝/JVM | 2009.04.20 13:12 | Posted by 조대협
재미있는 소식이 있어서 포스팅합니다.
JDK 1.6 update 14에 G1이라는 형식의 Garbage collector가 추가됩니다.
기존에 CMS (Concurrent mark and sweep)과 는 다르게, Compaction을 사용하며, 특히 주목할만한 것은 Large Memory에서 latency time을 극소화 했다는 것입니다.
 쉽게 풀어서 설명하자면, 이제 GC 시간 때문에 대용량 Heap을 사용하지 못하는 일이 없어진다는 것입니다. 애플리케이션이 메모리에서 많이 자유로워 지는 것이지요...

 물론 뚜껑을 열어봐야 알겠지만, CMS옵션도 1.4에 release되어 1.5에는 꽤나 쓸만한 모습을 갖춘만큼. G1 Collector도 앞으로 많은 기대가 됩니다.

참고

'성능과 튜닝 > JVM' 카테고리의 다른 글

VisualVM을 이용한 JVM 모니터링  (0) 2013.09.05
G1GC Collector  (0) 2009.04.22
새로운 GC Collector G1.  (1) 2009.04.20
JVM 튜닝  (5) 2008.03.12
Sun JVM HeapDump 얻기  (1) 2007.11.28
-XX:PretenureSizeThreshold  (0) 2007.11.10
TAG g1, gc, JVM, Performance

Java File Writing 성능 비교

성능과 튜닝/자바 성능팁 | 2009.03.31 17:39 | Posted by 조대협
JAPM을 업그레이드 할까 싶어서 Log Writing 부분을 개선하고자 해서
File Writing을 어떻게 하는 것이 제일 빠를까 테스트를 해봤다.
크게 아래 케이스인데.

1. FileWriter fw = new FileWriter(LOG_HOME+"writer.log");
2. BufferedWriter bw = new BufferedWriter(new FileWriter(LOG_HOME+"writer.log"));
3. FileOutputStream fos = new FileOutputStream(LOG_HOME+"outputstream.log");
4. BufferedOutputStream fos =  new BufferedOutputStream(new FileOutputStream(LOG_HOME+"bufferedoutputstream.log"));
5. FileChannel fc =(new FileOutputStream(new File(LOG_HOME+"filechannel.log"))).getChannel(); + Byte Buffer 매번 생성
6. FileChannel fc =(new FileOutputStream(new File(LOG_HOME+"filechannel.log"))).getChannel(); + ByteBuffer 재사용

테스트의 정확성을 위해서 측정중에 GC가 발생하지 않도록 NewSize와 HeapSize를 크게 해놓고 테스트를 하였다. Vm 옵션은 -XX:NewSize=480m -ms768m -mx768m -verbosegc 이다.
환경 : Windows XP, Sun JVM 1.5, Centrio VPro Dual core, IBM Thinkpad X61s

결과는 다음과 같다.
   1K  2K  5K  10K  50K  
 FileWriter  31  32  94 203  1281  
 FileWriter + BufferedWriter  15  31  94  188  1000  
 FileOutputStream  32 47  109  188  1063  
 FileOutputStream + BufferedOutputStream  31  47  109  203  1578  
FileChannel  47  63  109  219  2906  
FileChannel + Byte Buffer 재사용 31 47 188 250 2766

(해당 레코드를 1000번씩 write)

예상하기로는 NIO의 FileChannel이 가장 빠를것이라 생각했는데, 의외로 FileWrite와 FileOutputStream의 성능이 높게 나왔다. NIO의 경우 JVM 벤더에 종속성이 있겠지만 이런 결과가 나오는것은 약간 의외였다.
 오히려 프로그래밍 기법을 내서 FileChannel을 사용할 경우 최대 3배까지 성능이 나쁜 경우가 올 수 있으니. 이런건 차라리 모르는게 나을 수 도 있겠다~~ 싶다.. ^^

BufferedWriter등의 경우 GC를 유발하는 문제가 있을 수 있기 때문에 또 다른 성능 저하 요인이 될 수 는 있겠지만, 현재까지 테스트 결과로는 Windows Platform에서는 FileWriter + BufferedWriter의 경우가 성능이 제일 좋은것 같다.
아래는 테스트에 사용한 소스 코드
==
package bcho.filewriter.test;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import junit.framework.TestCase;

public class FileWriterTest extends TestCase {
final static int loop = 1000;
final static String LOG_HOME="c:/temp/";
static String LOG_STRING="";
static {
}
public void testSuite() throws Exception{
int stringSize[]={100,200,500,1000,5000};
for(int i=0;i<stringSize.length;i++){
LOG_STRING="";
for(int j=0;j<stringSize[i];j++) LOG_STRING+="1234567890";
log(stringSize[i]+"0 bytes");
testFileWriter();
System.gc();
testBufferedWriter();
System.gc();
testFileOutputStream();
System.gc();
testFileBufferedOutputStream();
System.gc();
testFileChannel();
System.gc();
testFileChannelOneBuffer();
System.gc();
}
}
public  static void log(String str){
System.out.println(str);
}
// java.io.FileWriter
private void testFileWriter() throws Exception {
FileWriter fw = new FileWriter(LOG_HOME+"writer.log");
long st = Timer.getCurrentTime();
for(int i =0;i<loop;i++){
fw.write(LOG_STRING);
}
log("FileWriter :"+Timer.getElapsedTime(st) +"ms");
fw.close();
}
// java.io.BufferedWriter
private void testBufferedWriter() throws Exception {
BufferedWriter bw = new BufferedWriter(new FileWriter(LOG_HOME+"writer.log"));
long st = Timer.getCurrentTime();
for(int i =0;i<loop;i++){
bw.write(LOG_STRING);
}
log("BufferedWriter :"+Timer.getElapsedTime(st) +"ms");
bw.close();
}
// java.io.FileOutputStream
private void testFileOutputStream() throws Exception{
FileOutputStream fos = new FileOutputStream(LOG_HOME+"outputstream.log");
long st = Timer.getCurrentTime();
for(int i=0;i<loop;i++){
byte[] buf = LOG_STRING.getBytes();
fos.write(buf);
}
log("FileOutputStream :"+Timer.getElapsedTime(st) +"ms");
fos.close();
}
// java.io.FileOutputStream
// + java.io.BufferedOutputStream
private void testFileBufferedOutputStream() throws Exception{
BufferedOutputStream fos = 
new BufferedOutputStream(
new FileOutputStream(LOG_HOME+"bufferedoutputstream.log"));
long st = Timer.getCurrentTime();
for(int i=0;i<loop;i++){
byte[] buf = LOG_STRING.getBytes();
fos.write(buf);
}
log("FileBufferedOutputStream :"+Timer.getElapsedTime(st) +"ms");
fos.close();
}
private void testFileChannel() throws Exception {
FileChannel fc =(new FileOutputStream(new File(LOG_HOME+"filechannel.log"))).getChannel();
long st = Timer.getCurrentTime();
for(int i=0;i<loop;i++){
byte[] buf = LOG_STRING.getBytes();
ByteBuffer bytebuffer = ByteBuffer.allocate(buf.length);
bytebuffer.put(buf);
bytebuffer.flip();
fc.write(bytebuffer);
}
log("FileChannel  :"+Timer.getElapsedTime(st) +"ms");
fc.close();
}
private void testFileChannelOneBuffer() throws Exception {
FileChannel fc =(new FileOutputStream(new File(LOG_HOME+"filechannelonebuf.log"))).getChannel();
int BUF_SIZE=1000;
long st = Timer.getCurrentTime();
ByteBuffer bytebuffer = ByteBuffer.allocate(BUF_SIZE);
for(int i=0;i<loop;i++){
byte[] buf = LOG_STRING.getBytes();
int offset=0;
int length= buf.length;
while(offset < length){
int chunkSize = BUF_SIZE > length-offset ? length-offset-1 : BUF_SIZE;
bytebuffer.put(buf, offset, chunkSize);
bytebuffer.flip();
offset+=BUF_SIZE;
fc.write(bytebuffer);
bytebuffer.clear();

}
}
log("FileChannel with reusing buffer:"+Timer.getElapsedTime(st) +"ms");
fc.close();
}


}


'성능과 튜닝 > 자바 성능팁' 카테고리의 다른 글

Java File Writing 성능 비교  (8) 2009.03.31
이번에는 앞에서 설명한 Aspect J와 JMX를 이용하여 초간단 APM을 만들었습니다.
JAPM (Java Application Performance Monitor)
상용 APM 툴 설치하기 어렵거나, 간단하게 Tracing하고 싶을때 사용하시면 됩니다.
소스코드와 설치 메뉴얼등을 첨부합니다.

JMX를 이용하여 Thread 별 CPU 시간을 측정하는 방법

==
 ThreadMXBean mbThread = (ThreadMXBean) ManagementFactory.getThreadMXBean();
 
 long[] ids = mbThread.getAllThreadIds();
 for (long id: ids)
 {
  System.out.println(mbThread.getThreadInfo(id).getThreadName());
  System.out.println(" CPU Time(" + id+ ")" + mbThread.getThreadCpuTime(id));
  System.out.println(" User Time(" + id+ ")" + mbThread.getThreadCpuTime(id));
 }

==
AOP에서 before에서 자기 Thread의 CPU 시간을 저장한후 after에서 다시 측정하여 결과를 빼면 해당 메서드의 CPU  사용 시간을 측정할 수 있다.

참고 : 단위는 nano second ( /1000,000 = milisecond)