반응형

[ jQquery ] jQuery(제이쿼리) 플러그인으로 쿠키 다루기


자바스크립트로도 쿠키를 control할 수 있으나~! jQuery Plugin을 이용하면 훨씬 더 직관적으로 쉽게


쿠키를 컨트롤 할 수 있다.


# 자바스크립트로 쿠키의 특정값을 가져오는 경우


# jQuery Plugin을 사용해서 쿠키 특정값을 가져오는 경우



위에서 보듯 자바스크립트를 이용할 때보다 jQyery를 이용하는 방법이 훨씬 직관적이면서 쉬운것을 볼 수 있다.



사용방법


* cdn으로 jquery.cookie.js를 import해준다. (당연히 jQuery는 import되어 있어야겠죠?) 소스코드를 받아 프로젝트에 내장하는걸 권장

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script>


위의 스크립트를 import해주면 플러그인의 기능을 손쉽게 사용할 수 있다.


[ 쿠키저장 ] - 쿠키는 브라우저가 열려 있는 동안만 유지

$.cookie('key', 'value');


[ 쿠키만료일 지정 ] 

$.cookie('key', 'value', {expires: 값});


[ 쿠키삭제 ] - 특정도메인이 있는 쿠키의 값인 경우 도메인을 명시해주지 않으면 제대로 삭제되지 않는다. 

* expires기간을 오늘 이전 날짜로 셋팅해주면 자동으로 지워진다.

* 쿠키 설정시 domain과 path를 설정했을 경우 삭제시에도 동일하게 옵션으로 전달해야 삭제가능

$.cookie('BID', '', {domain : "toast.com", expires: new Date(2016, 10, 29, 11, 00, 00)});

혹은 다음처롬도 삭제 가능하다.

$.removeCookie('BID', {path: '/',domain: 'toast.com'});


[ 특정시간만료시 삭제 & secure를 true로 설정시 https를 통해서만 쿠키값을 전송가능하다 ] 

$.cookie(visits, 10, {expires: new Date(2019, 10, 29, 11, 00, 00), secure: true});


자바스크립트를 사용하든 jQuery플러그인을 선택하든 선택은 자유:)

반응형
반응형

스프링부트(SpringBoot) 순차적 방식과 비동기처리(asyn애노테이션), Completablefuture와 성능 비교

Spring Boot 기반의 웹 애플리케이션은 HTTP 요청이 들어왔을 때 내장된 서블릿 컨테이너(Tomcat)가 관리하는 독립적인 1개의 Worker 쓰레드에 의해 동기 방식으로 실행된다. 하지만 요청 처리 중 @Async가 명시된 메써드를 호출하면 앞서 등록한 ThreadPoolTaskExecutor 빈에 의해 관리되는 또 다른 독립적인 Worker 쓰레드로 실행된다. 
별도의 쓰레드로 동작하기에 원래의 요청 쓰레드는 그대로 다음 문장을 실행하여 HTTP 응답을 마칠 수 있다.


배경

리얼환경에서의 서비스를 위해 실제 환경(l4 - API서버 3)에서 어느정도의 트래픽을 안전하게 처리할 수 있는지에 대한 산정 필요(서버 도입 시점 등)'

해당 테스트는 단순 select로직을 통한 테스트로 참고 부탁드립니다.

메서드 내에서 여러 곳으로부터의 데이터를 받아와 처리하는 작업이 있는 경우 async애노테이션, CompletableFuture를 사용한 방식이 훨씬이

성능상 훨씬 많은 이점을 가져다 줄 수 있습니다. 

테스트 로직

기존로직

기존로직.png

변경로직 (@Asyn 애노테이션과 CompletableFuture를 통한 비동기 처리)

변경로직.png

쿼리 (위 : 변경쿼리, 아래 : 기존쿼리)

쿼리.png

성능측정

L4장비에 트래픽 부하(gatling) - 부하 툴로는 gatling을 사용하였습니다. 무료로 사용할 수 있는 툴로 쉽게 사용하실 수 있습니다.

1. Request : 9000, Duration 10초  - TPS 300

기존 로직
cm_9000_1.pngcm_9000_2.png

변경로직

asyn_9000_1.pngasyn_9000_2.png

2. Request : 24000, Duration 10초  - TPS 800

기존로직                                                                 변경로직(ThreadPool - 200)                                변경로직(ThreadPool - 400)


ThreadPool설정값 조정

스프링부트를 사용할 경우 별도 application.properties에 server.tomcat.max-threads 다음설정을 해주지 않는 경우

기본 max-thread의 개수는 200개가 된다. (The default value for max-threads is 200)

따라서 400으로 올려서 테스트 진행


스레드의 개수를 600으로 두고 테스트를 했을 떄는 다음과 같은 에러가 발생했다.

[java.util.concurrent.ThreadPoolExecutor@18da28a1[Running, pool size = 741, active threads = 741, queued tasks = 200, completed tasks = 207]] did not accept task: java.util.concurrent.CompletableFuture$AsyncSupply@47ff8bc8] with root cause

java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.CompletableFuture$AsyncSupply@47ff8bc8 rejected from java.util.concurrent.ThreadPoolExecutor@18da28a1[Running, pool size = 741, active threads = 741, queued tasks = 200, completed tasks = 207]

        at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)

        at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)


3. 결론

1번 테스트(TPS 300) 결과를 보면 Asyn annotation과 Completablefuture를 사용한 쪽이 응답 속도가 훨씬 안정적으로 처리되는 것을 볼 수 있다.(99th percentile 기준)
2번 테스트 결과(TPS 800)를 봤을 때 1/3 정도의 요청이 fail나는 것을 확인 할 수 있었고 TPS 800 은 요청에 대한 fail비율과 응답속도(100ms 이내를 기준으로 한다)로 보았을 때 서버 3대로 처리할 수 있는 요청량이 아니라는 판단을 할 수 있다.
그 이후 TPS 400, 500, 600 700으로도 테스트 한 결과 안정적
(최대 50ms - 광고 비지니스 특성상)이내로 ADX, DSP에 값을 전달하기 위해서는 
최대 TPS 300을 기준으로 운영방침을 가져갈 수 있을 것 같다.

TPS 300 -> 한 서버당 하루요청량 2500만을 기준으로 둘 수 있겠다. 

(물론 카산드라 3.0에 데이터가 유입량과 로직 추가에 따른 부분을 항상 염두해 두어야 할 것이다.)



추가적으로, 비동기방식으로 처리를 했을 때 메모리, cpu사용률이 더 높은 것을 확인 할 수 있었다.

무작정 비동기방식이 좋다고 말할 수도 동기 방식이 좋다고도 말하기 힘들 것 같다.

단순한 작업은 동기 방식 한 메서드 내에서 순차적으로 이루어지지 않아도 되는 작업이 여러 개 있는 경우(DB호출, 외부 API호출 등)이 있는 경우에는

비동기 방식이 성능상 이점을 가져다 줄 수 있을 것이다.

반응형
반응형

 

일반적으로는 리눅스에서 빌드를 하는 경우가 많이는 없다.

 

보통은 git과 jenkins를 통해 빌드 배포하고 있기 때문에 하지만 내가 가지고 있는 프로젝트중에

 

hadoop mapreduce작업을 해서 cassandra에 밀어 넣는 처리를하는 경우가 있다.

 

이 경우 hadoop관련 jar파일이 필요한데 pom.xml  dependency 경로가 서버내의 cloudera경로에 걸려있어 

 

서버내에서 maven 빌드를 진행해주어야만 하는 경우가 있었다.(물론 해당 jar파일을 공통 레파지토리나 프로젝트내에 넣어 묶을 수 있긴한데...)

 

먼저 리눅스에서 maven 빌드를 실행하려면 서버에 maven이 깔려있는지 확인이 필요한다.

 

 

> mvn -v

 

깔려있지 않다면 먼저 maven 설치가 필요하다.

 

그리고 빌드를 해서 jar파일을 만들고자하는 프로젝트 경로로 이동해서 pom.xml이 위치한 곳에서 

 

mvn package를 실행해주면 된다. (profile이나 다른 옵션을 주는 경우 해당 명령어에 -P 등을 추가해주자)

 

 

> mvn package (pom.xml이 위치하고 있는 곳에서)

 

 

이렇게 빌드를 하게되면 필요한 dependency들을 다운받아와 jar를 만드는 것을 확인할 수 있다.

 

 

 

반응형

'Programming > Maven' 카테고리의 다른 글

mvn package시 test 코드 건너뛰기  (0) 2018.01.31
MAVEN과 ANT 비교  (0) 2017.05.10
반응형


톰캣(tomcat)의 기본포트가 8080인 이유를 아시나요???


많은 분들이 WAS로써 톰캣(tomcat)을 사용하실텐데요. 


특히나 요즘은 스프링부트로 인한 임베디드 톰캣을 사용하실줄로 압니다.


톰캣도 그렇고 스프링부트의 임베디드 톰캣도 그렇고 그럼 왜 기본 디폴트 포트는 8080이냐???하는 의문이 생길 수도 있는데요...(저는 그랬습니다...)


간단히 설명을 드리자면 리눅스나 유닉스는 1024이하의 포트(well-known port)들은 일반 유저 권한에서 바인딩 할 수 없도록 되어 있습니다.


이유는 보안때문인데요~!



8080포트에 대한 특별한 이유는 없습니다. 그저 1024이상의 포트중 하나를 임의로 디폴트로 설정한 것 일뿐(이라고 저는 생각합니다.)


하지만 외부 서비스를 해야하는경우에는 80포트로의 접근이 필요한 경우가 있습니다.


단순히 naver.com:8080이라고 사용자들이 접속하게 된다면 불편할테니까요...


그래서 루트권한(sudo)로 톰캣 포트를 80으로 설정 후 어플리케이션을 기동시켜서 사용할 수 는 있습니다.


다만! 위에서 말씀드렸듯 보안 문제가 존재합니다.


애드센스 자동삽입 광고


톰캣서버는 구동시에 tomcat 유저 권한으로 구동되게 됩니다. 때문에 톰캣을 통해 서비스되는 웹을 통해 해킹이 되더라도


tomcat유저 권한에 해당하는 부분까지만 접근 가능하게 됩니다.


따라서 루트권한(sudo)로 80포트로 구동시키게 된다면 해킹당했을 경우보단 안전하다고 할 수 있습니다.




물론 이런 문제를 회피하는 방법은 iptables를 통한 포트포워딩 방식이나 WAS앞단에 웹서버(apache, nginx)를 둬서 해결할 수 있지만


저 경험상에 의해서 iptables를 통해 포트포워딩을 할 경우 문제가 있었던 경험이 있기에 톰캣 80포트 8080 포트로 포워딩 이슈 


앞단에 웹서버를 두시고 서비스하는 방법이 좋다고 생각합니다.

반응형
반응형


리눅스에서 openjdk 업그레이드 하기!!!


1. 자바 버전 확인

$ java -version


2. 설치 가능한 openjdk 버전 확인

$ yum list java*jdk-devel



3. 설치고자하는 버전을 확인 후 설치

$ yum install -y java-1.8.0-openjdk-devel.x86_64


나의 경우에는 설치하고 java -version 명령어를 통해 확인했을 때 잘 업그레이드 된 걸 확인할 수 있었다.



혹시 바뀌지 않은 경우 다음과 같이 바꾸도록 하자.

$ /usr/sbin/alternatives --config java



해당 명령어를 쳐서 원하는 버전의 번호를 선택해주면 된다~!!!!



반응형
반응형

Column count doesn't match value count at row 1 메세지가 발생한다면


DB에 insert하는 데이터의 개수와 컬럼의 개수가 일치하는지 확인해보시길~



; bad SQL grammar []; nested exception is java.sql.SQLException: Column count doesn't match value count at row 1

at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:99)

at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)

at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)

at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)

at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73)

at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)



반응형
반응형

보통 웹서비스에서 포트를 두 개 사용하는 경우는 http, https를 사용하는 경우이다.


보통은 ssl작업은 앞단에 웹서버(apache, nginx)를 두지 처리하는데 springboot만으로도 처리가 가능하다.


application.properties에 server.port=8080을 설정해두고 


추가로 8082 포트를 사용하고자 하면 다음과같이  ConfigurableEmbeddedServletContainer에


Connector에 추가로 사용하고자 하는 포트(port)를 설정해 셋팅해주면 된다.




이렇게 설정하고 실행시켜서 테스트해보면


localhost:8080, localhost:8082로 모두 서비스를 사용할 수 있다.


어떻게 언제 사용하냐고????


보통은 http, https 처리하는 경우, 그 외에는 사실 잘모르겠다...

반응형
반응형


Java8 Stream을 사용하다 보면 자주 발생할 수 있는 미묘한 실수 중에 하나는


이미 사용했던 Stream을 다시 사용하려고 하는 것이다. Stream은 오직 한 번만 사용할 수 있다.


Stream should be operated on (invoking an intermediate or terminal stream operation) only once. 


A Stream implementation may throw IllegalStateException if it detects that the Stream is being reused.


이미 사용했던 Stream을 또 사용하게 될 경우 다음과 같은 에러 로그를 발견할 수 있을 것이다.


java.lang.IllegalStateException: stream has already been operated upon or closed

at java.util.stream.AbstractPipeline.sourceStageSpliterator(AbstractPipeline.java:279)

at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)

at com.payco.cm.service.CacheService.cachingPartnerUrlMap(CacheService.java:31)

at com.payco.cm.service.CacheService$$FastClassBySpringCGLIB$$d06ada09.invoke(<generated>)

at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)

at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)

at org.springframework.cache.interceptor.CacheInterceptor$1.invoke(CacheInterceptor.java:52)

at org.springframework.cache.interceptor.CacheAspectSupport.invokeOperation(CacheAspectSupport.java:344)

at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:407)

at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:326)

at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)

at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)



[ 문제가 발생했던 코드 ]



코드를 보면 Stream을 두 번 사용하고 있는 것을 볼 수있다.


로깅기능으로 잠깐 보려고 했던 코드가 문제가 되었다.


정리하자면

Stream shoud be used only Once!!!


반응형
반응형

[ Spring ] 문제해결 no suitable constructor found, can not deserialize from Object value 


API로 JSON 데이터 받아와 모델에 매핑시키는 부분에서 다음과 같은 에러가 발생하였다.


org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not construct instance of beomcess.coin.contractor.entity.Bittrex$BittrexCoin: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)

 at [Source: java.io.PushbackInputStream@423b2b62; line: 1, column: 41] (through reference chain: beomcess.coin.contractor.entity.Bittrex["result"]->java.util.ArrayList[0]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of beomcess.coin.contractor.entity.Bittrex$BittrexCoin: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)

 at [Source: java.io.PushbackInputStream@423b2b62; line: 1, column: 41] (through reference chain: beomcess.coin.contractor.entity.Bittrex["result"]->java.util.ArrayList[0])

at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:240)

at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:225)

at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:95)

at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:655)


쉽게 말해 API 응답으로 받아와 JSON 데이터가 내가 매핑하고자 하는 Model에 알맞지 않다는 것이다...


API호출 결과 날아오는 JSON의 형태는 다음과 같았다.



내가 받고자 했던 JAVA MODEL의 형태는 다음과 같았다.


문제는 Result Array 내부에 있는 데이터들을 매핑해 오지 못해생겼던 것 같다.



일단 해결은 내부의 BittrexCoin 클래스에 static을 선언해 해결하였다.



이렇게 inner class를 static으로 변경하고 나니 정상적으로 데이터를 받아 올 수 있었다.


static 지시사의 역할은 메소드나 변수를 메모리에 로딩해서 다른 클래스가 이 클래스의 인스턴스를


생성하지 않고서도 사용할 수 있게 해주는 목적이다. 


RestTemplate으로 요청을 날리면서 동시에 내가 원하는 모델에 매핑해서 데이터를 가져오는데 static을 선언해주지 않았을 경우에


inner class인스턴스를 못만들어내서 매핑이 되지 않는 것 같다. 더 정확한 원인까지는 잘 모르겠다...


나중에 시간되면 더 파고들어볼만한 이슈인 것 같다.


혹시 원인에 대해 아시는분이 계시다면 댓글남겨주시면 감사하겠습니다. 







반응형

+ Recent posts