
프론트 개발자로부터 사용자의 위치 정보를 2~3초 주기로 실시간으로 받아 데이터베이스에 저장해야 하는 상황이 생겼습니다.
이 상황에서 HTTP의 Stateless, Connectionless한 특성 때문에, HTTP 프로토콜을 사용하는 것이 적절하지 않다고 판단하였습니다. HTTP 통신을 하게 되면 매 위치 정보 요청마다 새로운 연결이 필요하게 되며, 이로 인해 서버에 과도한 부하를 초래할 수 있다고 생각했습니다.
그리하여 실시간 통신에 적합한 프로토콜인 WebSocket을 사용하기로 결정했습니다.
WebSocket 프로토콜
웹 소켓이란 서버와 클라이언트가 서로 실시간 메시지를 교환하기 위한 통신 방법입니다.

1. 클라이언트가 서버로 HTTP 프로토콜을 사용하여 최초 연결 요청을 하고, 응답을 받는 Handshake가 성공하면, 둘 간의 통신 프로토콜이 WebSocket으로 전환됩니다.
2. 연결이 완료되면, 클라이언트와 서버 간의 메시지를 주고받습니다. 메시지는 Frame 단위로 이루어집니다.
3. 연결 종료를 원하는 클라이언트 혹은 서버가 Close Frame을 상대 쪽으로 전송하여 연결을 종료합니다.
코드 작성
클라이언트에서 서버로 넘기는 위치 정보는 아래와 같습니다.
{"speed":0.027319271190629997,"heading":-1,"longitude":127.07289423207014,"accuracy":14.11364924371093,"latitude":37.54535705340557,"altitudeAccuracy":10.257959754288219,"altitude":38.98178774211556, "userId":4,"postId":5}
1. WebSocket을 사용하기 위한 라이브러리 추가
implementation 'org.springframework.boot:spring-boot-starter-websocket'
2. 웹소켓 Config
@Configuration
@EnableWebSocket
@RequiredArgsConstructor
public class WebSocketConfig implements WebSocketConfigurer {
private final WebSocketHandler webSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(webSocketHandler, "/tracking").setAllowedOrigins("*");
}
}
- @EnableWebSocket: 스프링 애플리케이션에서 웹소켓 기능을 사용
- WebSocketConfigurer: 웹소켓 핸들러 등록과 같은 웹소켓 관련 설정 커스터마이즈
- addHandler: "/tracking"이라는 경로로 웹소켓 요청이 오면, WebSocketHandler를 통해 처리
- setAllowedOrigins("*"): 모든 도메인에서의 웹소켓 연결 요청을 허용
3. 웹소켓 헨들러
@Component
public class WebSocketHandler extends TextWebSocketHandler {
private final LocationRepository locationRepository;
public WebSocketHandler(LocationRepository locationRepository) {
this.locationRepository = locationRepository;
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String id = session.getId(); //메시지를 보낸 아이디
JSONParser jsonParser = new JSONParser();
Object obj = jsonParser.parse(message.getPayload());
JSONObject jsonObject = (JSONObject)obj;
Location location = Location.builder()
.sessionId(id)
.position(message.getPayload())
.userId(jsonObject.get("userId").toString())
.postId(jsonObject.get("postId").toString())
.build();
locationRepository.save(location);
String responseMessage = "메시지 잘 받았소, sessionId: " + id;
session.sendMessage(new TextMessage(responseMessage));
}
}
- TextWebSocketHandler: 텍스트 기반의 WebSocket 메시지를 처리
- JSONParser, JSONObject: 메시지 페이로드를 JSON 객체로 파싱하여 userId, postId 추출
- sendMessage: 응답 메시지 전송
4. 위치 정보 Location 클래스
@Getter
@Entity
@NoArgsConstructor
public class Location {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String sessionId;
private String position;
private String userId;
private String postId;
@Builder
public Location(String sessionId, String position, String userId, String postId) {
this.sessionId = sessionId;
this.position = position;
this.userId = userId;
this.postId = postId;
}
}
결과 확인
1. 웹소켓 연결

2. 메시지 요청 및 응답

3. DB 저장 확인

맨 아래 잘 저장된 것을 확인할 수 있습니다.
참고자료
SpringBoot + WebSocket server 간단하게 구현해보기
스프링부트에서 웹소켓 서버 세팅을 하여 실시간으로 메세지를 주고받을 수 있는 서버를 만들어 보겠습니다. 정말 간단합니다. 먼저 의존성을 주입해줍시다. [Gradle] implementation 'org.springframework.b
yjkim-dev.tistory.com
채팅서비스를 구현하며 배워보는 Websocket 원리 (feat. node.js)
본 포스팅에서는 Websocket 의 원리를 배우고, node.js 의 ExpressJS 프레임워크에서 Websocket 서버를 만들어 웹브라우저와 실시간 통신으로 간단한 채팅을 만드는 것을 목표로 한다. 1. Websocket 이란? 1-1.
hudi.blog
'기타' 카테고리의 다른 글
| 인프콘 2023 후기 (0) | 2023.08.16 |
|---|---|
| 단위 테스트(Unit Test) 공부하기 (0) | 2023.07.31 |
느리더라도 단단하게 성장하고자 합니다!
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!