π λμ λ°°κ²½
All:Chive μλΉμ€μ νκ·Έ, μμΉ΄μ΄λΉ μ λͺ©μ λ°νμΌλ‘ κ²μνλ λΆλΆμ΄ μλ€.
λ€μ΄λ²λ κ΅¬κΈ λ±μμ κ²μν λ, κ²μμ΄μ μΌλΆλΆμ μ λ ₯ν κ²½μ°, μ μλ κ²μμ΄ λͺ©λ‘μ΄ μ€μκ°μΌλ‘ λνλλ μλ μμ± κΈ°λ₯μ΄ μλ€.
All:Chive μλΉμ€μλ μ΄λ₯Ό λμ νκ³ μΆμλ€.
κ·Έλμ μμνλ€.
π DB μ ν
μ΄ μλΉμ€λ₯Ό ꡬνν¨μ μμ΄μ μμΈ(?) κ΄λ ¨ λ°μ΄ν°λ₯Ό μ μ₯ν΄μΌ νλ€.
λλ μ΄ 3κ°μ DBλ₯Ό κ³ λ €νλ€.
μλλ λ΄κ° μ μ΄ DBλ₯Ό μ ν νΉμ μ ννμ§ μμ μ΄μ μ΄λ€.
π΅ Elastic Search
λ°μ΄ν° μ μ₯, κ²μμ μμ΄μ λ°μ΄λ μ±λ₯μ κ°μ§κ³ μλ€κ³ μλ €μ§ DBμ΄λ€.
μ΄κ²μ μ¬μ©νκΈ° μν΄μ μλ‘μ΄ μμ€ν μ λμ ν΄μΌ νλ€.
νλ‘μ νΈλ₯Ό μ§ννλ μλ² κ°λ°μκ° 1λͺ μΈ μν©μμ, κ΄λ¦¬ ν¬μΈνΈλ₯Ό νλ λ리λ κ²μ΄ λΆλ΄μ€λ½κ² λ€κ°μλ€.
λν λ΄κ° μκ°νλ λ‘μ§μΌλ‘ ꡬνν μ μμ κ² κ°μλ€.
Elastic Searchλ₯Ό μ΄μ©νλ©΄ ν¨μ¬ μμ μ μΌλ‘ μλν μ μμ κ²μ΄λ€.
νμ§λ§ λ΄ μμΌλ‘ μ§μ ꡬννκ³ μΆμλ€.
μ΄μ λλ Elastic Searchλ₯Ό μ¬μ©νμ§ μμλ€.
π΅ MySQL
μ΄λ―Έ μλΉμ€ DBλ‘ MySQLμ μ¬μ©νκ³ μλ μν©μ΄μλ€.
μ΄μ μΆκ°μ μΈ μμ€ν λμ μ΄ νμ μμλ€.
νμ§λ§ λλ μ΄λ₯Ό μ ννμ§ μμλ€.
μ΄μ λ μλ λλ¬Έμ΄λ€.
μ°λ¦¬λ κ²μμ΄ μλ μμ± μλΉμ€λ₯Ό λ€μ΄λ², ꡬκΈμμ νν λ³Ό μ μλ€.
μ°λ¦¬κ° κΈμλ₯Ό νμ΄ννλ μμ€μλ κ°μ΄ λΉ λ₯΄κ² λ°λλ κ²μ λ³Ό μ μλ€.
λΉ λ₯΄κ² μλ μμ± λ°μ΄ν°λ₯Ό μ κ³΅ν΄ μ£Όλ κ²μ΄λ€.
μ΄μ²λΌ λ§μ λ°μ΄ν°μ μμ΄μ λΉ λ₯Έ μ‘°νλ₯Ό μ 곡νλ κ²μ΄ μ€μνλ€.
μ΄ λΆλΆμ μμ΄μ RDB λ³΄λ€ μΈλ©λͺ¨λ¦¬ DBκ° λ λΉ λ₯Έ μ‘°ν μ±λ₯μ κ°μ§λ€.
κ·Έλ¬λ―λ‘ RDBλ₯Ό μ¬μ©νμ§ μμλ€.
π΅ Redis
Redis λν μλΉμ€μμ μ¬μ©νκ³ μμκΈ°μ, μΆκ°μ μΈ μμ€ν λμ μ λν μ°λ €κ° μμλ€.
μΈλ©λͺ¨λ¦¬ DBλ‘ RDBλ³΄λ€ λ λΉ λ₯Έ μ‘°ν μ±λ₯μ κ°μ§λ€.
λν μλ£κ΅¬μ‘°λ₯Ό μ ννμ¬ μ λ ¬λ μνλ‘ μλ£κ° μ μ₯λλλ‘ ν μ μμλ€.
μ΄μ Redisλ₯Ό μ΄μ©νκΈ°λ‘ νλ€.
π Redis κΈ°λ° κ²μμ΄ μλ μμ± κΈ°λ₯
π΅ μ΄μ©ν μ리
ballκ³Ό bearλΌλ λ°μ΄ν°κ° μλ€κ³ νμ
bλ₯Ό κ²μνμ λλ λ λ¨μ΄ λͺ¨λκ° κ²μλκ³ , baλ₯Ό κ²μνμ λλ ballλ§ κ²μλμ΄μΌ νλ€.
μ΄λ₯Ό μ΄λ»κ² ꡬνν΄μΌ ν κΉ?
DFS μκ³ λ¦¬μ¦μ ν΅ν΄ μ΄λ€ λ¬Έμ μ λν κ²½μ°μ μλ₯Ό ꡬν μ μλ€.
μ΄ κ²½μ° λΆλͺ¨ λ Έλμ κ°μ λμ νμ¬ μμ λ Έλμμ μ΄ κ°μ μ΄μ©νλ€.
μμ κ°μ λ°©μμ trieμ μ μ©νκ³ , λͺ¨λ λ Έλμμ λΆλͺ¨ λ Έλμ μμ μ κ°μ ν©μ³μ μΆλ ₯νλλ‘ νλ©΄ μ΄λ€ κ²°κ³Όκ° λμ¬κΉ?
μμ κ°μ νΈλ¦¬κ° μμ λ, κ²°κ³Όλ μλμ κ°λ€. (μ€λ¦μ°¨μ μν κΈ°μ€)
a
ab
aba
abc
ad
b
ba
bad
bag
μ΄λ, trieμ λΆλͺ¨ λ Έλμ μμ λ Έλ κ° νΉμ±μ κ³ λ €ν΄ λ³΄μ.
trieμ μμ λ Έλλ 리ν λ ΈλλΆν° λΆλͺ¨ λ ΈλκΉμ§μ λ¨μ΄λ₯Ό μ λμ΄λ‘ μ¬μ©νλ λ¨μ΄μ΄λ€.
μ¦, μ κ²°κ³Ό κ°μμ λΆλͺ¨ λ Έλκ° μμ λ Έλλ³΄λ€ μμ μΆλ ₯λλ―λ‘, νΉμ λ¨μ΄κ° μ‘΄μ¬ν λ, μ΄ λ¨μ΄λ λ€μ μμΉν λ¨μ΄μ λΉμ·ν λ¨μ΄λΌκ³ ν μ μλ€.
κ·Έλ¬λ―λ‘ μ΄λ¬ν μ μ μ΄μ©νμ¬ λ¨μ΄λ₯Ό μΆμΆνκ³ μ νλ€.
μ΄λ¬ν μ μ μ΄μ©νμ¬ κ΅¬ννκ³ μ νλ€.
κΈ°λ₯ ꡬνμ ν¬κ² λ λΆλΆμΌλ‘ λλλ€.
- κ²μμ΄ μλ μμ± λ°μ΄ν° μ μ₯
- κ²μμ΄ μλ μμ± λ°μ΄ν° λΆλ¬μ€κΈ°
μλλ μ΄μ λν μμΈν μ€λͺ μ΄λ€.
π΅ κ²μμ΄ μλ μμ± λ°μ΄ν° μ μ₯
μ μ₯μ Redisμ Sorted Setμ μ΄μ©νλ€.
Sorted Setμ key, member, scoreλ‘ κ΅¬μ±λλ€.
μ΄λ, score μμΌλ‘ μ λ ¬λλ©°, scoreκ° κ°μ κ²½μ° memberλ‘ μ λ ¬λλ€.
κ·Έλ¬λ―λ‘ scoreλ₯Ό λμΌνκ² ν μνμμ λ¨μ΄λ₯Ό μ μ₯ν κ²½μ°, μλμ μΌλ‘ μ€λ³΅ μμ΄ μ¬μ μμΌλ‘ λ°°μΉκ° λλ€.
μ΄ μ μ λ°μ΄ν° μ μ₯κ³Ό μ‘°νμ μ΄μ©νλ€.
λ°μ΄ν° μ μ₯μ μμ -> μλ‘μ΄ λ°μ΄ν° μ μ₯ μμλ‘ μ§νλλ€.
λ°μ΄ν° μ μ₯μ μμ΄μ μλ‘μ΄ λ°μ΄ν°κ° μκ²Όμ λ, μ¦μ λ°μ΄ν°λ₯Ό μ λ‘λνλ κ²μ΄ μλλΌ μ€μΌμ€λ¬λ‘ μμ μ μ²λ¦¬νλ€.
κ²μμ΄ μλ μμ± λ°μ΄ν°μ κ²½μ° μ€μκ°μΌλ‘ μ 곡λλ λ°μ΄ν°κ° νμ μλ€κ³ μκ°νκΈ° λλ¬Έμ΄λ€.
μ€μκ°μ±μ 보μ₯νκΈ° μν΄ μμ€ν μ λΆνλ₯Ό λ리λ λ°©λ²λ³΄λ¨, μμ€ν μ μμ μ μΌλ‘ μ΄μνλ κ²μ μ΄μ μ λ§μ·λ€.
κ·Έλμ μ΄ μμ μλ μ€μΌμ€λ¬ cron μ‘μ μ΄μ© νλ€.
1. κΈ°μ‘΄ λ°μ΄ν° μμ
μ°μ Key κ°μ μ΄μ©ν΄ κΈ°μ‘΄ λ°μ΄ν°λ₯Ό μμ νλ€.
2. μλ‘μ΄ λ°μ΄ν° μ μ₯
κ²μμ΄μ νΉμ±μ, μ λ ₯κ°μ΄ μλ²½ν λ¨μ΄κ° μλ κ°λ₯μ±μ΄ λλ€.
κ·ΈλΌμλ λΆκ΅¬νκ³ κ·Έμ λΉμ·ν λ¨μ΄λ₯Ό λ°νν΄μ€μΌ νλ―λ‘, μμ μ€λͺ ν μμ΄λμ΄λ₯Ό μ΄μ©νλ€.
λ¨μ΄λ₯Ό μ²μλΆν° κΈμ νλμ© λλ €κ°λ©° μ μ₯νλ€.
ballμ κ²½μ°, b ba bal ball μμΌλ‘ μ μ₯νλ€λ λ§μ΄λ€.
μ΄λ, μλ²½ν λ¨μ΄ ball, bearμ κ²½μ° λ§¨ λ€μ *λ₯Ό λΆμ¬μ μ μ₯νλ€.
μλλ bear, ball λ λ¨μ΄κ° μ μ₯λ ννμ΄λ€
b
ba
bal
ball*
be
bea
bear*
Sorted Set μ΄λ―λ‘ μ€λ³΅λ bλ ν λ²λ§ μ μ₯λκ³ , λ€λ₯Έ λ¨μ΄λ€μ μ λ ¬λμ΄ μ μ₯λλ€.
μ΄λ₯Ό λͺ¨λ κ³Όμ μ μ½λλ‘ κ΅¬ννλ©΄ μλμ κ°λ€.
@UseCase
@Slf4j
@RequiredArgsConstructor
public class RenewalSearchDataUseCase {
private final ArchivingAdaptor archivingAdaptor;
private final TagAdaptor tagAdaptor;
private final RedisTemplate<String, String> redisTemplate;
@Scheduled(cron = "0 0 3 * * *")
@Transactional(readOnly = true)
public void executeSchedule() {
log.info("renewal title scheduler on");
renewalData();
log.info("renewal title scheduler off");
}
private void renewalData() {
redisTemplate.delete(SEARCH_KEY);
renewalArchiving();
renewalTag();
}
private void renewalTag() {
Set<Tag> tags = new HashSet<>(tagAdaptor.findAll());
tags.forEach(
tag -> {
redisTemplate.opsForZSet().add(SEARCH_KEY, tag.getName().trim() + ASTERISK, 0);
for (int index = 0; index <= tag.getName().length(); index++) {
redisTemplate
.opsForZSet()
.add(SEARCH_KEY, tag.getName().trim().substring(0, index), 0);
}
});
}
private void renewalArchiving() {
Set<Archiving> archivings =
new HashSet<>(archivingAdaptor.findAllByPublicStatus(Boolean.TRUE));
archivings.forEach(
archiving -> {
redisTemplate
.opsForZSet()
.add(SEARCH_KEY, archiving.getTitle().trim() + ASTERISK, 0);
for (int index = 0; index <= archiving.getTitle().length(); index++) {
redisTemplate
.opsForZSet()
.add(
SEARCH_KEY,
archiving.getTitle().trim().substring(0, index),
0);
}
});
}
}
π΅ κ²μμ΄ μλ μμ± λ°μ΄ν° λΆλ¬μ€κΈ°
μμμ μ μ₯ν κ°μ μ΄μ©ν΄ λ°μ΄ν°λ₯Ό κ°μ Έμ ν΄λΌμ΄μΈνΈλ‘ λ°νν΄ μ£Όλ κ³Όμ μ΄λ€.
νΉμ λ¨μ΄ μ΄νμ μμΉν λ¨μ΄ μ€ μμ±λ λ¨μ΄λ₯Ό κ°μ Έμ€λ©΄ μ΄λ₯Ό μνν μ μλ€.
μ¬κΈ°μ κ°μ₯ μ€μν κ³Όμ μ rank()λ₯Ό μ΄μ©ν΄ μ λ ₯κ°κ³Ό κ°μ₯ λΉμ· νΉμ κ°μ κΈμμ Indexλ₯Ό ꡬνλ κ²μ΄λ€.
μ΄ index κ° λ€μ μλ κ°μ ν΄λΉ λ¨μ΄μ μ μ¬λκ° λμ λ¨μ΄λ€μ΄λ€.
κ·Έλ¬λ―λ‘ ν΄λΉ λ¨μ΄ λ€μμ κ°μ μλ μμ± λ°μ΄ν°λ‘ μ¬μ©ν μ μλ€.
μ΄μ μλμ κ°μ λ°©μμ ꡬννλ€.
1. μ λ ₯ κ°κ³Ό κ°μ₯ λΉμ·ν νΉμ κ°μ κΈμμ Sorted Set λ΄μμμ Index κ°μ ꡬνλ€.
rank() ν¨μλ₯Ό ν΅ν΄ μ λ ₯κ°κ³Ό μ μ¬ν κ°μ indexλ₯Ό κ°μ Έμ¨λ€
2. Index ~ Index + 100μ ν΄λΉνλ λ¨μ΄λ₯Ό κ°μ Έμ¨λ€.
μ΅λ 5κ°μ΄μ§λ§ μ μ¬λ¬ κΈμλ₯Ό κ°μ Έμ¬κΉ?
μμμ λ°μ΄ν°λ₯Ό μ μ₯ν νμμ 보μ.
ν λ¨μ΄λ₯Ό μλΌμ μ μ₯νλ€.
κ·Έλ¬λ―λ‘ 5κ°λ§ κ°μ Έμ¬ κ²½μ°, κ·Έ 5κ°μ λ¨μ΄μ μλ²½ν λ¨μ΄κ° μμ μ μλ€.
κ·Έλ¬λ―λ‘ 100κ°μ λ°μ΄ν°λ₯Ό κ°μ Έμ€λλ‘ νλ€.
μ μ₯ν λ°μ΄ν°μ μ΅λ κΈΈμ΄κ° 20μ΄μλ€.
λ°μ΄ν° μ μ₯ μ μ΅μ μ κ²½μ°λ λ°μ΄ν° κ° μλ‘ μ°κ΄μ΄ μλ κ²½μ°μ΄λ€.
λ¨μ΄ 5κ°λ₯Ό μ μ₯νμ λ. μμ κ°μ μν©μ΄ λ²μ΄μ§ κ²½μ°, μ μ₯λ λ°μ΄ν°λ 5 * 20κ° μ¦, 100κ°μ΄λ€.
κ·Έλ¬λ―λ‘ 100κ°λ₯Ό μ‘°ννμ λ, 5κ°μ λ°μ΄ν°λ₯Ό μ‘°νν μ μλ€λ μ μ΄ λ³΄μ₯λλ€.
κ·Έλμ 100κ°μ λ°μ΄ν°λ₯Ό μ‘°ννλ€.
3. μλ²½ν λ¨μ΄λ₯Ό μ΅λ 5κ° νν°λ§νλ€.
λ°μ΄ν°λ₯Ό μ μ₯ν λ, μλ²½ν λ¨μ΄μ κ²½μ° *λ₯Ό λ€μ λΆμ¬μ μ μ₯νλ€.
κ·Έλ¬λ―λ‘ κ°μ Έμ¨ λ°μ΄ν° μ€ *μ΄ λΆμ λ¨μ΄ 5κ°λ§ μΆλ €λ΄λ©΄ λλ€.
μλλ μ΄λ₯Ό ꡬνν μ½λμ΄λ€.
@UseCase
@RequiredArgsConstructor
public class GetRelativeSearchListUseCase {
private final RedisTemplate<String, String> redisTemplate;
@Transactional
public SearchListResponse execute(String word) {
validateExecution(word);
ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
List<String> autoCompleteList = new ArrayList<>();
Long rank = zSetOperations.rank(SEARCH_KEY, word);
if (rank != null) {
Set<String> rangeList = zSetOperations.range(SEARCH_KEY, rank, rank + 100);
autoCompleteList = getAutoCompleteList(rangeList, word);
}
return SearchListResponse.from(autoCompleteList);
}
private void validateExecution(String word) {
StringParamUtil.checkEmptyString(word);
}
private List<String> getAutoCompleteList(Set<String> rangeList, String keyword) {
return rangeList.stream()
.filter(value -> value.endsWith(ASTERISK) && value.startsWith(keyword))
.map(value -> StringUtils.removeEnd(value, ASTERISK))
.limit(5)
.toList();
}
}
μ΄λ¬ν λ°©μμΌλ‘ Redisλ₯Ό μ΄μ©ν΄ κ²μμ΄ μλ μμ± κΈ°λ₯μ ꡬνν μ μμλ€.
π λ§λ¬΄λ¦¬
μ΄ κ΅¬νμ μμ΄μ λͺ κ°μ§ νκ³μ μ΄ μ‘΄μ¬νλ€.
- ν€ νλμ λ§μ μμ λ°μ΄ν°κ° μ μ₯λλ€.
ν€ νλμ λ§μ λ°μ΄ν°κ° μ μ₯λλ€λ©΄, λ°μ΄ν° μ‘°ν μ±λ₯μ΄ λ¨μ΄μ§λ€.
'a'λ₯Ό κ²μνμ λ, 'b'λ‘ μμνλ λ°μ΄ν°λ₯Ό λ³Ό νμ μμΌλ―λ‘, μνλ²³ 첫 κΈμλ‘ ν€λ₯Ό λΆλ¦¬νλ€λ©΄ λ ν¨μ¨μ μ΄μ§ μμκΉ μκ°νλ€. - μλΉμ€λ₯Ό μ 곡νμ§ λͺ»νλ μκ°μ΄ μ‘΄μ¬νλ€.
μμ λ λ°μ΄ν°λ₯Ό κ²μμ΄μμ μ§μ°κΈ° μν΄μ μ 체 리λ΄μΌμ΄ νμνλ€
νμ§λ§ λ°μ΄ν° μμ΄ λ§μμ§λ§, λ°μ΄ν° 리λ΄μΌμ μκ°μ΄ λ§μ΄ μμλ κ²μ΄κ³ , μ΄λ μλΉμ€ μ 곡 λΆκ°λ₯ μκ°μ΄ κΈΈμ΄μ§μ μλ―Ένλ€. - μλ§μ μΏΌλ¦¬κ° λ°μνλ€.
μ±κΈ μ€λ λμ΄λ―λ‘ λ§μ μμ μΏΌλ¦¬κ° λ°μνλ©΄, κ²°κ΅ μΏΌλ¦¬λ€ λλ¬Έμ μμ€ν μ λΆνκ° λ°μν μ μμ κ²μ΄λ€.
bulk μμ μΌλ‘ λ체ν΄λ λ κ²μ΄λΌ μκ°νλ€. - μλ‘ μ°κ΄μ±μ΄ λ¨μ΄μ§λ λ΅μ΄ λμ¨λ€.
λ°μ΄ν° μμ΄ μ λ€λ©΄, baλ₯Ό κ²μνμ λ κ²°κ³Ό κ°μΌλ‘ catμ΄ λμ¬ μ μλ€.
μ΄λ¬ν μ μ μμ΄μ κ°μ μ΄ νμν κ²μ΄λΌ μκ°νλ€.
π μλΉμ€ κ°μ
μ΄μ μ μΈκΈνλ νκ³μ μ κ°μ ν΄ λ΄€λ€.
@UseCase
@Slf4j
@RequiredArgsConstructor
public class RenewalSearchDataUseCase {
private final ArchivingAdaptor archivingAdaptor;
private final TagAdaptor tagAdaptor;
private final RedisTemplate<String, String> redisTemplate;
@Scheduled(cron = "0 0 3 * * *")
@Transactional(readOnly = true)
public void executeSchedule() {
log.info("renewal title scheduler on");
renewalData();
log.info("renewal title scheduler off");
}
@Transactional(readOnly = true)
public void executeForce() {
renewalData();
}
private void renewalData() {
delete();
renewalArchiving();
renewalTag();
}
private void delete() {
redisTemplate.executePipelined((RedisCallback<Object>)
redisConnection -> {
for (char c = 'A'; c <= 'Z'; c++) {
String key = SEARCH_KEY + c;
redisConnection.del(key.getBytes());
}
for (int index = 0; index < 19; index++) {
String key = SEARCH_KEY + KOREAN_ALPHA[index];
redisConnection.del(key.getBytes());
}
for (int index = 0; index < 9; index++) {
String key = SEARCH_KEY + index;
redisConnection.del(key.getBytes());
}
redisConnection.del((SEARCH_KEY + '?').getBytes());
return null;
});
}
private void renewalTag() {
int pageNum = 0;
while (true) {
PageRequest pageRequest = PageRequest.of(pageNum, BULK_SIZE);
Slice<Tag> slicedTags = tagAdaptor.querySliceTag(pageRequest);
Set<Tag> tags = new HashSet<>(slicedTags.getContent());
redisTemplate.executePipelined(
(RedisCallback<Object>)
redisConnection -> {
tags.forEach(
tag -> {
String key;
if (StringUtil.isKorean(
tag.getName().trim().charAt(0))) {
key = SEARCH_KEY + StringUtil.extractKoreanInitial(
tag.getName()
.trim()
.charAt(0));
} else {
key = SEARCH_KEY + tag.getName()
.trim()
.toUpperCase()
.charAt(0);
}
redisConnection.zSetCommands()
.zAdd(key.getBytes(),
0,
(tag.getName().trim() + ASTERISK).getBytes());
for (int index = 0; index <= tag.getName().length(); index++) {
redisConnection.zSetCommands()
.zAdd(key.getBytes(),
0,
tag.getName()
.trim()
.substring(0, index)
.getBytes());
}
});
return null;
});
if (!slicedTags.hasNext()) {
break;
}
pageNum++;
}
}
private void renewalArchiving() {
int pageNum = 0;
while (true) {
PageRequest pageRequest = PageRequest.of(pageNum, BULK_SIZE);
Slice<Archiving> slicedArchivings =
archivingAdaptor.querySliceArchivingByPublicStatus(pageRequest, true);
Set<Archiving> archivings = new HashSet<>(slicedArchivings.getContent());
redisTemplate.executePipelined(
(RedisCallback<Object>)
redisConnection -> {
archivings.forEach(
archiving -> {
String key;
if (StringUtil.isKorean(
archiving.getTitle().trim().charAt(0))) {
key = SEARCH_KEY + StringUtil.extractKoreanInitial(
archiving.getTitle()
.trim()
.charAt(0));
} else {
key = SEARCH_KEY + archiving.getTitle()
.trim()
.toUpperCase()
.charAt(0);
}
redisConnection.zSetCommands()
.zAdd(key.getBytes(),
0,
(archiving.getTitle().trim() + ASTERISK).getBytes());
for (int index = 0; index <= archiving.getTitle().length(); index++) {
redisConnection.zSetCommands()
.zAdd(key.getBytes(),
0,
archiving.getTitle()
.trim()
.substring(0, index)
.getBytes());
}
});
return null;
});
if (!slicedArchivings.hasNext()) {
break;
}
pageNum++;
}
}
}
1λ²μ μμμ μ€λͺ ν λ΄μ©μ ꡬννλ€.
key + 첫 κΈμλ₯Ό ν€λ‘ νμ¬ μ μ₯νλ€.
νκΈμ κ²½μ° 'κ°'λΌλ λ¨μ΄λ₯Ό μ¬μ©νλ κ²μ΄ μλλΌ 'γ±'λ₯Ό ν€μ μ¬μ©νλλ‘ νλ€.
μ΄λ κ² κ΅¬μ±νλλΌλ ν ν€μ μ§μ€λ κ°λ₯μ±μ΄ μ‘΄μ¬νλ€.
νμ§λ§ λͺ¨λ κΈμλ₯Ό ν ν€μ λ£λ κ²λ³΄λ¨ λ μ§μ€λ κ²μ΄λ€.
λν μ΄λ₯Ό ν΅ν΄ 4λ²μ κ°μ ν μ μμλ€.
λ¨μ΄μ μ κΈμλ₯Ό κΈ°μ€μΌλ‘ μ μ₯, μ‘°ννλ―λ‘, μμ μ€λͺ ν μν©μ λ°μνμ§ μλλ€.
νμ§λ§ λ¬Έμ λ₯Ό μλ²½ν ν΄κ²°λ κ²μ μλλ€.
b... λ₯Ό κ²μνμ λ c... κ° μ λμ¬ λΏ, ba... λ₯Ό κ²μνμ λ, bz... κ° μ¬μ ν κ²μλ μ μλ€.
3λ²μ κ²½μ° redis pipelineμ μ΄μ©νλ€.
pipelineμ λ§μ μμ²μ ν λ²μ λ³΄λΌ μ μλ λ°©λ²μ΄λ€.
νμ¬ κ°μ ν λ°©μμ λ°μ΄ν°λ₯Ό λΆλ¬μ¬ λ 100κ°μ© λΆλ¬μμ μμ² 100κ°λ₯Ό λ§λ€μ΄ 보λ΄λ λ°©μμ΄λ€.
μ΄λ pipelineμ μ΄μ©ν¨μΌλ‘μ¨ 100κ°μ μμ²μ 1λ²μΌλ‘ μ²λ¦¬ν μ μκ² λμλ€.
μλ₯Ό ν΅ν΄ 2λ²μ κ°μ ν μ μμλ€.
μλλ κ°μ μ κ³Ό νμ λ°μ΄ν° 리λ΄μΌ μ²λ¦¬ μκ°μ΄λ€.
λ‘컬 νκ²½μμ λμ»€λ‘ DBλ₯Ό λμμ, archivingκ³Ό tag λ°μ΄ν° rowμ μ΄ν©μ λ°λΌ λ‘μ§ μ²λ¦¬ μκ°μ λΉκ΅ν΄ λ΄€λ€.
rows | 200 | 4000 | 9000 |
μ΄μ μ½λ | 318ms | 5479ms | 11684ms |
κ°μ μ | 287ms | 1912ms | 3784ms |
row μκ° λ§μμ§μλ‘ μμ μλ μ°¨μ΄κ° 컀μ‘λ€.
λ§μ λ°μ΄ν°μ λΉ λ₯΄κ² λμν μ μλλ‘ κ°μ νλ€.
νμ§λ§ μ¬μ ν μλΉμ€κ° μ€λ¨λλ κ²μ λ§μ μ μμλ€.
μ€μ μ΄μ μ€μΈ μλΉμ€μ κ°μ λ°μ΄ν° 리λ΄μΌ μ μκ°μ μΈ‘μ ν΄ λ΄€λ€.
λ€μκ³Ό κ°μ κ°μ μ 보μλ€.
λμμ± μ²λ¦¬ μμ΄ 1κ°μ μ€λ λκ° 100κ°μ μμ²μ 보λ΄λλ‘ νλ€.
882msμμ 105msλ‘ μ€μλ€.
λ‘컬 λλΉμλ λ¬λ¦¬, DB I/O μκ°μ΄ λ 걸리λ μλ²μ νΉμ±μ΄ λ°μλ κ² κ°λ€.
I/O νμλ₯Ό μ€μμΌλ‘μ¨ μκ°μ λν μ€μΌ μ μμλ€.
'Backend' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
<Spring> Spring Bean, IoC/DI μ 리 2 (0) | 2023.10.03 |
---|---|
<Spring> Spring Bean, IoC/DI μ 리 1 (0) | 2023.10.03 |
<Spring> AOP κΈ°λ° λΆμ°λ½ (0) | 2023.10.01 |
<Spring> ResponseEntityExceptionHandler μ΄μ©ν κ³΅ν΅ μλ¬ μ²λ¦¬ (0) | 2023.05.07 |
<Spring> HttpServletRequest κ° μ¬λΌμ§λ λ¬Έμ (1) | 2023.05.06 |