1. ๋ฌธ์ ๋ฐ๊ฒฌ
k6๋ก ๋ถํํ ์คํธ ํ๋ ์ค์ธ๋ฐ slow query 1,131ms

TPS๊ฐ 8.97์ด๋ผ๋ ์์ฒญ๋ ์ซ์๊ฐ ๋์ด..ใ ใ
2. ์์ธ ๋ถ์
Total Page์๋ฅผ ๊ณ์ฐํ๊ธฐ ์ํด์
๋งค๋ฒ select count(*) from article ์ฟผ๋ฆฌ๊ฐ ์ถ๊ฐ ์คํ๋๋ ๋ฌธ์ ๋ฅผ ๋ฐ๊ฒฌํจ
๋๋ฏธ ๋ฐ์ดํฐ๋ก DB์ article 10๋ง๊ฐ ๋ฃ์ด๋์ ์ํฉ์ด๋ผ ์๊ฐ์ ์ค๋ ์ก์๋จน๋๊ฒ์ผ๋ก ์ถ์ ๋จ.
api controller์์ Page<Article>๋ก ๋ฐํํ๋ฉด์
JPA๊ฐ ์๋์ผ๋ก ์ฟผ๋ฆฌ๋ฅผ 2๊ฐ ๋ ๋ฆฌ๊ฒ๋จ
-- ์ฟผ๋ฆฌ 1: ํด๋น ํ์ด์ง ๋ฐ์ดํฐ 10๊ฑด
SELECT * FROM article ORDER BY created_at DESC LIMIT 10 OFFSET 0;
-- ์ฟผ๋ฆฌ 2: ์ ์ฒด ํ์ด์ง ์ ๊ณ์ฐ์ฉ (JPA๊ฐ ์๋์ผ๋ก ์ถ๊ฐ)
SELECT COUNT(*) FROM article; -- 10๋ง๊ฑด ์ ๋ถ ์
์ ์ฒด ๋ช ํ์ด์ง์ธ์ง ๊ณ์ฐํ๋ ๊ณผ์ ์์ 10๋ง๊ฑด์ ์ธ๊ณ ์๋๊ฒ
3. ํด๊ฒฐ ๋ฐฉ๋ฒ ์ ํ
total page๋ฅผ ๊ณ์ฐํ๊ธฐ ์ํด ์ ์ฒด article ๊ฐฏ์๋ฅผ ๊ณ์ฐํ๋๊ฑด ์ต์ด ํ ๋ฒ๋ง ํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์บ์์ ์ ์ฅํด๋๋ฉด
์ฌ์ฌ์ฉํจ์ผ๋ก์จ ์ฑ๋ฅ๊ฐ์ ๊ฐ๋ฅ์ฑ์ด ์๋ค๊ณ ํ๋จํ์ฌ
์บ์๋ฅผ ์ ์ฉํ๋ ค๊ณ ํ๋๋ฐ,
์บ์์๋ ํฌ๊ฒ 2๊ฐ์ง๊ฐ ์์.
๋ก์ปฌ ์บ์ / ๋ถ์ฐ์บ์
๋ก์ปฌ์บ์

์ ์ฅ ์์น๋ JVM ํ ๋ด๋ถ.
๋ฐ๋ผ์ ๋คํธ์ํฌ ๊ฑฐ์น์ง ์๊ณ application๋ด๋ถ์์ ๋ฐ๋ก ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋๋ฌธ์ ์กฐํ์๋๊ฐ ๋งค์ฐ ๋น ๋ฆ
๋ณ๋์ ์๋ฒ๋ฅผ ๊ตฌ์ถํ ํ์๊ฐ ์์ผ๋๊น ๋น์ฉ์ ๊ฐ ํจ๊ณ ๋ ์๊ณ ...
๊ตฌํ๋ ๋น๊ต์ ๊ฐ๋จํ๋ค๊ณ ํจ.
๋จ ์๋ฒ๊ฐ ์ฌ๋ฌ๋ ์ผ๋๋ ๋ฐ์ดํฐ ๋ถ์ผ์น ๋๋ฌธ์ MSA ํ๊ฒฝ์์๋ ์ฌ์ฉ์ด ์ด๋ ค์.
ex)Caffeine
๋ถ์ฐ ์บ์

์ฌ๋ฌ ์๋ฒ๊ฐ ๊ณต์ ํ๋ ์ธ๋ถ ์บ์ ์ ์ฅ์์ ์์น.
๋คํธ์ํฌ๋ฅผ ํตํด ๋ฐ์ดํฐ๊ฐ ์ด๋ํ๊ธฐ ๋๋ฌธ์ ๋ก์ปฌ ์บ์๋ณด๋ค๋ ๋๋ฆผ
ํ์ง๋ง ์๋ฒ๊ฐ ๋ฐ์ดํฐ ์ผ๊ด์ฑ ์ ์งํ ์ ์๊ณ
ํ์ฅ์ฑ์ด๋ ๊ฐ์ฉ์ฑ์ด ์ข๋ค๋ ์ฅ์ ์ด ์์.
ex ) Redis
-> ๋๋ ๋จ์ผ์๋ฒ๋ก ์งํํ๊ณ ์๊ธฐ๋๋ฌธ์ Caffeine ์ ํ!
์ถํ ํ์ฅํ๊ฒ ๋๋ค๋ฉด Redis๋ ์ถ๊ฐ๋์ ํ ์ง๋,,
4. ์ ์ฉ ๊ณผ์
๋จผ์ ์์กด์ฑ ๋ฃ์ด์ฃผ๊ณ
implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation 'com.github.ben-manes.caffeine:caffeine'
Config ํ์ผ ์์ฑ
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("articleCount");
cacheManager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES));
return cacheManager;
}
}
Service์ฝ๋ ์์
// ๊ธ ์๋ก ์์ฑ ์ ์บ์ ๋ฌดํจํ
@CacheEvict( value = "articleCount", allEntries = true)
public Article save(AddArticleRequest request, String username) {
User user = userRepository.findByEmail(username)
.orElseThrow(() -> new IllegalArgumentException("Unexpected User"));
return blogRepository.save(request.toEntity(username, user.getId()));
}
// ๊ธ ์ญ์ ์ ์บ์ ๋ฌดํจํ
@CacheEvict( value = "articleCount", allEntries = true)
public void delete(Long id) {
Article article = blogRepository.findById(id)
.orElseThrow( () -> new IllegalArgumentException("not found : " + id));
authorizeArticleAuthor(article);
blogRepository.deleteById(id);
}
@Cacheable("articleCount")
public long getArticleCount() {
return blogRepository.count();
}
controller์์
long totalCount = blogService.getArticleCount();
int totalPages = (int) Math.ceil((double) totalCount / 10);
5. ๊ฒฐ๊ณผ
๋ก์ปฌ์์ ์คํํ๊ณ postman์ผ๋ก ํ ์คํธ
์ฒซ๋ฒ์งธ ์์ฒญ


๋๋ฒ์งธ ์์ฒญ

์๋ต์๋๊ฐ
971ms -> 126ms ๋ก ํ์ฐํ๊ฒ ์ค์ด๋ค์์.
๋ก๊ทธ์๋

์ฒ์์ no cache๋ผ๊ณ ๋จ๋ค๊ฐ ๋๋ฒ์งธ get ์์ฒญ์๋ ์๋ธ ใ ใ
์บ์ ๋ฌดํจํ ํ ์คํธ

์ด๋ฐ์์ผ๋ก ๊ฒ์๋ฌผ ํ๋ ์จ์ฃผ๊ณ
๋ค์ get์์ฒญ ๋ ๋ฆฌ๋๊น

์ด๋ ๊ฒ no cache๋ผ๊ณ ๋จ๋ค์~
์๊ฐ์ ์ฌ์ ํ ์งง๊ฒ ๋์ค๋๊ฒ ์๋ง ๋ก์ปฌ DB๋ผ ๊ทธ๋ฐ๋ฏ..
์ํผ ๋
'Spring Boot' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [Cache] ๋ก์ปฌ ์บ์ vs ๋ถ์ฐ ์บ์ (0) | 2026.05.16 |
|---|---|
| [error] Unable to determine Dialect without JDBC metadata ํด๊ฒฐ (0) | 2025.11.28 |
| [JUnit] does not declare any static, non-private, non-final, nested classes annotated with @Configuration ์๋ฌ ํด๊ฒฐ (0) | 2025.05.28 |
| [OAuth] OAuth2 ์ค์ ํ์ผ ์์ฑ (0) | 2025.05.11 |
| [OAuth2] OAuth2 ์ฌ์ฉ์ ์๋น์ค ๊ตฌํํ๊ธฐ (0) | 2025.05.11 |