실시간 채팅방 구현(3) - (프로젝트 수행시 고려점2)
포스트
취소

실시간 채팅방 구현(3) - (프로젝트 수행시 고려점2)

잘못된 이해로 비롯된 에러

1. spring-data-jpa save(S entity)

본 프로젝트에서는 Service Layer에서 트랜젝션처리를 수행한다. 또한 Repository는 data-jpa를 사용했다. 필자는 서비스 내 예외 발생 시, 원하는 값을 반환하고싶었다. 따라서 service내 try-catch로 UniqueKeyViolation 예외발생 시 값을 반환하는 코드를 추가했다. 하지만, 문제는 data-jpa에서 발생했다. save시, 먼저 select후 insert되는 점이였다. 만약 같은 id값을 가지는 객체가 존재한다면 persist가 아닌 merge가 되었었다. 즉, save는 이미 같은 key를 가지는 데이터가 존재하면 변경감지하여 update하며, 없을때만 insert되기에 예외처리가 수행되지 않았다.

아래는 data-jpa에서의 save() 이다.

1
2
3
4
5
6
7
8
9
10
@Transactional
@Override
public <S extends T> S save(S entity) {
    if (entityInformation.isNew(entity)) {
        em.persist(entity); // 원하는 흐름. 이쪽으로 갔을 때, UniqueKeyViolation 예외 발생한다.
        return entity;
    } else {
        return em.merge(entity); // 하지만 이쪽으로 흘러갔다.
    }
}

따라서 data-jpa를 사용하기 위해선 먼저 서비스에서 userRepository.findById(user.getUserId())과정을 필수적으로 작성해야한다.

1
2
3
4
5
6
7
8
9
10
    // userService
    @Override
    public ResponseEntity<?> save(User user) {
        Optional<User> findUser = userRepository.findById(user.getUserId());
        if (findUser.isPresent()) {
            return ResponseEntity.badRequest().body("해당 ID로 등록된 유저가 존재합니다");
        }
        userRepository.save(user);
        return ResponseEntity.ok(user);
    }

2. REST and Kafka

REST에서는 HTTP통신이기에 GET/POST를 구분할 수 있다. 하지만 Kafka는 이를 구분하지 않는다(물론 이를 지원해주는 Confluent Rest Proxy가 존재한다). Kafka는 data stream platform으로 그 형태자체가 다르기 때문이다. 이를 잠깐 깜빡하고 api를 다 짜놨는데 다시 고치려니 막막하다…

PostMapping("/user/{userId}")이런 url로 가져왔던 부분들을 수정해야한다. 즉, producer은 json에 모든 request 내용을 담아 전송하고 consumer에서 이를 읽는 Request/Response 형식으로 작성해야한다.

아래의 포스팅은 필자가 하고자 하는 방향인 Kafka를 Request/Response로 사용하는 것에 대한 고찰을 확인할 수 있다.

If you build a modern enterprise architecture and new applications, apply the natural design patterns that work best with the technology. Remember: Data streaming is a different technology than web services and message queues! CQRS with event sourcing is the best pattern for most use cases in the Kafka world:

Nevertheless, it is still only the second-best approach and is often an anti-pattern for streaming data.

reference : Request-Response in Kafka

또한 유저가 채팅을 보냈을 때, 제대로 서버에서 저장했는지 서버로부터 다시 받아봐야한다. 필자는 이를 웹소켓으로 받는다. 또 다르게 받아볼 수 있는 Server-Sent Event(SSE)방식이 존재해서 아래와 같이 링크를 남긴다.

Server-Sent Events (SSE) is a server push technology where clients receive automatic server updates through the secure http connection. SSE can be used in apps like live stock updates, that use one way data communications and also helps to replace long polling by maintaining a single connection and keeping a continuous event stream going through it. We used a simple Kafka producer to publish messages onto Kafka topics and developed a reactive Kafka consumer by leveraging Spring Webflux to read data from Kafka topic in non-blocking manner and send data to clients that are registered with Kafka consumer without closing any http connections. This implementation allows us to send data in a fully asynchronous & non-blocking manner and allows us to handle a massive number of concurrent connections. We’ll cover: •Push data to external or internal apps in near real time •Push data onto the files and securely copy them to any cloud services •Handle multiple third-party apps integrations

reference : Server Sent Events using Reactive Kafka and Spring Web flux

즉, SSE는 One-way connection that only server can send data to the client 이다. 본 프로젝트에서 채팅기능은 양방향 통신을 해야하기때문에 SSE는 해당 기능에서 제외한다. 또한 Conenction을 계속 유지해야하기때문에 서버의 리소스 소모가 꽤 클것으로 예상된다(물론 웹소켓도 마찬가지…).

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.