Ace-T's Blog 내 검색 [네이버 커넥트 이웃 합니다~^-^/ 요청 大 환영~~]

Spring Boot + Spring Batch 분석_01

OpenSource/Spring Batch 2018.10.12 15:51
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T


주저리 

   spring boot를 사용하여 
   spring batch를 해보려는데 막상 spring batch를 잘모르면 제대로 못할것 같은 생각이 들었다.
   springframework를 spring boot기반으로 해볼때도 마찬가지였다.


구성

  • Job과 Step으로 구성.
    • Job
      • 여러개의 Step으로 구성.
        • Step은 ItemReader, ItemProcessor, ItemWriter의 구조이거나 
          이런 전형적인 구조가 아닐 경우 Tasklet 구조.

분석

    2018/09/12 - [OpenSource/Spring Batch] - SpringBatch 예제

    에서 처럼 https://spring.io/guides/gs/batch-processing/
   공식 사이트를 살펴보도록 하자.


org.springframework.boot:spring-boot-starter-batch 디펜던시는 요녀석!

Batch Job을 구성할 때 
Spring Batch는 따로 작성할 필요없이 비즈니스 로직에 집중할 수 있도록 많은 유틸리티를 제공한다.


BatchConfiguration! 이부분은 옛날 Spring Batch에서 xml로 구성되던 녀석이다.

@Configuration
@EnableBatchProcessing
public class BatchConfiguration {


하나하나씩 보도록 하자. 우선 Factory를 DI 하는 것을 볼수 있다.

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

Factory는 Job과 Step에서 사용!
// tag::jobstep[]
    @Bean
    public Job importUserJob(JobCompletionNotificationListener listener, Step step1) {
        return jobBuilderFactory.get("importUserJob")
            .incrementer(new RunIdIncrementer())
            .listener(listener)
            .flow(step1)
            .end()
            .build();
    }

    @Bean
    public Step step1(JdbcBatchItemWriter<Person> writer) {
        return stepBuilderFactory.get("step1")
            .<Person, Person> chunk(10)
            .reader(reader())
            .processor(processor())
            .writer(writer)
            .build();
    }
    // end::jobstep[]


그리고 Step에서 사용되어지는 reader, processor, writer도 함께 구성.

    // tag::readerwriterprocessor[]
    @Bean
    public FlatFileItemReader<Person> reader() {
        return new FlatFileItemReaderBuilder<Person>()
            .name("personItemReader")
            .resource(new ClassPathResource("sample-data.csv"))
            .delimited()
            .names(new String[]{"firstName", "lastName"})
            .fieldSetMapper(new BeanWrapperFieldSetMapper<Person>() {{
                setTargetType(Person.class);
            }})
            .build();
    }

    @Bean
    public PersonItemProcessor processor() {
        return new PersonItemProcessor();
    }

    @Bean
    public JdbcBatchItemWriter<Person> writer(DataSource dataSource) {
        return new JdbcBatchItemWriterBuilder<Person>()
            .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
            .sql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)")
            .dataSource(dataSource)
            .build();
    }
    // end::readerwriterprocessor[]


구조는 이러하고..이제 조금 더 자세하게 보도록 하자.

More and More


BatchConfiguration.java

  1. @Configuration : 설정 파일임을 알려준다. @MVC에서 @service @controller와 같다고 보면 된다.
  2. @EnableBatchProcessing : Batch 관련 유용한 유틸을 제공가능케 한다. 영어 고대로 Enable하겠다는 뜻.
  3. 위에서 언급한 내용처럼 Factory를 DI 하여 Job과 Step을 구성한다.
    1. Job은 Step으로 구성하여 만들어지고 Step은 reader, processor, writer를 구성할 수 있다.
  • 어노테이션 @Autowired로 DI 해주는 부분.
    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;
  • Job과 Step을 설정 해주는 부분.
    @Bean
    public Job importUserJob(JobCompletionNotificationListener listener, Step step1) {
        return jobBuilderFactory.get("importUserJob")
            .incrementer(new RunIdIncrementer())
            .listener(listener)
            .flow(step1)
            .end()
            .build();
    }

    @Bean
    public Step step1(JdbcBatchItemWriter<Person> writer) {
        return stepBuilderFactory.get("step1")
            .<Person, Person> chunk(10)
            .reader(reader())
            .processor(processor())
            .writer(writer)
            .build();
    } 
    • Job은 아래와 같이 importUserJob이라는 함수명을 가지며, 파라미터로는 listener, step
    • return으로는 JobBuilderFactory를 이용하여 Job을 리턴하는 구조이다.
      • jobBuilderFactory.get은 job builder를 생성하고 JobRepository를 초기화 시킨다.

[ Spring Batch 흐름도]

         

      • 아래를 좀 더 심화있게 이해하려면 builder pattern을 이해해야한다. 
      • 하지만 우선적으로 Spring Batch에 대해서 파악하는게 우선이다. 
      • 이제 돌아와서 incremeter를 보자.
        • JobBuilderHelper Class에 속해있는 method이다. 
        • JobBuilderHelper는 JobBuilder의 부모 클래스이다.
        • 포맷은 아래와 같다.
          • public B incrementer(JobParametersIncrementer jobParametersIncrementer)
          • 파라미터로 JobPrametersIncrementer를 가지는데 이것은 Interface 형태이다.
          • 이 Interface를 구현한 녀석이 위에 사용되어진 RunIdIncrementer Class 이다.
        • 그리고 incrementer 이녀석이 하는 역할은 JobParametersIncrementer 인터페이스의 
          역할을 보면 알수 있다. JobParameters를 취득하기 위한 인터페이스이기 때문이다.
        • JobParameters..! 이녀석을 이해하려면 아래의 그림을 이해해야한다.
        • 동시 다발적으로 돌아가는 Job들의 차이는 어떻게 알수가 있나? Job들 간의 구별? 그 해답은 JobParameters에 있다. 그래서 batch job을 시작할 때 이처럼 JobParameters를 취득한다.
          더욱 더 자세한 내용은 해당 링크를 참조. 

           

        • 그 다음으로 listener.
          • JobBuilderHelper Class에 속해 있는 Method이며, format은 아래와 같다.
            public B listener(JobExecutionListener listener)
          • JobExecutionListener도 Interface이며 지금 설명하는 소스에서는 
            JobCompletionNotificationListener Class에서 extends하고 있다.
          • JobCompletionNotificationListener.java
            package hello;
            
            import org.slf4j.Logger;
            import org.slf4j.LoggerFactory;
            import org.springframework.batch.core.BatchStatus;
            import org.springframework.batch.core.JobExecution;
            import org.springframework.batch.core.listener.JobExecutionListenerSupport;
            import org.springframework.beans.factory.annotation.Autowired;
            import org.springframework.jdbc.core.JdbcTemplate;
            import org.springframework.stereotype.Component;
            
            @Component
            public class JobCompletionNotificationListener extends JobExecutionListenerSupport {
            
            	private static final Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class);
            
            	private final JdbcTemplate jdbcTemplate;
            
            	@Autowired
            	public JobCompletionNotificationListener(JdbcTemplate jdbcTemplate) {
            		this.jdbcTemplate = jdbcTemplate;
            	}
            
            	@Override
            	public void afterJob(JobExecution jobExecution) {
            		if(jobExecution.getStatus() == BatchStatus.COMPLETED) {
            			log.info("!!! JOB FINISHED! Time to verify the results");
            
            			jdbcTemplate.query("SELECT first_name, last_name FROM people",
            				(rs, row) -> new Person(
            					rs.getString(1),
            					rs.getString(2))
            			).forEach(person -> log.info("Found <" + person + "> in the database."));
            		}
            	}
            }
          • 위의 소스는 job이 BatchStatus.COMPLETED인가에 대해서 listen하고 있다. 그리고나서 JdbcTemplate를 사용한다.
        • 다음으로 flow.
          • JobBuilder Class에 속해 있는 Method이며, format은 아래와 같다.
            public JobFlowBuilder flow(Step step)
            딱 봐도 job과 step의 연결 & 수행. return으로는 a SimpleJobBuilder.
        • 다음으로 end. 즉, builder를 종료.
        • 다음으로 build() : 호출하여 최종적으로 a job builder를 리턴. 

지금까지 Job 관련 내용들을 살펴 보았습니다.

다음 포스팅에서는 비즈니스 로직을 당담하고 있는 Step에 대해서 알아보도록 하겠습니다.



'OpenSource > Spring Batch' 카테고리의 다른 글

Spring Boot + Spring Batch 분석_01  (0) 2018.10.12
SpringBatch 예제  (0) 2018.09.12
MyBatisPagingItemReader를 사용할 때 유의점  (0) 2015.10.02
Spring Batch 환경 셋팅  (0) 2012.09.03

acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

SpringBatch 예제

OpenSource/Spring Batch 2018.09.12 17:32
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T

스프링배치 버전이 낮아서 이참에 스프링부트+스프링배치로 변경해보려고 한다.

"라스트 제다이"가 아닌 "라스트 스프링" ㅋㅋ 

설명에 앞서 주저리를 하자면..요즘 스프링 관련 업무가 없어서..너무 뒤쳐진거 같다..ㅜ.ㅜ..마지막 남은 스프링인가? ㅋㅋ 


예제는 아래 사이트를 참고
  - https://spring.io/guides/gs/batch-processing/ 


결과는 아래와 같다.


위 사이트 내용을 요약해서 보면

간단한 배치 서비스를 만들껀데
이 서비스는 csv파일의 데이터를 가져와서 입맛에 맞게 변경 한 뒤 데이터베이스에 저장하는게 목표이다.

정형적인 배치서비스를 축약한 내용의 소스인것 같아서 선택했다.

데이터를 수집해서 변경 후에 데이터베이스에 저장(insert) or 변경(update)하는 style이 되겠다.

위 소스를 위해서 필요한것은


src/main/java/hello/Person.java  : 데이터를 저장&전달하는 DTO.

src/main/java/hello/PersonItemProcessor.java : 데이터 가공 하는 부분.

src/main/java/hello/BatchConfiguration.java : input / prossessor / output ,  job과 step을 설정 

src/main/java/hello/JobCompletionNotificationListener.java : 배치 완료 후 노티 




'OpenSource > Spring Batch' 카테고리의 다른 글

Spring Boot + Spring Batch 분석_01  (0) 2018.10.12
SpringBatch 예제  (0) 2018.09.12
MyBatisPagingItemReader를 사용할 때 유의점  (0) 2015.10.02
Spring Batch 환경 셋팅  (0) 2012.09.03

acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

mac os에서 kafka-console-consumer 사용하기

OpenSource 2017.09.13 14:23
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T



kafka install

brew로 인스톨 해준다.
brew install kafka

명령어를 날리려는데 셋팅 된 위치를 모르겠다..ㅋㅋ

위치는 요기!!
/usr/local/Cellar/kafka/0.11.0.0/bin


명령은!

./kafka-console-consumer --zookeeper xxx.xxx.com:1111/acet-kafka --topic ace-taeha


끝~

'OpenSource' 카테고리의 다른 글

mac os에서 kafka-console-consumer 사용하기  (0) 2017.09.13
mesosphere  (0) 2017.04.28

acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

kibana 잘 안띄워 진다면? 확인해보면 좋다!

OpenSource/ElasticSearch 2017.08.28 16:55
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T


로컬이 아닌 서버에 kibana를 다운 받고 run을 한 뒤!

웹브라우저로 접근을 하려는데..접근이 fail...

# Specifies the address to which the Kibana server will bind. IP addresses and host names are both valid values.

# The default is 'localhost', which usually means remote machines will not be able to connect.

# To allow connections from remote users, set this parameter to a non-loopback address.

server.host: "0.0.0.0" 

원인은 server.host가 주석처리가 되어있었는데 default가 localhost라서..접근이 안되었던 것!!!

docker image와는 다른 default~!!

엄청나게 쉽게 될 줄 알았는데 삽질 함..-_-;;

다른분들은 금방 해결 되길 바라며..포스팅~촤촤촤! ㅎㅎ


acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

mesosphere

OpenSource 2017.04.28 11:36
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T



https://mesosphere.github.io/marathon/



Marathon은 Mesosphere의 Datacenter Operating System (DC / OS) 및 Apache Mesos 용 프로덕션 급 컨테이너 오케스트레이션 플랫폼입니다.


특징

  • 고 가용성. Marathon은 100 % 가동 시간 동안 리더를 선출 한 액티브 / 패시브 클러스터로 실행됩니다.
  • 다중 컨테이너 런타임. Marathon은 Mesos 컨테이너 (cgroup 사용)와 Docker에 대한 first-class 지원을 제공합니다.
  • Stateful apps(상태 보존 형 앱). Marathon은 영구 저장소 볼륨을 응용 프로그램에 바인딩 할 수 있습니다. MySQL 및 Postgres와 같은 데이터베이스를 실행할 수 있으며 Mesos로 스토리지를 구성한다. 
  • 아름답고 강력한 UI.
  • 제약 조건. 예 : 랙, 노드 등 하나당 하나의 애플리케이션 인스턴스
  • 서비스 검색 및 로드 밸런싱. 몇 가지 방법을 사용할 수 있습니다.
  • Health Checks. HTTP 또는 TCP 검사를 사용하여 응용 프로그램의 상태를 평가.
  • Event Subscripton(이벤트 구독). HTTP 엔드 포인트에 통지를 수신하려면 - 예를 들어 외부 로드 밸런서와 통합.
  • 측정 항목. JSON 형식으로 / metrics에서 쿼리하거나 graphite, statsd 및 Datadog와 같은 시스템에 푸시.
  • 손쉬운 통합과 스크립트 작성을위한 완벽한 REST API 제공.
하다가 중단하게 되어 아쉽지만 여기까쥐..ㅜ.ㅜ.



'OpenSource' 카테고리의 다른 글

mac os에서 kafka-console-consumer 사용하기  (0) 2017.09.13
mesosphere  (0) 2017.04.28

acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

Spring WebFlux

OpenSource/Spring 2017.04.26 17:40
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T

toby님이 회사에 오셨다.
스프링캠프 2017을 등록 못해서 못갔는데 다행히 좋은 강의를 들을수 있어서 좋았다.

강의자료 : 

Spring WebFlux
 람다식 
 추가 : 구 Spring web reactive 
  •  용도
    • 서비스간 호출이 많은 마이크로서비스 아키텍처에 적합.
    • 비동기 - 논블럭킹 개발방식.
    • 성능을 뛰어나게 만들겠다.
  • 기존 @MVC 방식, 새로운 방식
  • 서블릿 스택과 api에서 탈피
  • 블록킹, 논블록킹
    • 동기, 비동기와는 관점이 다름.
    • 내가 직접 제어할 수 없는 대상을 상대하는 방법
    • 대상이 제한적임
      • IO
      • 멀티 쓰레드 동기화 
  • 함수형 스타일의 콜백 방식

스프링 웹
1. 요청 매핑
2. 요청 바인딩
3. 핸들러 실행
4. 핸들러 결과 처리(응답 생성)

WebFlux
  • Router Function - 1. 요청매핑 (.route())
    • 함수형 스타일 (람다식..)
  • Handler Function - 2,3,4

RouterFunction의 등록 -> @Bean으로 만든다.
and(), andRoute(), nest() 등의 유용 메소드들.
flatMap

장점
  • 모든 웹 요청 처리 작업을 명시적인 코드로 작성.
  • 어노테이션에 의존하는 @MVC 스타일보다 명확
  • 정확한 타입 체크 가능.
  • 함수 조합을 통한 편리한 구성, 추상화에 유리
  • 테스트 작성의 편리함.

단점
  • 함수형 스타일의 코드가 익숙치 않음.
  • 기존 방식 가능

섞어서 사용 가능.
@MVC 요청 바인딩 + return Mono/Flux 사용.

WebFlux와 리액티브 기술
블로킹 IO 사용 X

JPA - JDBC 기반 RDB 연결
현재는 노답. - 블로킹 메소드로 점철된 jdbc api
JDK 10에서 Async JDBC가 등장할 수도(빠른 시간내에 적용)
@Async (적절한 쓰레드풀을 사용)
단, MongoDB, Redis, CouchDB등 Async 가능.

Spring5 함수형 스타일..

ReactiveStreams
RxJava를 비롯한 다양한 리액티브 기수에 적용된 표준 인터페이스
자바9에 Flow api로 포함.

뭘 공부해야하나?
java8 + 함수형 프로그래밍에 익숙해질 것.
Completablefuture와 같은 비동기 작업의 조합, 결합에 뛰어난 툴에 사용법을 익힐 것.

ReactorCore 학습 

열심히 공부하자+ㅁ+ㅋㅋ


'OpenSource > Spring' 카테고리의 다른 글

Spring WebFlux  (0) 2017.04.26
ChainedTransactionManager를 이용한 글로벌트랜잭션  (0) 2013.08.22
Bug  (0) 2013.06.21
@Vaild 처리 시 주의 할 사항!!  (0) 2013.06.21
Spring jmsTemplate 사용하기  (0) 2013.03.26
HornetQ, JMS Client using Springframework and Maven  (0) 2013.03.22

acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

Study - JPA 소개

OpenSource/Jpa 2016.11.28 19:04
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T

주저리 > 

보통 Web Project를할 때 MVC 패턴과 더불어 SQL Mapper인 ibatis, mybatis등을 많이 사용하였습니다.

지금 회사에서도 mybatis가 사용된 프로젝트들이 대다수 입니다.

필드 하나가 추가 되면 dto(vo)를 비롯한 sql등을 수정해주어야하는..

 즉, MVC pattern : View - Controller - Service - Repository(Dao) - SQL까지 전체적인 수정을 요합니다.

이런 노가다적이고 복잡한 것을 JPA에서는 객체모델링을 기반으로 풀어나간다고 합니다.

db 모델링 기반이 아닌 object 모델링!! 

정말 가능한지 한번 알아보겠습니다.


JPA는 무엇인가?

풀어서 알아보면! Java Persistence Api~~자바 진영의 ORM 기술 표준이다.

출처 : https://www.tutorialspoint.com/jpa/jpa_introduction.htm


여기서 ORM이란? Object Relational Mapping 말그대로 관계형 데이터베이스와 객체를 매핑 시켜준다는 것이다.

ORM하면 하이버네이트가 떠오를 것이다.

하이버네이트를 기반으로 새로운 자바 ORM기술 표준이 만들어졌는데 이것이 바로 JPA이다!

그림 - JPA 표준 인터페이스와 구현체

출처 : 책 - 자바 ORM 표준 JPA 프로그래밍

위의 UML을 보면 감이 오는가?


JPA는 왜 사용해야하는가?

1. 생산성

2. 유지보수

3. 패러다임의 불일치 해결

4. 성능

5. 데이터 접근 추상화와 벤더 독립성(Dialect) 

라고 한다. 앞으로 정말 그러한지 알아보도록 하자!



'OpenSource > Jpa' 카테고리의 다른 글

Study - JPA 소개  (0) 2016.11.28

acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

ace-t의 Spring Boot 따라잡기(기본 - freeMarker 연동)

OpenSource/Spring Boot 2016.08.28 18:59
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T

오랜만에 강좌를 쓰네요^0^ 

오늘은 freeMarker라는 템플릿을 이용하여  view를 만들어보겠습니다. ㅎㅎ

왜 freemarker냐?! 라고 하시면..회사에서 현재 사용하고 있어서라고..후훗


우선 지난번의 강좌를 통해 새롭게 검토하는 겸 따라서 해보겠습니다.

2016/03/22 - [OpenSource/Spring Boot] - ace-t의 Spring Boot 따라잡기(셋팅편)

2016/03/22 - [OpenSource/Spring Boot] - ace-t의 Spring Boot 따라잡기(기본 - 헬로우월드찍어보기!)

2016/03/23 - [OpenSource/Spring Boot] - ace-t의 Spring Boot 따라잡기(기본 - SourceTree에 연결 및 Repository에 올리기)

2016/03/23 - [OpenSource/Spring Boot] - ace-t의 Spring Boot 따라잡기(기본 - 외부톰캣 연동하기!)

2016/03/24 - [OpenSource/Spring Boot] - ace-t의 Spring Boot 따라잡기(기본 - CouchBase 연동하기)

2016/03/24 - [OpenSource/Spring Boot] - ace-t의 Spring Boot 따라잡기(기본 - logging)

2016/03/24 - [OpenSource/Spring Boot] - ace-t의 Spring Boot 따라잡기(기본 - 예외처리)


셋팅편을 참고하여 2분만에 샤샤샤~(JPA는 우선 셀렉 하지 마세용~)



압축 되어진 친구를 원하는 디렉토리에 압축을 풀어보면 아래와 같이 되어있습니다.



STS던지 인텔리J던지 원하는 에디터에 연결하여 줍니다. 저는 회사에서 제공해주는 인텔리J에 연결을 해보겠슴돠~

 

그리고나서 헬로우월드 한번 찍어주시고~(위의 링크 참조!)

그리고나서 우리가 원하는 freemarker를 설정해보겠습니다.


1. 위에서 freemarker를 선택하지 않았을 경우!  build.gradle에 아래의 디펜던시를 추가!


compile('org.springframework.boot:spring-boot-starter-freemarker')


2. 우리가 접근하고 싶은 view 를 하나 만들어 봅니다. templates dir에 index.ftl 하나를 만들어 줍니다.

    확장자는 ftl 입니다.


index.ftl의 내용은 아래와 같습니다.

<html>
<h1> hello~ ${message}</h1>
</html>

 




3. 그리고 이 view를 컨트롤할 Controller를 하나 만들어줍니다.


   


    import org.slf4j.Logger;

import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@Controller
@RequestMapping(value = "/")
public class FreeMarkerController {
public static final Logger log = LoggerFactory.getLogger(FreeMarkerController.class);

@RequestMapping(method = RequestMethod.GET)
public String showIndex(Map<String,Object> model){
String msg = "terry~";
model.put("message", msg);
return "index";
}

}


 


서버를 띄운 뒤에 아래와 같이 나오면 성공!


http://localhost:8080/





test 관련

http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html


요렇게 간단하게 웹을 구현할 수 가 있었습니다.

앞으로는 더 멋있는 녀석을 구현해보도록 하겠습니다.



 - 다음 이시간에.. -



acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

spring boot 환경 나누기(profiles)

OpenSource/Spring Boot 2016.07.18 10:38
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T



TEST Code


@RunWith(SpringJUnit4ClassRunner.class)

@SpringApplicationConfiguration(classes = LineupFantaApplication.class)

public class ServerHolderTest {


    public static final Logger logger = LoggerFactory.getLogger(ServerHolderTest.class);



    @Autowired ServerHolder serverHolder;


//    @Before

//    public void setUp(){}


    @Test

    public void testServerProfiles() throws Exception {

        Map<String,Map<String,String>> servers = serverHolder.getServerInfo();

        Assert.assertThat(servers.size(), is(1));

    }


} 


옛날 spring 방식하고 다르게 C언어처럼 main이 있으니 @SpringApplicationConfiguration(classes = LineupFantaApplication.class) 만 추가해주면 컨텍스트 쭉쭉 올라감! 굿굿!


@Autowired된 친구쪽에서 application.yml 읽어들임!

application.yml은 우리가 사용하게 되는 application.properties와 같은 친구!




@Component

@ConfigurationProperties(locations={"classpath:application.yml"})

public class ServerHolder {


    public Map<String, Map<String, String>> serverInfo = new HashMap<String, Map<String, String>>();

    public Map<String, Map<String, String>> getServerInfo() {

        return serverInfo;

    }

} 


application.yml의 내용은 아래와 같음.

serverInfo:

    - name: lineup

      ip: xxx.xxx.xxx.xxx

---


spring:

    profiles: real

serverInfo:

    - name: lineup

      ip: xxx.xxx.xxx.xxx



사용법은 아래와 같이 원하는 곳에서 사용하면 됨!

protected List<String> getBootstrapHosts() {

        return Arrays.asList(serverHolder.getServerInfo().get("0").get("ip"));

}



profiles는 tomcat같은 경우 vm argument에 이처럼 정보를 넣어서 사용!

-Dspring.profiles.active=real 옵션~안해주면 default 정보

1) 디폴트 : No active profile set, falling back to default profiles: default

2) -Dspring.profiles.active=real 옵션 : The following profiles are active: real


즉, 위의 옵션으로 yml의 정보를 real이냐 default냐 읽어들여서 profiles를할 수가 있다.

참고 사이트 : http://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html




acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

log 모니터링을 위한 아키텍처

OpenSource/ElasticSearch 2016.06.15 19:12
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T

log 모니터링을 위한 아키텍처



목표는 ansible + elk


 END


acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

uses unchecked or unsafe operations.

OpenSource/Spring Boot 2016.04.01 17:38
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T



uses unchecked or unsafe operations. 와 같은 워닝이 뜨면 확인해보아야할 것이있다.


아래와 같이 ArrayList 를 하나 선언했다.

ArrayList keyArr = new ArrayList();


위처럼 선언을 하면 uses unchecked or unsafe operations. 라고 warning이 뜬다.


ArrayList<String> keyArr = new ArrayList<String>();  이렇게 해야 경고는 뜨지 않는다.


관련해서 이펙티브 자바책을 한번 보면 좋을것 같다.


  - 끝 -



acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

ace-t의 Spring Boot 따라잡기(기본 - 예외처리)

OpenSource/Spring Boot 2016.03.24 18:05
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T

예외처리!

예외가 발생하면 그냥 찍기만 하는가?!!! 그것이 예외처리를 한것인가? 

예외의 종류는 런타임, 체크드 2가지가 있다카던데.. 어떻게 해야 예외처리 잘했다고 소문이 날것인가??


우리는 런타임예외가 발생하면 그녀석을 잡아다가! 조치를 취할 것 입니다.

1) CommonLineupException.java,CommonLineupResponse.java, ExceptionAdvice.java를 

    만들어 줍니다.




내용은?

CommonLineupException에서는

  • extends RuntimeException를 상속.
  • 생성자를 통해 메시지를 부모생성자에 전달.

  public CommonLineupException(String message){

     super(message);

  }


source

더보기


ComonLineupRespose에서는

  • message를 전달받아 getMessage()를 만들어 전달하도록 합니다.

source

더보기


ExceptionAdvice에서는

@ControllerAdvice, @ExceptionHandler, @ResponseStatus를 사용!

source

더보기


이제 예외처리를 하기 위한 것을 만들었으니 예외를 발생시켜보고 어떻게 동작하는지 알아봅시다.

tip. 보통은 로직이 있는 서비스쪽에서 런타임예외를 발생! 컨트롤러까지 올라오게 되어집니다.


TEST로 기존에 만들었던 컨트롤러에 아래의 메소드를 추가하여 줍니다.

    @RequestMapping("/fail")

    public String fail() {

        throw new CommonLineupException("  This is Fail Test!!");

    } 


결과

http://localhost:8080/lineup/fail



이것을 기반으로 예외처리 구조를 잡으면 된다!

Tip. ExceptionAdvice.java에 위에는 사용자정의 예외만 잡는것을 해보았는데

다른 일반적인 예외도 잡아서 처리가 가능함!!


   @ExceptionHandler(NoHandlerFoundException.class)

    public @ResponseBody CommonLineupResponse noHandlerFoundException(NoHandlerFoundException ex) {

        return new CommonLineupResponse("["+ex.getHttpMethod()+"] / NoHandlerFoundException~!!."+ex.getMessage());

    } 




  - 끝 -


설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

ace-t의 Spring Boot 따라잡기(기본 - logging)

OpenSource/Spring Boot 2016.03.24 16:55
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T


참고 : https://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html

Spring Boot의 로깅은 의무적인게 아니라서 commons-logging이 제외 되어있어서 

Logback같은 녀석이 필요하면 spring-boot-starter-logging에 의존되어진 common-logging을 사용. 

(단, web을 사용한다면 spring-boot-starter-web에 포함되어있다고 한다. 굿!)

즉, build.gradle의 compile("org.springframework.boot:spring-boot-starter-web")이 있으면 OK!



logging의 레벨은 application.properties에서 조정할 수가 있다.

  • logging.level.org.springframework.web=DEBUG
의 레벨을 ERROR, INFO, DEBUG등으로 변경해서 로그를 보면 조정되어지는것을 알수가 있다.

이제 우리가 셋팅해야할 Logback logging에 대해서 알아보자.
  • logback-spring.xml을 만들어준다. logback.xml도 되지만 logback-spring.xml이 이점이 있다고 한다.

ex)


logback-spring.xml의 안의 간단한 내용은

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml"/>
    <logger name="org.springframework.web" level="DEBUG"/>
</configuration>

여기에서 base.xml은 spring-boot.jar에 있고 위에처럼 간단하게 처리가 가능하다. 하지만 따로 logback의 포맷으로 지지고 볶고 해도 무관!

참고할 좋은 예제는 아래에!

http://www.mkyong.com/logging/logback-xml-example/


위를 참고하여~

더보기


아래처럼 log들이 생긴다. logback의 지식이 있어야 더 잘사용할 수 있다는게 함정ㅋ 



  - 끝 -





acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

ace-t의 Spring Boot 따라잡기(기본 - CouchBase 연동하기)

OpenSource/Spring Boot 2016.03.24 11:16
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T



2016/03/23 - [OpenSource/Spring Boot] - ace-t의 Spring Boot 따라잡기(기본 - 외부톰캣 연동하기!)


Rest api + CouchBase 연동

CouchBase 셋팅은 따로 다루지 않겠습니다.

이미 셋팅이 되어있다는 전제하에 진행합니다.


1) build.gradle의  dependency 추가

    compile('org.springframework.data:spring-data-couchbase:2.0.0.RELEASE') 를 추가.


2) Controller 작성

  • Controller 작성 후 Service를 호출하는 방식이 보통 MVC 패턴이며, Repository라는 interface를 implements하여 Service에서 구현해 나가는 구조 입니다. 또한 couchbase의 config관련도 필요합니다.
  • Controller 뼈대 코딩 후 필요한 Config -> Interface -> Service 순으로 만들어 가겠습니다.
  • Restful api 방식은 @RestController와 @PathVariable를 통해 간단하게 구현할 수 있습니다. 단, Restful은 아키텍처를 따로 공부하여 업무에 맞게 알맞게 구현해보세요~
  • add source

import com.kakaocorp.www.api.service.LineupDataService;

import com.kakaocorp.www.api.config.CouchBaseConfig;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.*;


import java.util.List;

import java.util.Map;


@RestController

public class LineupDataController {

    @Autowired

    CouchBaseConfig couchBaseConfig;

    @Autowired

    LineupDataService lineupDataService;


    @RequestMapping(value = "/{version}/findAll", method = RequestMethod.GET)

    public List<Map<String, Object>> getStaticData(@PathVariable String version, @RequestParam String query, @RequestParam(defaultValue = "mobile") String platform){

        if("v1".equals(version)){

            return lineupDataService.findAll(couchBaseConfig, query, platform);

        }

        return null;

    }


}



3) CouchBaseConfig.java 생성

  • extends AbstractCouchbaseConfiguration
  • add source

    @Override    
    protected List<String> getBootstrapHosts() {

        return Arrays.asList("couchbase ip or domain");

    }



    @Override

    public String getBucketName() {

        return "wirite bucket name";

    }


    @Override

    protected String getBucketPassword() {

        return "";

    }


    @Bean

    public Bucket contextBucket() throws Exception {

        return couchbaseCluster().openBucket("wirite bucket name", "");

    }


    @Bean(name = "contextTemplate")

    public CouchbaseTemplate contextTemplate() throws Exception {

        CouchbaseTemplate template = new CouchbaseTemplate(couchbaseClusterInfo(), //reuse the default bean

                contextBucket(), mappingCouchbaseConverter(), translationService() //default beans here as well

        );

        template.setDefaultConsistency(getDefaultConsistency());

        return template;

    }

 

3) CouchBaseDataReposiry interface를 하나 만듭니다.

  • 원하는 기능을 interface에 넣고 service에서 재구현할 것이다.
  • add source

import java.util.List;

import java.util.Map;

public interface CouchBaseDataRepository {

    public List<Map<String, Object>> findAll(final CouchBaseConfig couchBaseConfig, final String searchKeyword, String platform);

} 



4) CouchBaseDataService.java 생성

  • 위에서 만든 interface를 implements 하여 구현 합니다.
  • add source : N1ql을 사용 함.

아래의 소스는 프로토타입으로 간단하게 구현되었음. 무조건 실행! 아래의 소스를 바탕으로 확장하시면 됩니다.

참고 : http://developer.couchbase.com/documentation/server/4.0/n1ql/n1ql-intro/data-access-using-n1ql.html

import com.couchbase.client.java.query.N1qlQuery;

import com.couchbase.client.java.query.N1qlQueryResult;

import com.couchbase.client.java.query.N1qlQueryRow;

import com.couchbase.client.java.query.Statement;

import com.couchbase.client.java.query.dsl.path.AsPath;

import com.kakaocorp.www.api.config.CouchBaseConfig;

import com.kakaocorp.www.api.repository.CouchBaseDataRepository;

import org.springframework.dao.DataRetrievalFailureException;

import org.springframework.stereotype.Service;


import java.util.ArrayList;

import java.util.List;

import java.util.Map;


import static com.couchbase.client.java.query.Select.select;

import static com.couchbase.client.java.query.dsl.Expression.i;

import static com.couchbase.client.java.query.dsl.Expression.s;

import static com.couchbase.client.java.query.dsl.Expression.x;


@Service

public class LineupDataService implements CouchBaseDataRepository {


    @Override

    public List<Map<String, Object>> findAll(CouchBaseConfig couchBaseConfig, final String searchKeyword, String platform) {

        Statement query;


        AsPath prefix = select("D, H, P").from(i(couchBaseConfig.getBucketName()));

        query = prefix.where(x("QUERY").eq(s(searchKeyword)).and("PLATFORM").eq(s(platform)));


        logQuery(query.toString());

        N1qlQueryResult result = null;

        try {

            result = couchBaseConfig.contextBucket().query(N1qlQuery.simple(query));

        } catch (Exception e) {

            e.printStackTrace();

        }

        return extractResultOrThrow(result);

    }


    private static List<Map<String, Object>> extractResultOrThrow(N1qlQueryResult result) {

        if (!result.finalSuccess()) {

            //log.warn("Query returned with errors: " + result.errors());

            throw new DataRetrievalFailureException("Query error: " + result.errors());

        }


        List<Map<String, Object>> content = new ArrayList<Map<String, Object>>();

        for (N1qlQueryRow row : result) {

            content.add(row.value().toMap());

        }

        return content;

    }


    /**

     * Helper method to log the executing query.

     */

    private static void logQuery(String query) {

        //log.info("Executing Query: {}", query);

    }

 

  - 끝 -



acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

ace-t의 Spring Boot 따라잡기(기본 - 외부톰캣 연동하기!)

OpenSource/Spring Boot 2016.03.23 16:01
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T


2016/03/23 - [OpenSource/Spring Boot] - ace-t의 Spring Boot 따라잡기(기본 - SourceTree에 연결 및 Repository에 올리기)


외부 톰캣을 사용하고자 한다면!! 

jar -> war로 변경을 해주면 됩니다.


방법은? 

1) build.gradle에서 주황색 부분을 변경 jar->war

apply plugin: 'war'


war {

baseName = 'lineup-fanta'

version = '0.0.1-SNAPSHOT'

}


2) main 소스에 추가 작업

  • extends SpringBootServletInitializer
  • add overriding source

@Override

protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {

    return application.sources(LineupFantaApplication.class);

}


3) gradle clean, build 후 체크


4) 생성한 war를 톰캣에 올려서 띄워보도록 하겠습니다.

  • editor configuration을 통해 미리 받아놓은 톰캣과 연동 시킵니다.



  • 리가 생성한 war를 선택하여 줍니다.



  • 실행 ㄱ ㄱ




5) 추가적으로 build.gradle에서 exclude module 추가


compile("org.springframework.boot:spring-boot-starter-web") {

   exclude module: "spring-boot-starter-tomcat"

}


  - 끝 -






acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

ace-t의 Spring Boot 따라잡기(기본 - SourceTree에 연결 및 Repository에 올리기)

OpenSource/Spring Boot 2016.03.23 11:49
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T

1. 로컬에 있는 소스를 소스트리에 연동 시킵니다.




2. 아래와 같이 gitignore.io에 접속하여 커밋하면 안되거나 불필요한 액션을 줄이기 위해 ignore할 파일들에 대해서 Generate 해줍니다.

 https://www.gitignore.io/




/.git/info의  exclude에 위에서 생성되어진 내용을 붙여넣기를 해준다.

붙여넣을 내용.

더보기


그러한 뒤에 github에 push를 해주면 된다.



  - 끝 -


acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

ace-t의 Spring Boot 따라잡기(기본 - 헬로우월드찍어보기!)

OpenSource/Spring Boot 2016.03.22 13:42
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T


2016/03/22 - [OpenSource/Spring Boot] - ace-t의 Spring Boot 따라잡기(셋팅편)


주저리 - 헬로우월드를 찍기전에 스프링의 구조를 한번 생각해볼 필요가 있겠습니다.

특히나 팀으로 혹은 2~3명이서 개발을 하는거라면 서로 각자 개발하지말고 먼저 물어보세요~

당신은 어떤구조로 개발하였나요? 라구요! 

주변에 너무 혼자서만 개발하시는분들이 많기 때문에 각자 자기만의 스타일을 고집한다면..

유지보수도 힘들고 커뮤니케이션을 함에 있어서도 힘든 부분이 있으니깐요! 

예를 들어 아래와 같이 기본적인 구조로 생각을 하신다는 가정하에 진행해보도록 하겠습니다.

api

  ㄴ config

  ㄴ controller

  ㄴ repository

  ㄴ service


이제 코딩을 한번 해볼 차례 입니다. 헬로우월드를 한번 찍어보겠습니다. 

controller에 아래와 같이 HelloWorldcontroller.java를 하나 만듭니다.


아래와 같이 소스코딩을한 뒤에 내장된 서버로 띄어봅니다.

소스코드

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;


@RestController

public class HelloWorldController {

    private static final String template = "Hello";

    @RequestMapping("/greeting")

    public String greeting(@RequestParam(value="name", defaultValue="World") String name) {

        return template+":"+name;

    }

}

결과는 아래와 같습니다.

http://localhost:8080/greeting?name=terry



  - 끝 -










acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

ace-t의 Spring Boot 따라잡기(셋팅편)

OpenSource/Spring Boot 2016.03.22 13:18
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T

1. 목표

현재 개발중인 프로젝트에서 필요한 api를 Spring Boot로 구현하고자 함.

정리를 해두면 다른사람도 좋고 나도 좋고~도랑치고 가재잡고~

CouchBase storege - SpringBoot api



2. 환경

Mac OS X

JDK 8

Tomcat 8

Gradle 1.3.3

Spring Boot

CouchBase 4.x

인텔리J IDE 12

git


3. Spring Boot 간단 셋팅!

  • http://start.spring.io/  에 접속!
  • 아래의 그림처럼 필요한 것들을 찾아서 Dependencies 선택! 나중에 찾아서 넣어도 되니 신중하게 생각하지 않아도 됨.


위에서 Group는 패키지라고 생각하시면 됩니다. 

또한 Gradle Project Artifact를 설정, 디펜던시 설정 후에 Generaate Project!!

아래와 같이 zip파일로 프로젝트 소스가 똭!





압축을 해제한 뒤 원하는 위치에 복사!




그런 다음 인텔리J에서 프로젝트를 가져옵니다.




Gradle 기반이므로 Gradle을 선택하여 줍니다.



다음x2 을 해주면 아래와 같이 프로젝트가 import 되어집니다.

단, gradle이 로컬에 없으면 다음다음이 안될수가 있겠네요~ 고렇다면 gradle 다운 받은다음에 아래와 같이 연결 시켜주면 됩니다.





이제 소스코딩을 하거나 원하는 셋팅을 하시어 사용하시면 됩니다. 참 쉽죠잉? 

셋팅편 끝~


다음편은..항상 우리가 하던 헬로우월드찍기! 를 해보겠습니다.


2016/03/22 - [OpenSource/Spring Boot] - ace-t의 Spring Boot 따라잡기(기본 - 헬로우월드찍어보기!)







acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

step by step - spring boot

OpenSource/Spring Boot 2016.02.17 03:29
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T



스프링 부트를 프로젝트에 적용시켜 구현을 하고 있다.

위의 소스는 해당 프로젝트를 위한 가이드 소스이다. 

꼭 필요한 작업이라고 생각이 되어 개발 가이드 소스를 조금씩 습득하며 구현하고 있다.

전체적인 아키텍처와 as-is 분석도 해야하니..새벽에 더 볼수 밖에 없지만 뭔가 하고있다는게 즐거운듯 하다.

또한 다른업무에 치여 손도 못댔었는데..그나마 요즘 운동을 시작했더니 새벽에 안졸리고 집중이 되어 조금이라도 코드를 짜봐서 조으다~

2016년 목표한바 성취하도록 화이팅 하자!


acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

redis 메모리 사용량?

OpenSource/Redis 2016.01.27 11:17
[Good Comment!!, Good Discussion!!, Good Contens!!]
[ If you think that is useful, please click the finger on the bottom~^-^good~ ]
by ace-T

http://redis.io/topics/quickstart


redis 관련 정보를 얻을 수 있다.


특히 redis-cli (commad line)을 통해 redis에서 사용하고 있는 용량을 알수 있다.

redis-cli info를 하면 아래와 같은 내용이 나오며 실제 사용되어지고 있는 것은 used_memory_human를 보면 된다.

# Memory
used_memory:38894386256
used_memory_human:36.22G
used_memory_rss:46722285568
used_memory_peak:85900378992
used_memory_peak_human:80.00G
used_memory_lua:31744
mem_fragmentation_ratio:1.20

mem_allocator:jemalloc-3.2.0


리눅스 메모리 사용률도 함께 체크하면 좋다.

참고  http://zetawiki.com/wiki/%EB%A6%AC%EB%88%85%EC%8A%A4_%EB%A9%94%EB%AA%A8%EB%A6%AC_%EC%82%AC%EC%9A%A9%EB%A5%A0_%ED%99%95%EC%9D%B8




'OpenSource > Redis' 카테고리의 다른 글

redis 메모리 사용량?  (0) 2016.01.27

acet 박태하가 추천하는 readtrend 추천글!

설정

트랙백

댓글

:::: facebook을 이용하시는 분들은 로그인 후 아래에 코멘트를 남겨주세요 ::::

티스토리 툴바