Rental Application (React & Spring boot Microservice) - 16 : rental-service(2)
#1 service, repository
RentalService, RentalRepository를 구현하도록 하겠습니다.
- RentalService
package com.microservices.rentalservice.service;
import com.microservices.rentalservice.dto.RentalDto;
public interface RentalService {
RentalDto createRental(RentalDto rentalDto);
RentalDto getRentalByRentalId(String rentalId);
Iterable<RentalDto> getRentalsByOwner(String owner);
Iterable<RentalDto> getRentalsByBorrower(String borrower);
RentalDto deleteRental(String rentalId);
}
- RentalServiceImpl
package com.microservices.rentalservice.service;
import com.microservices.rentalservice.dto.RentalDto;
import com.microservices.rentalservice.entity.RentalEntity;
import com.microservices.rentalservice.repository.RentalRepository;
import com.microservices.rentalservice.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@Service
@Slf4j
public class RentalServiceImpl implements RentalService {
private RentalRepository rentalRepository;
@Autowired
public RentalServiceImpl(RentalRepository rentalRepository) {
this.rentalRepository = rentalRepository;
}
@Transactional
@Override
public RentalDto createRental(RentalDto rentalDto) {
log.info("Rental Service's Service Layer :: Call createRental write Method!");
RentalEntity rentalEntity = RentalEntity.builder()
.rentalId(UUID.randomUUID().toString())
.postId(rentalDto.getPostId())
.price(rentalDto.getPrice())
.owner(rentalDto.getOwner())
.borrower(rentalDto.getBorrower())
.startDate(rentalDto.getStartDate())
.endDate(rentalDto.getEndDate())
.createdAt(DateUtil.dateNow())
.build();
rentalRepository.save(rentalEntity);
return RentalDto.builder()
.rentalId(rentalEntity.getRentalId())
.postId(rentalEntity.getPostId())
.price(rentalEntity.getPrice())
.owner(rentalEntity.getOwner())
.borrower(rentalEntity.getBorrower())
.startDate(rentalEntity.getStartDate())
.endDate(rentalEntity.getEndDate())
.createdAt(rentalEntity.getCreatedAt())
.build();
}
@Transactional
@Override
public RentalDto getRentalByRentalId(String rentalId) {
log.info("Rental Service's Service Layer :: Call getRentalByRentalId Method!");
RentalEntity rentalEntity = rentalRepository.findByRentalId(rentalId);
return RentalDto.builder()
.rentalId(rentalEntity.getRentalId())
.postId(rentalEntity.getPostId())
.price(rentalEntity.getPrice())
.owner(rentalEntity.getOwner())
.borrower(rentalEntity.getBorrower())
.startDate(rentalEntity.getStartDate())
.endDate(rentalEntity.getEndDate())
.createdAt(rentalEntity.getCreatedAt())
.build();
}
@Transactional
@Override
public Iterable<RentalDto> getRentalsByOwner(String owner) {
log.info("Rental Service's Service Layer :: Call getRentalsByOwner Method!");
Iterable<RentalEntity> rentals = rentalRepository.findAllByOwner(owner);
List<RentalDto> rentalList = new ArrayList<>();
rentals.forEach(v -> {
rentalList.add(RentalDto.builder()
.rentalId(v.getRentalId())
.postId(v.getPostId())
.price(v.getPrice())
.owner(v.getOwner())
.borrower(v.getBorrower())
.startDate(v.getStartDate())
.endDate(v.getEndDate())
.createdAt(v.getCreatedAt())
.build());
});
return rentalList;
}
@Transactional
@Override
public Iterable<RentalDto> getRentalsByBorrower(String borrower) {
log.info("Rental Service's Service Layer :: Call getRentalsByBorrower Method!");
Iterable<RentalEntity> rentals = rentalRepository.findAllByBorrower(borrower);
List<RentalDto> rentalList = new ArrayList<>();
rentals.forEach(v -> {
rentalList.add(RentalDto.builder()
.rentalId(v.getRentalId())
.postId(v.getPostId())
.price(v.getPrice())
.owner(v.getOwner())
.borrower(v.getBorrower())
.startDate(v.getStartDate())
.endDate(v.getEndDate())
.createdAt(v.getCreatedAt())
.build());
});
return rentalList;
}
@Transactional
@Override
public RentalDto deleteRental(String rentalId) {
log.info("Rental Service's Service Layer :: Call deleteRental Method!");
RentalEntity rentalEntity = rentalRepository.findByRentalId(rentalId);
rentalRepository.delete(rentalEntity);
return RentalDto.builder()
.rentalId(rentalEntity.getRentalId())
.build();
}
}
- RentalRepository
package com.microservices.rentalservice.repository;
import com.microservices.rentalservice.entity.RentalEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface RentalRepository extends JpaRepository<RentalEntity, Long> {
RentalEntity findByRentalId(String rentalId);
Iterable<RentalEntity> findAllByOwner(String owner);
Iterable<RentalEntity> findAllByBorrower(String borrower);
}
코드 자체는 post-service와 비슷하고 메서드에 대한 설명은 이전 포스트에 RentalController를 구현하면서 설명을 했으니 참고하시길 바라겠습니다.
#2 kafka
rental-service는 post-service와 메시지 기반으로 통신을 할 서비스입니다. 시나리오는 다음과 같습니다.
1) 게시글을 통해 대여에 관한 수락이 된다면, rental-service에서는 대여에 관한 정보를 생성합니다.
2) 대여를 취소한다면, rental-service에서는 대여에 관한 정보를 취소합니다.
간단하게 생각해본 시나리오지만 메시지 기반으로 통신할 때는 여러 장점들이 존재합니다. 우선 Apache Kafka에 대해 알아보겠습니다.
Apache Kafka는 오픈 소스 메시지 브로커 프로젝트입니다.
위 사진처럼 service-x ~ z까지가 service-a ~ c에 요청을 하고있다고 가정해보겠습니다. 모든 요청들이 잘 처리되어진다면 최고의 상황이겠지만, 실제 상황에서는 service-a의 서버 다운, service-b의 과도한 처리로 인한 응답의 늦어짐 등등이 있겠죠. 이런 것들을 개선하기 위해 도입된 것이 메시지 브로커이고 대표적인 오픈소스 프로젝트가 Apache Kafka입니다.
위 사진처럼 중간에 kafka 메시지 브로커를 놓아주게 되면 다음과 같은 제가 생각하는 카프카를 사용했을 때 장점인 시나리오들을 처리할 수 있습니다.
1) service-a의 서버가 다운이 되어도 kafka에 메시지를 보내놓는다면 kafka를 구독하고 있는 service-a는 서버가 다시 구동이 되었을 때, 자신에게 온 메시지를 읽어서 요청을 처리할 수 있습니다.
2) service-b는 현재 처리할 요청들이 너무 많아 당장 요청을 받기 어렵습니다. 그래서 현재 요청들을 처리하고 그 다음에 다른 요청들을 처리하기 위해 kafka를 구독하고 순서대로 요청들을 처리할 수 있습니다.
3) service-z는 service-b, service-c에게 요청을 하고 싶습니다. 만약 각각 직접 요청을 해야한다면 service-z는 2번의 요청을 해야하고 2번의 응답을 받아야하죠. 하지만 kafka 메시지 브로커에 메시지를 보내고 b, c가 브로커를 구독하는 상황이라면 service-z는 한 번의 요청과 2번의 응답만 받으면 됩니다. 즉, 2번의 요청 -> 1번의 요청이라는 자원 낭비를 줄일 수 있죠.
Apache Kafka의 장점은 다음과 같습니다.
1) Low Latencty: 낮은 지연 시간을 갖습니다. 즉, 하나의 메시지를 보낼 때 이동하는데 걸리는 시간이 낮다는 의미이죠.
2) High Throughput: 높은 처리량을 갖습니다.
3) Fault Tolerance: 클러스터 내 노드 중 일부에서 결함이 생겨도 정상적 혹은 부분적으로 노드를 실행할 수 있게 합니다.
이 외에도 많은 장점들이 존재합니다.
#3 kafka 설치
kafka_2.13-2.8.0.tgz파일을 다운받고 MyRentalKafka라는 디렉토리를 만들어 압축 해제하도록 하겠습니다.
그리고 다음 명령어를 통해 Kafka Connect를 설치하고 압축해제 해주도록 하겠습니다.
curl -O http://packages.confluent.io/archive/6.1/confluent-community-6.1.0.tar.gz
tar xvf confluent-community-6.1.0.tar.gz
https://docs.confluent.io/kafka-connect-jdbc/current/index.html (아래 사진의 Download and extract the ZIP file) 로 이동해서 파일을 다운받고 kafka-connect-jdbc를 압축해제하도록 하겠습니다.
그리고 제 기준 /home/biuea/Desktop/MyRentalKafka/confluentinc-kafka-connect-jdbc-10.2.1/lib 경로를 복사해서 /home/biuea/Desktop/MyRentalKafka/confluent-6.1.0/etc/kafka/connect-distributed.properties 설정파일에 들어가 맨 하단에 있는 plugin.path를 다음과 같이 plugin.path=/home/biuea/Desktop/MyRentalKafka/confluentinc-kafka-connect-jdbc-10.2.1/lib 로 바꿔주도록 하겠습니다.
마지막으로 홈 디렉토리의 /home/biuea/.m2/repository/org/mariadb/jdbc/mariadb-java-client/2.7.2 경로로 가서 cp ./mariadb-java-client-2.7.2.jar /home/biuea/Desktop/MyRentalKafka/confluent-6.1.0/share/java/kafka로 파일을 복사하도록 하겠습니다.
이로써 kafka를 사용하기 위한 파일들을 다운받았고 다음 포스트에서는 이를 이용해서 post-service와 rental-service 간 메시지 통신을 진행해보겠습니다.
참고
인프런: Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA) - 이도원
Author And Source
이 문제에 관하여(Rental Application (React & Spring boot Microservice) - 16 : rental-service(2)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@biuea/Rental-Application-React-Spring-boot-Microservice-16-rental-service2저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)