'springboot'에 해당되는 글 8건

  1. 2022.03.23 [Docker] Spring Boot App 도커 적용
  2. 2021.12.07 [Elasticsearch] LLRC + Springboot 성능 튜닝 팁
  3. 2021.09.27 [SpringBoot] Application 실행 시 특정 작업 실행 시키기
  4. 2021.09.16 [SpringBoot] 깡통 프로젝트 생성 후 실행 시 에러 (Error creating bean with name 'dataSource' defined in class path resource)
  5. 2021.08.02 [Log4J2] Executable Jar + Springboot framework 사용 예.
  6. 2019.09.20 [Spring] Springboot + Thymeleaf 설정 시 주의.
  7. 2019.09.18 [SpringBoot] Project Starter
  8. 2019.09.16 [SpringBoot] @PropertySource 로 yaml 파일 읽기

[Docker] Spring Boot App 도커 적용

ITWeb/개발일반 2022. 3. 23. 10:49

Springboot 로 WAS 생성 후 이를 도커 기반으로 생성, 실행 하기 위해서 관련 내용 기록 합니다.

 

관련 문서)

https://spring.io/guides/gs/spring-boot-docker/
https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/

 

과정)

1. 프로젝트를 빌드 해서 bootJar 를 생성 합니다.

보통 build/libs 에 생성이 됩니다.

 

2. Dockerfile 을 생성 합니다.

여기서 bootJar 를 ADD 해야 하는데 Dockerfile 과 같은 Depth 에 위치 하거나 하위에 위치해야 합니다.

상위에 bootJar 가 있을 경우 permission denied 에러가 발생 합니다.

 

3. Image 생성을 합니다.

$ docker build -t 이미지명:태그 .

태그 정보는 jenkins 에서 build number 를 부여 하거나 운영 규칙을 정해서 관리 합니다.

registry 를 운영하고 있으면 생성된 이미지를 등록 합니다.

 

4. docker-compose.yml 을 생성 합니다.

registry 를 운영하고 있으면 registry 에서 이미지를 받아 옵니다.

 

관련 예제 코드들은 위 문서에 잘 나와 있으니 참고 하면 됩니다.

 

아래는 그냥 참고용으로 올려 봅니다.

build.gradle)
...중략...
bootJar {
  destinationDirectory=file('docker/libs')
  enabled = true
}
...중략...

$ export TAG=1.0.0
$ docker build -t boot-app:$TAG .


Case 1) docker/Dockerfile
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=./libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

Case 2) docker/Dockerfile
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=./libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT java \
-jar app.jar

Case 3) docker/Dockerfile
ENV heapSize="-Xms2048 -Xmx2048m"
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=./libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","${heapSize}","-jar","/app.jar"]

Case 4) docker/Dockerfile
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=./libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT java \
${heapSize} \
-jar app.jar

ENTRYPOINT 추가 옵션)
-Djava.security.egd=file:/dev/./urandom \
-Dspring.profiles.active=local


docker-compose) docker/docker-compose.yml
version: '3.7'

services:
  boot-app:
    container_name: boot-app
    image: boot-app:${TAG}
    environment:
      - TZ=Asia/Seoul
      - env=local
      - "heapSize=-Xms2048m -Xmx2048m"
    ports:
      - "8080:8080"
    volumes:
      - ./logs:/home/appuser/logs
    sysctls:
      - net.core.somaxconn=65000
    restart: on-failure

 

:

[Elasticsearch] LLRC + Springboot 성능 튜닝 팁

Elastic/Elasticsearch 2021. 12. 7. 09:14

대부분의 성능 이슈는 서버 엔진 보다는 클라이언트 단에서 사용을 잘 못 하는 경우가 많이 있습니다.

 

Low Level Rest Client 와 Springboot 조합으로 API 개발 시 튜닝 요소를 조금 정리 합니다.

나중에 또 기억 못할 것 같으니...

 

RestClientBuilder 에 보면 아래와 같이 기본 설정이 되어 있습니다.

public static final int DEFAULT_MAX_CONN_PER_ROUTE = 10;
public static final int DEFAULT_MAX_CONN_TOTAL = 30;

이 기본 값으로 그냥 사용하게 되면 너무 리소스를 제한적으로 사용하기 때문에 성능이 제대로 나오지 않게 됩니다.

해당 값을 적절하게 튜닝을 하셔야 하는데 모든 케이스에 다 적용 가능한 부분은 아니지만 그래도 가늠 할 수 있는 기준 정도로는 사용이 가능 할 것 같아 공유 합니다.

분석 결과는 Core 1 개당 setMaxConnPerRoute 설정 시 25 개씩이 최적 값으로 보입니다.
4 core 짜리면 4 x 25 = setMaxConnPerRoute(100)

 

아래는 실제 코드 내부에 작성 되어 있는 코멘트를 보여 드리기 위해 캡쳐 했습니다.

HttpAsyncClientBuilder httpClientBuilder = HttpAsyncClientBuilder.create().setDefaultRequestConfig(requestConfigBuilder.build())
  //default settings for connection pooling may be too constraining
  .setMaxConnPerRoute(DEFAULT_MAX_CONN_PER_ROUTE).setMaxConnTotal(DEFAULT_MAX_CONN_TOTAL)

 

코드에서도 동일하게 기본 설정은 너무 제한적일 수 있다고 되어 있습니다.

 

Embedded Tomcat 에서의 기본 Max Connection 은 8192 개 입니다.

Tomcat 과 HttpClient 그리고 Elasitcsearch 에 대한 각각의 Connection, Thread Count 를 잘 조정 하셔야 성능을 최적화 할 수 있습니다.

 

추가적으로 Connection 과 Route 의 비율은 10:1 정도가 적절해 보입니다.

 

아래는 Tomcat 기본 설정 내용입니다.

- Embedded Tocmat 의 설정 중
    acceptCount 는 기본 100 개 이며 이 설정은 maxConnection 에 다다랐을 때 OS 레벨에서 큐잉 하게 되는 값 입니다.
    maxConnections 는 기본 8192 개 이며 NIO/NIO2 를 사용 하며, -1 로 설정 시 카운팅 하지 않습니다. (unlimited)
    maxThreads 는 기본 200 개 이며 connection 당 생성 가능한 최대 thread 수 입니다.
    BIO 일 경우 maxConnections 와 maxThreads 값은 같아야 합니다.


정답은 없으나 시스템 리소스 상황에 맞춰서 최적 값을 찾아 내는게 제일 중요 합니다.
위에 설정 방식이나 값이 최적 값이 아니며 상황에 맞춘 최적 값이고 다른 환경에서는 튜닝 포인트가 된다고 보는게 좋을 것 같습니다.

시스템의 ulimit 설정을 꼭 확인 하고 사용하는 stack 의 default 값도 꼭 확인 하고 사용 합시다.

성능 최적화를 위해 함께 살펴 봐야 하는 소스 코드는 

Java NIO, Executor
Tomcat Connector
Http Client (Components)
Elasticsearch RestClient

 

:

[SpringBoot] Application 실행 시 특정 작업 실행 시키기

ITWeb/개발일반 2021. 9. 27. 12:39

아래 세 가지 방법으로 실행 시킬 수 있습니다.

@Component
public class RunAfterApplicationStart implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) {
        // 실행 코드
    }
}

@Component
public class RunAfterApplicationStart implements CommandLineRunner {

    @Override
    public void run(String... args) {
        // 실행 코드
    }
}

@Component
public class RunAfterApplicationStart {

    @EventListener(ApplicationReadyEvent.class)
    public void hello() {
        // 실행 코드
    }
}

 

:

[SpringBoot] 깡통 프로젝트 생성 후 실행 시 에러 (Error creating bean with name 'dataSource' defined in class path resource)

ITWeb/개발일반 2021. 9. 16. 17:26

springboot 프로젝트 만들어야 할 때 이용 합니다.

https://start.spring.io/

필요한 dependency 추가해 주고 로컬로 다운로드 받아 바로 실행 시켜 봅니다.

근데 깡통임에도 불구하고 에러가 발생을 했습니다.

 

mybatis 를 추가 했을 경우 application.yml 에 datasource 관련 설정을 하지 않게 되면 발생 하는 에러 입니다.

아래와 같이 설정을 추가 하고 build.gradle 에 mysql connector lib 도 추가해 주고 실행 하면 에러가 없어 집니다.

 

[error logs]
2021-09-16 17:24:18.201  WARN 76669 --- [  restartedMain] ConfigServletWebServerApplicationContext : 
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: 
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: 
Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: 
Factory method 'dataSource' threw exception; 
nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: 
Failed to determine a suitable driver class
2021-09-16 17:24:18.205  INFO 76669 --- [  restartedMain] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]

[application.yml]
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/...
    username: ${USER}
    password: ${PASSWORD}
    
[build.gradle]
implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.26'

 

:

[Log4J2] Executable Jar + Springboot framework 사용 예.

ITWeb/개발일반 2021. 8. 2. 20:45

 

springboot framework 을 이용해서 executable jar 구현 시 log4j2 사용 예)
- @Slf4j 사용
- logback.xml 사용
- -Dlogback.configurationFile=$DIR_HOME/logback.xml

로그가 중복으로 남을 경우)
https://logging.apache.org/log4j/2.x/manual/configuration.html#Additivity
- <logger name="..." ... additivity="false" />
- 단순하게 보면, Logger 에 선언 된 appender 로 한번 기록하고 root logger 에 의해서 한번 기록 하게 되는 구조 입니다.

build.gradle 예)
configurations.all {
  exclude module: 'spring-boot-starter-logging'
}
...중략...
dependencies {
...중략...
  compile group: 'org.slf4j', name: 'slf4j-api', version: "${props.getProperty('slf4j')}"
  compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: "${props.getProperty('log4j')}"
  compile group: 'ch.qos.logback', name: 'logback-classic', version: "${props.getProperty('logback')}"
  compile group: 'ch.qos.logback', name: 'logback-core', version: "${props.getProperty('logback')}"
...중략...
}

 

:

[Spring] Springboot + Thymeleaf 설정 시 주의.

ITWeb/개발일반 2019. 9. 20. 13:58

springboot 에서 thymeleaf 사용 시 applicaiton.properties 내 주의 사항 정도 입니다.

 

기본 설정은 아래와 같습니다.

 

spring.thymeleaf.cache=true
spring.thymeleaf.check-template=true
spring.thymeleaf.check-template-location=true
spring.thymeleaf.enabled=true
spring.thymeleaf.enable-spring-el-compiler=false
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.excluded-view-names=
spring.thymeleaf.mode=HTML
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.reactive.chunked-mode-view-names=
spring.thymeleaf.reactive.full-mode-view-names=
spring.thymeleaf.reactive.max-chunk-size=0B
spring.thymeleaf.reactive.media-types=
spring.thymeleaf.render-hidden-markers-before-checkboxes=false
spring.thymeleaf.servlet.content-type=text/html
spring.thymeleaf.servlet.produce-partial-output-while-processing=true
spring.thymeleaf.suffix=.html
spring.thymeleaf.template-resolver-order=0
spring.thymeleaf.view-names=

 

이 설정 값들을 넣어 주지 않으셔도 기본 동작에는 문제가 없으나 설정 최적화와 이해를 위해서는 각각의 설정이 어떤 의미를 가지는지 아는게 중요 합니다.

 

viewResolver 관련해서 주의 점은!!

spring.thymeleaf.view-names# Comma-separated list of view names (patterns allowed) that can be resolved.

이 설정을 제거 하시거나 등록을 해주셔야 한다는 것입니다.

 

그냥 저렇게 empty value 로 놔두시면 viewResolver 오류가 발생을 하게 됩니다.

주석에 나와 있는 설명 처럼 목록으로 넣어 주시거나 패턴으로 잡아 주시면 되겠습니다.

:

[SpringBoot] Project Starter

ITWeb/개발일반 2019. 9. 18. 10:10

시작 하기에 앞서 한번 읽어 보고 하면 좋은 링크 스크랩.

 

https://start.spring.io
https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/
https://docs.gradle.org/current/userguide/java_library_plugin.html

 

저 문서들을 읽고 나니 왜 스프링부트가 대세가 되었는지 알겠내요.

:

[SpringBoot] @PropertySource 로 yaml 파일 읽기

ITWeb/개발일반 2019. 9. 16. 13:34

아래 문서에 보면 설명이 잘 나와 있습니다.

기록 하는 차원에서 남겨 봅니다.

 

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-yaml-shortcomings

 

24. Externalized Configuration

Getters and setters are usually mandatory, since binding is through standard Java Beans property descriptors, just like in Spring MVC. A setter may be omitted in the following cases:Maps, as long as they are initialized, need a getter but not necessarily a

docs.spring.io

1. If you use “Starters”, SnakeYAML is automatically provided by spring-boot-starter.
2. The YamlPropertySourceLoader class can be used to expose YAML as a PropertySource in the Spring Environment. Doing so lets you use the @Value annotation with placeholders syntax to access YAML properties.

 

SnakeYAML 이 기본 탑재

@Value 로 접근 가능

 

@PropertySource("classpath:/application.yml")
...
@Value("${spring.profiles.active}")
private String profile;

@PropertySource("classpath:/application.yml")
...
@Value("${spring.profiles.active}")
private String profile;

 

: