일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- MSA
- 파이썬
- IT
- 자바
- JavaScript
- react
- c언어
- Data Structure
- 네트워크
- Kafka
- C
- MySQL
- Heap
- JPA
- redis
- 디자인 패턴
- OS
- 운영체제
- spring webflux
- Spring
- design pattern
- Galera Cluster
- Java
- 알고리즘
- 컴퓨터구조
- Proxy
- 자료구조
- 백준
- Algorithm
- mongoDB
- Today
- Total
시냅스
Spring 예제로 보는 중복 Request 방지, GUID (≒ UUID) 본문
GUID
GUID 는 Globally Unique Identifier 의 약자입니다.
특정한 난수를 사용하며 유일성을 보장하기 위해 임의로 생성됩니다.
많은 곳에서 사용되고 있지만 오늘은 Network 통신을 하며 사용되는 사례를 살펴볼까 합니다.
GUID 혹은 UUID 는 중복 요청을 방지하는 데 사용될 수 있습니다.
클라이언트가 서버로 어떤 request 를 보낼 때 혹은 서버에서 서버로 보낼 때
고유한 식별자를 사용해서 해당 request가 중복된 요청인지 여부를 판가름 할 수 있습니다.
따라서 같은 요청을 100번 보내도, 서버에서는 1번만 처리하게 되는 것입니다.
어떨 때 사용할까?
앞서 timeout 에 대해 알고 계시면 더욱 읽기 수월합니다.
https://liltdevs.tistory.com/173
이를테면 클라이언트 A 는 서버 B 에게 request를 보냈지만
클라이언트 입장에서 timeout 에러가 발생했다면 request가 보내졌는지,
보내졌다면 server가 요청을 처리했는지에 대한 여부는 알기 어렵습니다.
그렇다면 request 를 다시 보내야 할 것입니다.
다만, 그 요청이 결제와 관련된 일이라면 굉장히 복잡해질 수 있습니다.
운이 좋아 서버에서 처리하지 않아 결제가 되지 않았다면 다행이지만
그날 운세가 좋지 않았다면 100만원 결제를 2번 하게 될 수 있는 상황이기 때문입니다.
이는 서버 간의 통신에서도 마찬가지 입니다.
A 서버에서 B 서버로 요청을 보내며 read timout 이 발생하여
retry 를 하는 상황에서도 운이 좋지 않으면 같은 요청을 2번 보내게 됩니다.
아래에서는 이에 대한 해결책으로 GUID ( UUID ) 에 대한 활용법을 살펴보겠습니다.
예시
예시는 의외로 단순할 수 있습니다.
public class MyResource {
private String guid;
// other fields, constructors, getters, setters
public String getGuid() {
return guid;
}
public void setGuid(String guid) {
this.guid = guid;
}
}
중복에 대한 판별을 하게 될 guid 를 갖고 있는 객체입니다.
필요에 따라서 다른 필드들을 갖게 될 수 있습니다.
@Service
public class MyService {
private Set<String> processedGuids = new HashSet<>();
public synchronized boolean isGuidValid(String guid) {
if (processedGuids.contains(guid)) {
return false;
}
processedGuids.add(guid);
return true;
}
public void processRequest(String guid) {
// process request
}
}
서비스에서는 중복된 request 인지 판별하게 됩니다.
서비스에는 set 을 가지고 있고
만약 중복되지 않은 request 라면 guid를 set에 추가하여 true를,
중복된 request 라면 false를 반환합니다.
isGuidValid 는 동시성을 고려하여 synchronized 로 구현되어 있습니다.
(위의 set은 실제로는 다른 제품으로 구현해야 할 것입니다. DB 나 Redis를 고려해볼 수도 있겠습니다.)
@RestController
@RequestMapping("/api")
public class MyController {
@Autowired
private MyService myService;
@GetMapping("/resource")
public MyResource getResource() {
String guid = UUID.randomUUID().toString();
MyResource resource = new MyResource();
resource.setGuid(guid);
return resource;
}
@PostMapping("/resource")
public ResponseEntity<?> createResource(@RequestBody MyResource resource) {
if (!myService.isGuidValid(resource.getGuid())) {
return ResponseEntity.status(HttpStatus.CONFLICT).build();
}
myService.processRequest(resource.getGuid());
return ResponseEntity.ok(resource);
}
}
GET /resource 에서 guid 를 갖게 되는 resource 를 반환 한 뒤에
실제로 POST /resource 에 반환한 resource와 함께 요청이 들어오면 정의했던 메소드들을 토대로 진행합니다.
따라서 guid 를 토대로 중복된 요청이라면 CONFLICT 를 내려주고 중복되지 않은 경우 진행합니다.
위에서 본 예시는 서버에서 GUID 를 내려준 형태이지만,
클라이언트에서 GUID를 생성하여 request를 보내는 상황에서도 비슷하게 구현할 수 있겠습니다.
'Java, Spring' 카테고리의 다른 글
Spring 과 Ulimit, Socket 자원 관리에 대해 (0) | 2023.03.05 |
---|---|
JVM 의 Xmx 와 Xms 를 지정해야 하는 이유에 대해 (2) | 2023.03.02 |
Java 코드로 보는 Connection 관련 timeout 에러 정리 (0) | 2023.03.01 |
Java 코드와 예제로 보는 Thread Dump 활용 방법 (0) | 2023.03.01 |
Java 코드로 알아보는 직렬화와 역직렬화 (0) | 2023.02.28 |