Spring Boot 프로젝트 생성

Spring Boot initializr 를 사용하여 스프링 부트 프로젝트를 생성 후 IDE에서 열어보기

https://start.spring.io/

 

 

java, Spring Boot 버전에 맞게 설정 후 사용할 디펜던시 추가

  • Lombok: Getter, Setter 등 어노테이션 사용을 위해 추가
  • Spring Web: Spring의 MVC 패턴을 사용하기 위해 추가
  • Spring Boot Dev Tools: 소스 변경시 재기동 등 다양한 개발 편의를 위해 추가

프로젝트 실행

생성한 프로젝트를 VSCode에서 open 후  실행 확인

 

 


Swagger 라이브러리 추가

https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui/2.5.0

 

Swagger를 사용하기위한 springdoc 라이브러리 추가

 ps. Spring Boot 3.x 이상부터는 openAPI Starter WebMVC UI로 적용해야한다.

 

maven repository에서 springdoc을 찾아서 gradle 클릭 후 카피

 

 

build.gradle에 추가

 

접속

테스트 컨트롤러 및 openAPI 설정 

SwaggerConfig.java

package com.portfolio.portfolio_was.config;

import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * SwaggerConfig
 */
@Configuration
public class SwaggerConfig {

  
  @Bean
  public GroupedOpenApi api() {
    String[] paths = {"/**"};
    // String[] pakcagesToScan = {"com.portfolio.portfolio_was"};
    return GroupedOpenApi.builder().group("springdoc-openapi")
    .pathsToMatch(paths)
    // .packagesToScan(pakcagesToScan)
    .build();
  }
}

 

TestController.java

package com.portfolio.portfolio_was.controller;

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

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;


@RequestMapping("/test")
@RestController
public class TestController {
 
  @GetMapping("/api1")
  @Tag(name = "test api")
  @Operation(summary = "test")
  public String test22() {
    return "test";
  }
}

 

 


https://github.com/Kmmanki/portfolio_was

 

GitHub - Kmmanki/portfolio_was: portfolio

portfolio. Contribute to Kmmanki/portfolio_was development by creating an account on GitHub.

github.com

 

포트폴리오를 작성하는 이유

최근 이직을 위해 이력서를 작성하는데 자꾸 서류에서 탈락하고 있다.

포트폴리오가 없기 때문일까? 라는 생각에 포트폴리오를 작성하고자 한다.

 

포트폴리오는 WAS와 WEB으로 구성할 예정이다.

면접관이 보았을 때 가독성이 좋도록 작성을 하고 JAVA Doc과 같은 주석을 자세히 달고자 노력이 필요할 듯 하다.

 

메인 포지션은 Backend 이기 때문에 WAS 부터 구성을 하며 sweager를 통해 ui를 대채하며 진행하고 WAS가 어느정도 틀이 잡히면 WEB을 작성할 예정

 


WAS 정보(중간 중간 추가 및 변경 가능)

  • Java 17
  • Spring Boot 3.2.5

WAS 기타 라이브러리

  • swagger
  • JPA

기타 

  • Mysql

 


WEB 정보 (미정

  • React ?, Vue?

리액트 교과서 Chapter11(타이머)


// 시간 정보 timer 정보를 가지고 있는 wrapper 
class TimerWrapper extends React.Component {
  constructor(props) {
    super(props)
    this.state = {timeLeft : null, timer: null}
    this.startTimer = this.startTimer.bind(this)
  }

  // 타이머 시작, 타이머가 존재한다면 기존 타이머 제거
  // setInterval로 1초마다 시간이 줄어들도록
  startTimer(timeLeft){
    clearInterval(this.state.timer)
    let timer = setInterval(() => {
      var timeLeft = this.state.timeLeft - 1
      if (timeLeft <= 0) {
        clearInterval(this.state.timer)
      }
      this.setState({
        timeLeft :timeLeft
      })
      console.log("running")
    }, 1000);
    console.log("start")
    return this.setState({timeLeft: timeLeft , timer: timer})
  }

  // button에 startTimer와 각각 할당된 time 제공
  render() {
    return (
      <div>
        <h2>Timer</h2>
        <Button time="5" startTimer={this.startTimer}></Button>
        <Button time="10" startTimer={this.startTimer}></Button>
        <Button time="15" startTimer={this.startTimer}></Button>
        <Timer timeLeft={this.state.timeLeft}></Timer>
      </div>
    )
  }

}

// 제공된 time과 startTimer 사용
class Button extends React.Component {

  render() {
    return (
      <div>
        <button onClick={() => {this.props.startTimer(this.props.time)}}>{this.props.time}</button>
      </div>
    )
  }
}

// 상위로 wrapper로 부터 받은 시간을 표기 
class Timer extends React.Component {
  constructor(props) {
    super(props)
  }

  render(){
    return (
      <div>'
        <h2>{this.props.timeLeft}</h2>
      </div>
    )
  }
  
}


let timer = document.getElementById('timer')
let root = ReactDOM.createRoot(timer)

root.render(
  <TimerWrapper></TimerWrapper>
)

https://github.com/Kmmanki/react_note/tree/master/chapter11

 

GitHub - Kmmanki/react_note: 리액트 교과서 따라하기

리액트 교과서 따라하기. Contribute to Kmmanki/react_note development by creating an account on GitHub.

github.com

 

 

Kafka를 통해 데이터를 송신해야하는 케이스가 생겼다.

비지니스 로직상 빈도는 낮으나(한달에 한번도 호출 안한다.) 한번 발생하면 한번에 약 3만건의 데이터를 전송해야한다.

 

개발 후 consumer측과 테스트를 진행하던 도중 문제가 생겼는데

데이터를 단건 씩 보낼때는 이상이 없었으나 3만건을 반복문으로 계속 보냈더니 수신한 데이터의 건은 1,2000건이었다.....

 

LAG나 다른 kafak의 상태를  보고싶었지만 kafkacat과 같은 툴을 반입할 수 없고, kafka 서버에 직접 터미널로 접속할 수 없는 상태였다.

 

일단 송신과정에서 누락이 된것인가 싶어서 kafka producer의 ACKS옵션을 변경하였다.

 

acks

application.properties

spring.kafka.producer.acks=-1

 

acks의 옵션은 총 3가지로 -1, 0, 1이다.

  • 0 : 프로듀서가 kafka에 메시지를 전송하고 kafka로부터 잘 전송되었는지 응답을 받지 않는다.
  • 1 :  프로듀서가 kafka에 메시지를 전송하고 kafka의 leader가 잘 받았는지 응답을 받는다.
  • -1(all) : 프로듀서가 kafka에 메시지를 전송하고 kafka의 leader, follower가 잘 받았는지 응답을 받는다.

옵션 1, -1은 응답으로 실패를 받는다면 spring kafka가 재전송을 한다.

 


akcs를 적용후에도 동일한 증상이 발생.

단건 전송시에는 문제가 없었으니 데이터를 100건마다 Thread.sleep을 적용해보았다.

 

if (count % 100 == 0){
	Thread.sleep(1000)
}

 

수신측에서 모든 데이터가 들어왔다고 한다.

하지만 kafka 전송하는 로직이 @Service로 싱글톤 내부에 있는 메소드다.

 

싱글톤 내부의 메소드에서 Thread.sleep을 사용하게 되면 해당 로직이 끝나기 전까지는 블록상태가 된다.(맞나...?)

 


일단 kafka로 send하는 로직에 시간을 늘리면 해결된다는 부분은 확인을 했으니 방법을 찾아봤다.

 

Excuters로 별도의 스레드에 할당 할까 하였지만?

Kafka Producer의 다른 옵션들이 있는것을 확인

 


batch.size

메시지보관 사이즈로 linger의 옵션 시간동안 메시지를 쌓는다.

쌓인 메시지가 size보다 작으면 linger의 옵션까지 대기했다가 전송한다.

 

디폴트:16384

 

linger

linger.ms는 데이터 전송까지의 시간을 의미한다.

기본값은 0으로 데이터를 즉시 전송한다.

 

linger.ms = 10라면 10ms 마다 send한다.

 

단 batch.size만큼 데이터가 쌓여있다면 linger옵션을 무시하고 전송한다.

즉 batch.size가 꽉 찰 때 까지 기다리는 옵션

 

spring.kafka.producer.properties.linger.ms=10
// 혹은
spring.kafka.producer.linger.ms=10

Spring Kafka의 버전마다 해당 옵션 키값이 다른 듯 하다.

 

compression

메시지를 압축하는 옵션이다.

 

메시지를 압축하면 하지 않는 것 보다 발송 지연이 생기지만 비지니스 로직상 허용 가능한 부분이기에 추가하였다.

압축을 통하여 batch.size에 쌓이는 메세지의 수가 늘어나도록 설정하였다.

 

spring.kafka.producer.compression-type=snappy

 


 

+ Recent posts