야구장 티켓을 예매하기 위해선 예매하고 싶은 날짜에 해당하는 좌석들이 생성되어야 합니다.
그래서 날짜 별 좌석 생성 API 를 만들었지만 좌석 생성 테스트를 할 때 시간이 너무 소요된다는 점을 파악하여 성능 개선이 필요하다고 느꼈습니다.
@Transactional
public void createSeatBucket(List<Seat> seats, LocalDate date) {
for (Seat seat : seats) {
String cacheKey = seatCommonHelper.makeCacheKey(seat, date);
Map<String, String> cacheValue = makeCacheValue(seat);
RBucket<Map<String, String>> bucket = redissonClient.getBucket(cacheKey);
bucket.set(cacheValue);
String blockKey = makeBlockKey(seat, date);
RList<String> blockSeats = redissonClient.getList(blockKey);
if (!blockSeats.contains(cacheKey)) {
blockSeats.add(cacheKey);
}
}
}
CacheKey - seat:20250526:101:1
CacheValue - status : "AVAILABLE"
seat:20250526:101
seat:20250526:101:1
seat:20250526:101:2
seat:20250526:101:3
...
RBatch batch = redissonClient.createBatch();
// batch 를 통해 bucket 에 값 설정
batch.getBucket(cacheKey).setAsync(cacheValue);
// batch 실행 명령어
batch.execute();
final int batchSize = 1000;
@Transactional
public void createSeatBucket(List<Seat> seats, LocalDate date) {
final int batchSize = 1000;
int operationCount = 0;
RBatch batch = redissonClient.createBatch();
Map<String, List<String>> blockSeatKeysMap = new HashMap<>();
for (Seat seat : seats) {
String cacheKey = seatCommonHelper.makeCacheKey(seat, date);
Map<String, String> cacheValue = makeCacheValue(seat);
batch.getBucket(cacheKey).setAsync(cacheValue);
String blockKey = makeBlockKey(seat, date);
blockSeatKeysMap.computeIfAbsent(blockKey, k -> new ArrayList<>()).add(cacheKey);
operationCount++;
// 배치 처리 후 남은 좌석들을 한번에 처리
if (operationCount % batchSize == 0) {
executeBatch(batch, blockSeatKeysMap);
batch = redissonClient.createBatch();
blockSeatKeysMap.clear();
}
}
if (!blockSeatKeysMap.isEmpty()) {
executeBatch(batch, blockSeatKeysMap);
}
}
private void executeBatch(RBatch batch, Map<String, List<String>> blockSeatKeysMap) {
for (Map.Entry<String, List<String>> entry : blockSeatKeysMap.entrySet()) {
batch.getSet(entry.getKey()).addAllAsync(entry.getValue());
}
batch.execute();
}