๐ Spring @Async์ CompletableFuture๋ฅผ ์ด์ฉํ ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ์ธ๊ณ๋ก! ๐

์๋ ํ์ธ์, ์ฝ๋ฉ ํํ๊ฐ ์ฌ๋ฌ๋ถ! ์ค๋์ ์ ๋ง ํฅ๋ฏธ์ง์งํ ์ฃผ์ ๋ก ์ฌ๋ฌ๋ถ์ ์ฐพ์์์ต๋๋ค. ๋ฐ๋ก Spring์ @Async ์ด๋ ธํ ์ด์ ๊ณผ CompletableFuture๋ฅผ ์ด์ฉํ ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ๋ํด ์์๋ณผ ๊ฑฐ์์. ์ด ์ฃผ์ ๋ ๋ง์น ์ฌ๋ฅ๋ท์์ ๋ค์ํ ์ฌ๋ฅ์ด ๋์์ ๊ฑฐ๋๋๋ ๊ฒ์ฒ๋ผ, ์ฌ๋ฌ ์์ ์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃน๋๋ค. ์, ๊ทธ๋ผ ์ฐ๋ฆฌ์ ์ฝ๋ฉ ๋ชจํ์ ์์ํด๋ณผ๊น์? ๐โโ๏ธ
๐ ํ์ต ๋ชฉํ:
- Spring์ @Async ์ด๋ ธํ ์ด์ ์ดํดํ๊ธฐ
- CompletableFuture์ ๊ฐ๋ ๊ณผ ์ฌ์ฉ๋ฒ ์ตํ๊ธฐ
- ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ์ฅ์ ๊ณผ ์ฃผ์์ ํ์ ํ๊ธฐ
- ์ค์ ํ๋ก์ ํธ์ ๋น๋๊ธฐ ์ฒ๋ฆฌ ์ ์ฉํ๊ธฐ
๐ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ ๋ฌด์์ผ๊น์?
๋น๋๊ธฐ ์ฒ๋ฆฌ๋ผ๋ ๋ง, ๋ค์ด๋ณด์ จ๋์? ๐ค ๊ฐ๋จํ ๋งํด, ์์ ์ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ๋ค๋ฅธ ์ผ์ ํ ์ ์๊ฒ ํด์ฃผ๋ ๋ง๋ฒ์ด๋ผ๊ณ ํ ์ ์์ด์. ์ฌ๋ฅ๋ท์์ ์ฌ๋ฌ๋ถ์ด ๋์์ ์ฌ๋ฌ ์ฌ๋ฅ์ ํ์ํ๊ณ ๊ฑฐ๋ํ ์ ์๋ ๊ฒ์ฒ๋ผ, ํ๋ก๊ทธ๋จ๋ ์ฌ๋ฌ ์์ ์ ๋์์ ์ฒ๋ฆฌํ ์ ์๋ต๋๋ค!
๐ ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ์ฅ์ :
- ์๊ฐ ์ ์ฝ: ์ฌ๋ฌ ์์ ์ ๋์์ ์ฒ๋ฆฌํ ์ ์์ด์.
- ํจ์จ์ฑ ์ฆ๊ฐ: ์์์ ๋ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ด์.
- ๋ฐ์์ฑ ํฅ์: ์ฌ์ฉ์ ๊ฒฝํ์ด ๋ ์ข์์ง๋๋ค.
์, ์ด์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ๋ญ์ง ๋๋ต ๊ฐ์ด ์ค์๋์? ๊ทธ๋ผ ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก Spring์ @Async์ CompletableFuture์ ๋ํด ์์๋ณผ๊น์? ๐
๐ Spring์ @Async ์ด๋ ธํ ์ด์ ์ดํด๋ณด๊ธฐ
Spring Framework๋ ์ ๋ง ๋ง์ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋๋ฐ์, ๊ทธ ์ค์์๋ @Async ์ด๋ ธํ ์ด์ ์ ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ํต์ฌ์ด๋ผ๊ณ ํ ์ ์์ด์. ์ด ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ฉด, ๋ฉ์๋๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ์คํํ ์ ์๊ฒ ๋ฉ๋๋ค. ๋ง์น ์ฌ๋ฅ๋ท์์ ์ฌ๋ฌ ์ฌ๋ฅ์ ๋์์ ํ์ํ๋ ๊ฒ์ฒ๋ผ ๋ง์ด์ฃ ! ๐
๐ @Async ์ฌ์ฉ๋ฒ:
@Service
public class MyService {
@Async
public void asyncMethod() {
// ๋น๋๊ธฐ๋ก ์คํ๋ ์ฝ๋
}
}
์ด๋ ๊ฒ ๊ฐ๋จํ @Async ์ด๋ ธํ ์ด์ ์ ๋ฉ์๋ ์์ ๋ถ์ด๋ฉด, ํด๋น ๋ฉ์๋๋ ๋ณ๋์ ์ค๋ ๋์์ ๋น๋๊ธฐ์ ์ผ๋ก ์คํ๋ฉ๋๋ค. ๋๋์ง ์๋์? ๐
ํ์ง๋ง ์ฌ๊ธฐ์ ๋์ด ์๋๋๋ค! @Async๋ฅผ ์ฌ์ฉํ ๋๋ ๋ช ๊ฐ์ง ์ฃผ์ํ ์ ์ด ์์ด์:
- ๋ฐํ ํ์ ์ ์ฃผ์ํ์ธ์: void๋ Future ํ์ ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
- self-invocation์ ์ฃผ์ํ์ธ์: ๊ฐ์ ํด๋์ค ๋ด์์ @Async ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ๋์ํ์ง ์์ต๋๋ค.
- ์์ธ ์ฒ๋ฆฌ์ ์ ๊ฒฝ ์ฐ์ธ์: ๋น๋๊ธฐ ๋ฉ์๋์์ ๋ฐ์ํ ์์ธ๋ ๋ณ๋๋ก ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.
์ด์ @Async์ ๋ํด ์ด๋ ์ ๋ ์ดํด๊ฐ ๋์ จ๋์? ๊ทธ๋ ๋ค๋ฉด ์ด์ CompletableFuture๋ก ๋์ด๊ฐ๋ณผ๊น์? ๐
๐ฎ CompletableFuture์ ๋ง๋ฒ
CompletableFuture๋ Java 8์์ ๋์ ๋ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ๊ฐ๋ ฅํ ๋๊ตฌ์ ๋๋ค. ์ด๋ฆ์์ ์ ์ ์๋ฏ์ด, ๋ฏธ๋์ ์๋ฃ๋ ์์ ์ ๋ํ๋ด๋ ๊ฐ์ฒด์์. ์ฌ๋ฅ๋ท์์ ์ฌ๋ฌ๋ถ์ด ์ํ๋ ์ฌ๋ฅ์ ์ฐพ๋ ๊ณผ์ ์ ์์ํด๋ณด์ธ์. ์ฌ๋ฌ๋ถ์ ๊ฒ์์ ์์ํ๊ณ , ๊ฒฐ๊ณผ๊ฐ ๋์ฌ ๋๊น์ง ๋ค๋ฅธ ์ผ์ ํ ์ ์์ฃ . CompletableFuture๋ ์ด์ ๋น์ทํฉ๋๋ค! ๐ต๏ธโโ๏ธ
๐ญ CompletableFuture์ ์ฃผ์ ํน์ง:
- ๋น๋๊ธฐ ์์ ์ ๊ฒฐ๊ณผ๋ฅผ ํํ
- ์์ ์ ์๋ฃ๋ฅผ ์๋์ผ๋ก ์ค์ ๊ฐ๋ฅ
- ์ฌ๋ฌ ๋น๋๊ธฐ ์์ ์ ์กฐํฉํ๊ณ ์ฐ๊ฒฐ ๊ฐ๋ฅ
- ์์ธ ์ฒ๋ฆฌ๋ฅผ ์ํ ๋ค์ํ ๋ฉ์๋ ์ ๊ณต
์, ์ด์ CompletableFuture๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ์ดํด๋ณผ๊น์? ๐ง
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// ๋น๋๊ธฐ๋ก ์คํ๋ ์ฝ๋
return "Hello, Async World!";
});
future.thenAccept(result -> System.out.println(result));
์ด ์ฝ๋์์ supplyAsync()๋ ๋น๋๊ธฐ์ ์ผ๋ก ์์ ์ ์คํํ๊ณ , thenAccept()๋ ์์ ์ด ์๋ฃ๋์์ ๋ ๊ฒฐ๊ณผ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. ๋ง์น ์ฌ๋ฅ๋ท์์ ์ฌ๋ฅ์ ๊ฒ์ํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์๋ณด๋ ๊ฒ๊ณผ ๋น์ทํ์ฃ ? ๐
CompletableFuture๋ ์ ๋ง ๋ค์ํ ๋ฉ์๋๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ช ๊ฐ์ง ๋ ์ดํด๋ณผ๊น์?
- thenApply(): ๊ฒฐ๊ณผ๋ฅผ ๋ณํ
- thenCompose(): ๋ ๊ฐ์ ๋น๋๊ธฐ ์์ ์ ์์ฐจ์ ์ผ๋ก ์คํ
- thenCombine(): ๋ ๊ฐ์ ๋น๋๊ธฐ ์์ ์ ๋ณ๋ ฌ๋ก ์คํํ๊ณ ๊ฒฐ๊ณผ ๊ฒฐํฉ
- exceptionally(): ์์ธ ์ฒ๋ฆฌ
์ด๋ ๊ฒ ๋ค์ํ ๋ฉ์๋๋ฅผ ํ์ฉํ๋ฉด, ๋ณต์กํ ๋น๋๊ธฐ ๋ก์ง๋ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ต๋๋ค. ๋ง์น ์ฌ๋ฅ๋ท์์ ์ฌ๋ฌ ์ฌ๋ฅ์ ์กฐํฉํด ์๋ก์ด ๊ฐ์น๋ฅผ ๋ง๋ค์ด๋ด๋ ๊ฒ์ฒ๋ผ ๋ง์ด์ฃ ! ๐
๐คน @Async์ CompletableFuture์ ํ์์ ์ธ ์ฝ๋ผ๋ณด
์, ์ด์ @Async์ CompletableFuture๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์์๋ณผ๊น์? ์ด ๋์ ์กฐํฉํ๋ฉด ์ ๋ง ๊ฐ๋ ฅํ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ๊ตฌํํ ์ ์์ด์. ๋ง์น ์ฌ๋ฅ๋ท์์ ์ฌ๋ฌ ์ฌ๋ฅ์ ์กฐํฉํด ๋ ํฐ ๊ฐ์น๋ฅผ ๋ง๋ค์ด๋ด๋ ๊ฒ์ฒ๋ผ ๋ง์ด์ฃ ! ๐ญ
๐ @Async์ CompletableFuture ์ฌ์ฉ ์์:
@Service
public class AsyncService {
@Async
public CompletableFuture<String> asyncMethod() {
// ๋น๋๊ธฐ ์์
์ํ
return CompletableFuture.completedFuture("Async task completed!");
}
}
// ์ฌ์ฉ ์
CompletableFuture<String> future = asyncService.asyncMethod();
future.thenAccept(result -> System.out.println(result));
์ด ์์์์ @Async ์ด๋ ธํ ์ด์ ์ ๋ฉ์๋๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ์คํํ๊ฒ ๋ง๋ค๊ณ , CompletableFuture๋ ๊ทธ ๋น๋๊ธฐ ์์ ์ ๊ฒฐ๊ณผ๋ฅผ ํํํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ฉ์๋ ํธ์ถ์๋ ์ฆ์ CompletableFuture๋ฅผ ๋ฐ์ ๋ค๋ฅธ ์์ ์ ๊ณ์ํ ์ ์์ฃ . ๐จโ๐ป
์ด ๋ฐฉ์์ ์ฅ์ ์ ๋ฌด์์ผ๊น์?
- ์ ์ฐ์ฑ: CompletableFuture์ ๋ค์ํ ๋ฉ์๋๋ฅผ ํ์ฉํ ์ ์์ด์.
- ํ์ฅ์ฑ: ์ฌ๋ฌ ๋น๋๊ธฐ ์์ ์ ์ฝ๊ฒ ์กฐํฉํ ์ ์์ด์.
- ๊ฐ๋ ์ฑ: ๋น๋๊ธฐ ๋ก์ง์ ๋ช ํํ๊ฒ ํํํ ์ ์์ด์.
- ์์ธ ์ฒ๋ฆฌ: CompletableFuture์ ์์ธ ์ฒ๋ฆฌ ๋ฉ์ปค๋์ฆ์ ํ์ฉํ ์ ์์ด์.
์ด์ ์ฌ๋ฌ๋ถ๋ @Async์ CompletableFuture๋ฅผ ์์ ์์ฌ๋ก ๋ค๋ฃฐ ์ ์๊ฒ ์ฃ ? ๋ง์น ์ฌ๋ฅ๋ท์์ ๋ค์ํ ์ฌ๋ฅ์ ์์ ๋กญ๊ฒ ํ์ํ๊ณ ํ์ฉํ๋ ๊ฒ์ฒ๋ผ ๋ง์ด์์! ๐
๐๏ธ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ๊ธฐ
์, ์ด์ ์ฐ๋ฆฌ๊ฐ ๋ฐฐ์ด ๋ด์ฉ์ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํด๋ณผ ์๊ฐ์ด์์! ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ํ๋ซํผ์ ๊ฐ๋ฐํ๋ค๊ณ ์์ํด๋ด ์๋ค. ์ด๋ค ๋ถ๋ถ์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ ์ฉํ ์ ์์๊น์? ๐ค
๐ ๋น๋๊ธฐ ์ฒ๋ฆฌ ์ ์ฉ ์์:
- ์ฌ์ฉ์ ํ๋กํ ์ ๋ฐ์ดํธ
- ๋๋ ์ด๋ฉ์ผ ๋ฐ์ก
- ๋ณต์กํ ๊ฒ์ ์ฟผ๋ฆฌ ์คํ
- ์ธ๋ถ API ํธ์ถ
- ๋์ฉ๋ ํ์ผ ์ ๋ก๋/๋ค์ด๋ก๋
์ด ์ค์์ "๋ณต์กํ ๊ฒ์ ์ฟผ๋ฆฌ ์คํ"์ ์๋ก ๋ค์ด ์ฝ๋๋ฅผ ์์ฑํด๋ณผ๊น์? ๐งโ๐ป
@Service
public class SearchService {
@Async
public CompletableFuture<List<TalentDto>> searchTalents(String keyword) {
return CompletableFuture.supplyAsync(() -> {
// ๋ณต์กํ ๊ฒ์ ๋ก์ง ์ํ
List<TalentDto> results = performComplexSearch(keyword);
return results;
});
}
private List<TalentDto> performComplexSearch(String keyword) {
// ์ค์ ๊ฒ์ ๋ก์ง ๊ตฌํ
// ...
}
}
@RestController
public class SearchController {
@Autowired
private SearchService searchService;
@GetMapping("/search")
public CompletableFuture<ResponseEntity<List<TalentDto>>> search(@RequestParam String keyword) {
return searchService.searchTalents(keyword)
.thenApply(results -> ResponseEntity.ok(results))
.exceptionally(ex -> ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build());
}
}
์ด ์์์์ searchTalents ๋ฉ์๋๋ @Async ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํด ๋น๋๊ธฐ์ ์ผ๋ก ์คํ๋ฉ๋๋ค. ๋ณต์กํ ๊ฒ์ ๋ก์ง์ ๋ณ๋์ ์ค๋ ๋์์ ์ํ๋๊ณ , ๊ฒฐ๊ณผ๋ CompletableFuture๋ก ๋ฐํ๋ฉ๋๋ค. ๐
์ปจํธ๋กค๋ฌ์์๋ ์ด CompletableFuture๋ฅผ ๊ทธ๋๋ก ๋ฐํํ๊ณ ์๋๋ฐ, ์ด๋ Spring MVC๊ฐ ๋น๋๊ธฐ ์์ฒญ์ ์ง์ํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฆ์ ๋ฐํ๋๊ณ , ๊ฒฐ๊ณผ๊ฐ ์ค๋น๋๋ฉด ์๋ต์ด ์ ์ก๋ฉ๋๋ค. ๐จโ๐ซ
์ด๋ ๊ฒ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ ์ฉํ๋ฉด ์ด๋ค ์ฅ์ ์ด ์์๊น์?
- ์๋ต์ฑ ํฅ์: ์ฌ์ฉ์๋ ๊ธด ๋๊ธฐ ์๊ฐ ์์ด ๋น ๋ฅธ ์๋ต์ ๋ฐ์ ์ ์์ด์.
- ์๋ฒ ๋ฆฌ์์ค ํจ์จ์ ์ฌ์ฉ: ์ฌ๋ฌ ์์ฒญ์ ๋์์ ์ฒ๋ฆฌํ ์ ์์ด์.
- ํ์ฅ์ฑ: ์์คํ ์ ๋ถํ๋ฅผ ๋ ์ ๊ด๋ฆฌํ ์ ์์ด์.
์ด์ ์ฌ๋ฌ๋ถ๋ ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ํ๋ซํผ์ ๊ฐ๋ฐํ ๋ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ ์ฉํ ์ ์๊ฒ ์ฃ ? ์ฌ์ฉ์๋ค์๊ฒ ๋ ๋์ ๊ฒฝํ์ ์ ๊ณตํ ์ ์์ ๊ฑฐ์์! ๐
โ ๏ธ ์ฃผ์์ฌํญ ๋ฐ ๋ฒ ์คํธ ํ๋ํฐ์ค
๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ๊ฐ๋ ฅํ์ง๋ง, ๋์์ ๋ณต์ก์ฑ์ ์ฆ๊ฐ์ํฌ ์ ์์ด์. ์ฌ๋ฅ๋ท์์ ๋ค์ํ ์ฌ๋ฅ์ ๊ด๋ฆฌํ๋ ๊ฒ์ฒ๋ผ, ๋น๋๊ธฐ ์ฝ๋๋ ์ ์คํ๊ฒ ๊ด๋ฆฌํด์ผ ํฉ๋๋ค. ๋ช ๊ฐ์ง ์ฃผ์์ฌํญ๊ณผ ๋ฒ ์คํธ ํ๋ํฐ์ค๋ฅผ ์์๋ณผ๊น์? ๐ง
๐จ ์ฃผ์์ฌํญ:
- ๋ฐ๋๋ฝ ์ฃผ์: ๋น๋๊ธฐ ์์ ๊ฐ ์ํ ์์กด์ฑ์ ๋ง๋ค์ง ์๋๋ก ์ฃผ์ํ์ธ์.
- ๋ฆฌ์์ค ๊ด๋ฆฌ: ๋๋ฌด ๋ง์ ๋น๋๊ธฐ ์์ ์ ๋์์ ์คํํ์ง ์๋๋ก ์ฃผ์ํ์ธ์.
- ์์ธ ์ฒ๋ฆฌ: ๋น๋๊ธฐ ์์ ์ ์์ธ๋ฅผ ์ ์ ํ ์ฒ๋ฆฌํ์ง ์์ผ๋ฉด ์์คํ ์ด ๋ถ์์ ํด์ง ์ ์์ด์.
- ํ ์คํธ์ ์ด๋ ค์: ๋น๋๊ธฐ ์ฝ๋๋ ํ ์คํธํ๊ธฐ ์ด๋ ค์ธ ์ ์์ผ๋ฏ๋ก ํ ์คํธ ์ ๋ต์ ์ ์ธ์์ผ ํด์.
์ด๋ฌํ ์ฃผ์์ฌํญ์ ์ผ๋์ ๋๊ณ , ๋ค์๊ณผ ๊ฐ์ ๋ฒ ์คํธ ํ๋ํฐ์ค๋ฅผ ๋ฐ๋ฅด๋ ๊ฒ์ด ์ข์ต๋๋ค:
- ์ ์ ํ ์ค๋ ๋ ํ ์ฌ์ฉ: @Async ์์ ์ ์ํ ์ ์ฉ ์ค๋ ๋ ํ์ ๊ตฌ์ฑํ์ธ์.
- ํ์์์ ์ค์ : ๋ชจ๋ ๋น๋๊ธฐ ์์ ์ ์ ์ ํ ํ์์์์ ์ค์ ํ์ธ์.
- ์๋ฌ ํธ๋ค๋ง: CompletableFuture์ exceptionally() ๋๋ handle() ๋ฉ์๋๋ฅผ ํ์ฉํ์ธ์.
- ๋น๋๊ธฐ ์์ ๋ชจ๋ํฐ๋ง: ๋ก๊น ๊ณผ ๋ชจ๋ํฐ๋ง ๋๊ตฌ๋ฅผ ํ์ฉํด ๋น๋๊ธฐ ์์ ์ ์ถ์ ํ์ธ์.
- ๋จ์ ํ ์คํธ ์์ฑ: MockExecutor๋ฅผ ์ฌ์ฉํด ๋น๋๊ธฐ ์ฝ๋๋ฅผ ํ ์คํธํ์ธ์.
์ด๋ฌํ ๋ฒ ์คํธ ํ๋ํฐ์ค๋ฅผ ๋ฐ๋ฅด๋ฉด, ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ๋ณต์กํ ์์คํ ์์๋ ์์ ์ ์ด๊ณ ํจ์จ์ ์ธ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ๊ตฌํํ ์ ์์ ๊ฑฐ์์! ๐ช
๐ ์ฌํ ํ์ต: ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ๋ ๊น์ ์ดํด
์, ์ด์ ์ฐ๋ฆฌ๋ @Async์ CompletableFuture์ ๊ธฐ๋ณธ์ ๋ง์คํฐํ์ด์. ํ์ง๋ง ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์ธ๊ณ๋ ๋ ๊น๊ณ ๋๋ต๋๋ค. ๋ง์น ์ฌ๋ฅ๋ท์์ ๊ณ์ํด์ ์๋ก์ด ์ฌ๋ฅ์ ๋ฐ๊ฒฌํ๋ ๊ฒ์ฒ๋ผ ๋ง์ด์ฃ ! ์ข ๋ ์ฌํ๋ ๋ด์ฉ์ ์ดํด๋ณผ๊น์? ๐ต๏ธโโ๏ธ
๐ ์ฌํ ์ฃผ์ :
- Reactive Programming๊ณผ์ ์ฐ๊ณ
- ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ ํจํด
- ์ฑ๋ฅ ์ต์ ํ ๊ธฐ๋ฒ
- ๋ถ์ฐ ์์คํ ์์์ ๋น๋๊ธฐ ์ฒ๋ฆฌ
1. Reactive Programming๊ณผ์ ์ฐ๊ณ
Spring WebFlux์ Project Reactor๋ฅผ ์ฌ์ฉํ๋ฉด ๋์ฑ ๊ฐ๋ ฅํ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ๊ตฌํํ ์ ์์ด์. CompletableFuture๋ฅผ Mono๋ Flux๋ก ๋ณํํ๋ ๋ฐฉ๋ฒ์ ์์๋ณผ๊น์?
Mono<String> mono = Mono.fromFuture(completableFuture);
Flux<String> flux = Flux.from(mono);
์ด๋ ๊ฒ ํ๋ฉด CompletableFuture์ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌ์กํฐ๋ธ ์คํธ๋ฆผ์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ด์. ์ฌ๋ฅ๋ท์ ์ค์๊ฐ ๊ฒ์ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ค๊ณ ์๊ฐํด๋ณด์ธ์. ์ฌ์ฉ์์ ์ ๋ ฅ์ ๋ฐ๋ผ ์ค์๊ฐ์ผ๋ก ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณตํ ์ ์์ ๊ฑฐ์์! ๐
2. ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ ํจํด
๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์๋ ์ฌ๋ฌ ๊ฐ์ง ํจํด์ด ์์ด์. ๋ํ์ ์ธ ๋ช ๊ฐ์ง๋ฅผ ์ดํด๋ณผ๊น์?
- Promise ํจํด: CompletableFuture๊ฐ ์ด ํจํด์ ๊ตฌํํ๊ณ ์์ด์.
- Observer ํจํด: ์ด๋ฒคํธ ๊ธฐ๋ฐ ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ์ ์ฉํด์.
- Actor ๋ชจ๋ธ: ๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ด์์.
์ด๋ฌํ ํจํด๋ค์ ์ดํดํ๊ณ ์ ์ ํ ํ์ฉํ๋ฉด, ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ๋ณต์กํ ์์คํ ์์๋ ํจ์จ์ ์ธ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ๊ตฌํํ ์ ์์ด์. ๐จโ๐ฌ
3. ์ฑ๋ฅ ์ต์ ํ ๊ธฐ๋ฒ
๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ํตํด ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ง๋ง, ์๋ชป ์ฌ์ฉํ๋ฉด ์คํ๋ ค ์ฑ๋ฅ์ด ์ ํ๋ ์ ์์ด์. ๋ค์๊ณผ ๊ฐ์ ์ต์ ํ ๊ธฐ๋ฒ์ ๊ณ ๋ คํด๋ณด์ธ์:
- ์ ์ ํ ๋ณ๋ ฌ ์ฒ๋ฆฌ: CompletableFuture.allOf()๋ฅผ ์ฌ์ฉํด ์ฌ๋ฌ ์์ ์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํด๋ณด์ธ์.
- ์บ์ฑ: ์์ฃผ ์ฌ์ฉ๋๋ ๋น๋๊ธฐ ์์ ์ ๊ฒฐ๊ณผ๋ฅผ ์บ์ฑํ์ธ์.
- ๋ฐฑํ๋ ์ (Backpressure) ๊ด๋ฆฌ: ๋ฐ์ดํฐ ์์ฑ ์๋์ ์๋น ์๋์ ๊ท ํ์ ๋ง์ถ์ธ์.
์ด๋ฌํ ๊ธฐ๋ฒ๋ค์ ์ ์ฉํ๋ฉด, ์ฌ๋ฅ๋ท์ ๊ฒ์ ๊ธฐ๋ฅ์ด๋ ์ถ์ฒ ์์คํ ์ ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ ๊ฑฐ์์! ๐ช
4. ๋ถ์ฐ ์์คํ ์์์ ๋น๋๊ธฐ ์ฒ๋ฆฌ
๋๊ท๋ชจ ์์คํ ์์๋ ์ฌ๋ฌ ์๋ฒ๊ฐ ํ๋ ฅํ์ฌ ์์ ์ ์ฒ๋ฆฌํด์ผ ํด์. ์ด๋ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ ๋์ฑ ์ค์ํด์ง๋๋ค.
- ๋ฉ์์ง ํ: RabbitMQ๋ Apache Kafka๋ฅผ ์ฌ์ฉํด ๋น๋๊ธฐ ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํด๋ณด์ธ์.
- ์ด๋ฒคํธ ์์ฑ: ์์คํ ์ ์ํ ๋ณํ๋ฅผ ์ด๋ฒคํธ๋ก ๊ด๋ฆฌํ๋ ๋ฐฉ์์ ๊ณ ๋ คํด๋ณด์ธ์.
- CQRS ํจํด: ๋ช ๋ น๊ณผ ์กฐํ๋ฅผ ๋ถ๋ฆฌํ์ฌ ์์คํ ์ ํ์ฅ์ฑ์ ๋์ฌ๋ณด์ธ์.
์ด๋ฌํ ๊ธฐ์ ๋ค์ ํ์ฉํ๋ฉด, ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ๋๊ท๋ชจ ํ๋ซํผ์ ์๋ ์์ ์ ์ด๊ณ ํ์ฅ ๊ฐ๋ฅํ ๋น๋๊ธฐ ์์คํ ์ ๊ตฌ์ถํ ์ ์์ ๊ฑฐ์์. ๋ง์น ์ ์ธ๊ณ์ ๋ค์ํ ์ฌ๋ฅ์ ํ๋์ ํ๋ซํผ์์ ์ํํ๊ฒ ์ฐ๊ฒฐํ๋ ๊ฒ์ฒ๋ผ ๋ง์ด์ฃ ! ๐
๐จ ์ค์ ์์ : ์ฌ๋ฅ๋ท ์คํ์ผ์ ๋น๋๊ธฐ ์์คํ ๊ตฌํ
์, ์ด์ ์ฐ๋ฆฌ๊ฐ ๋ฐฐ์ด ๋ชจ๋ ๊ฒ์ ์ข ํฉํด์ ์ฌ๋ฅ๋ท๊ณผ ์ ์ฌํ ์์คํ ์ ์ผ๋ถ๋ฅผ ๊ตฌํํด๋ณผ๊น์? ์ด ์์ ์์๋ ์ฌ์ฉ์๊ฐ ์๋ก์ด ์ฌ๋ฅ์ ๋ฑ๋กํ ๋ ๋ฐ์ํ๋ ์ฌ๋ฌ ๋น๋๊ธฐ ์์ ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ๋๋ฆด๊ฒ์. ๐
@Service
public class TalentRegistrationService {
@Autowired
private TalentRepository talentRepository;
@Autowired
private UserNotificationService notificationService;
@Autowired
private SearchIndexService searchIndexService;
@Autowired
private RecommendationService recommendationService;
@Async
public CompletableFuture<TalentDTO> registerTalent(TalentDTO talentDTO) {
return CompletableFuture.supplyAsync(() -> {
// 1. ์ฌ๋ฅ ์ ๋ณด ์ ์ฅ
Talent savedTalent = talentRepository.save(new Talent(talentDTO));
// 2. ๋น๋๊ธฐ ์์
๋ค ์์
CompletableFuture<Void> notificationFuture = notificationService.notifyAdmins(savedTalent);
CompletableFuture<Void> indexingFuture = searchIndexService.indexTalent(savedTalent);
CompletableFuture<Void> recommendationFuture = recommendationService.updateRecommendations(savedTalent);
// 3. ๋ชจ๋ ๋น๋๊ธฐ ์์
์ด ์๋ฃ๋ ๋๊น์ง ๋๊ธฐ
CompletableFuture.allOf(notificationFuture, indexingFuture, recommendationFuture).join();
return new TalentDTO(savedTalent);
}).exceptionally(ex -> {
// ์์ธ ์ฒ๋ฆฌ
log.error("Error during talent registration", ex);
throw new TalentRegistrationException("Failed to register talent", ex);
});
}
}
@RestController
@RequestMapping("/api/talents")
public class TalentController {
@Autowired
private TalentRegistrationService registrationService;
@PostMapping
public CompletableFuture<ResponseEntity<TalentDTO>> registerTalent(@RequestBody TalentDTO talentDTO) {
return registrationService.registerTalent(talentDTO)
.thenApply(savedTalent -> ResponseEntity.ok(savedTalent))
.exceptionally(ex -> ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build());
}
}
์ด ์์ ์์๋ ๋ค์๊ณผ ๊ฐ์ ๋น๋๊ธฐ ์์ ๋ค์ ์ํํ๊ณ ์์ด์:
- ์ฌ๋ฅ ์ ๋ณด ์ ์ฅ: ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์๋ก์ด ์ฌ๋ฅ ์ ๋ณด๋ฅผ ์ ์ฅํฉ๋๋ค.
- ๊ด๋ฆฌ์ ์๋ฆผ: ์๋ก์ด ์ฌ๋ฅ์ด ๋ฑ๋ก๋์์์ ๊ด๋ฆฌ์์๊ฒ ์๋ฆฝ๋๋ค.
- ๊ฒ์ ์ธ๋ฑ์ฑ: ์๋ก์ด ์ฌ๋ฅ์ ๊ฒ์ ์์ง์ ์ธ๋ฑ์ฑํฉ๋๋ค.
- ์ถ์ฒ ์์คํ ์ ๋ฐ์ดํธ: ์๋ก์ด ์ฌ๋ฅ์ ๋ฐํ์ผ๋ก ์ถ์ฒ ์์คํ ์ ์ ๋ฐ์ดํธํฉ๋๋ค.
์ด ๋ชจ๋ ์์ ๋ค์ด ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌ๋๊ธฐ ๋๋ฌธ์, ์ฌ์ฉ์๋ ์ค๋ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ๋ ๋น ๋ฅธ ์๋ต์ ๋ฐ์ ์ ์์ด์. ๋ง์น ์ฌ๋ฅ๋ท์์ ์๋ก์ด ์ฌ๋ฅ์ ๋ฑ๋กํ๊ณ ์ฆ์ ํผ๋๋ฐฑ์ ๋ฐ๋ ๊ฒ์ฒ๋ผ ๋ง์ด์ฃ ! ๐
๐ก Pro Tip:
์ค์ ํ๋ก๋์ ํ๊ฒฝ์์๋ ์ด๋ฌํ ๋น๋๊ธฐ ์์ ๋ค์ ๋์ฑ ๊ฒฌ๊ณ ํ๊ฒ ๋ง๋ค์ด์ผ ํด์. ์๋ฅผ ๋ค์ด:
- ๊ฐ ์์ ์ ๋ํ ์ฌ์๋ ๋ฉ์ปค๋์ฆ ๊ตฌํ
- ๋ถ์ฐ ํธ๋์ญ์ ๊ด๋ฆฌ๋ฅผ ์ํ Saga ํจํด ์ ์ฉ
- ์ํท ๋ธ๋ ์ด์ปค ํจํด์ ํตํ ์ฅ์ ๊ฒฉ๋ฆฌ
- ์์ธํ ๋ชจ๋ํฐ๋ง ๋ฐ ๋ก๊น ๊ตฌํ
์ด๋ ๊ฒ ํ๋ฉด ๋๊ท๋ชจ ํธ๋ํฝ์์๋ ์์ ์ ์ผ๋ก ๋์ํ๋ ์์คํ ์ ๊ตฌ์ถํ ์ ์์ด์!
๐ ๋ง๋ฌด๋ฆฌ: ๋น๋๊ธฐ์ ๋ฏธ๋
์์ฐ! ์ ๋ง ๊ธด ์ฌ์ ์ด์์ฃ ? ์ฐ๋ฆฌ๋ Spring์ @Async๋ถํฐ CompletableFuture, ๊ทธ๋ฆฌ๊ณ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ๊น์ง ๊ด๋ฒ์ํ๊ฒ ์ดํด๋ดค์ด์. ์ด์ ์ฌ๋ฌ๋ถ์ ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ๋ณต์กํ ์์คํ ์์๋ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์์ ์์ฌ๋ก ํ์ฉํ ์ ์์ ๊ฑฐ์์! ๐
ํ์ง๋ง ๊ธฐ์ตํ์ธ์, ๊ธฐ์ ์ ์ธ๊ณ๋ ๊ณ์ํด์ ๋ฐ์ ํ๊ณ ์์ด์. ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ๋ฏธ๋๋ ์ด๋จ๊น์?
- Reactive Streams: ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ด ๋์ฑ ์ค์ํด์ง ๊ฑฐ์์.
- ์๋ฒ๋ฆฌ์ค ์ํคํ ์ฒ: AWS Lambda ๊ฐ์ ์๋น์ค๋ฅผ ํตํด ๋์ฑ ์ธ๋ถํ๋ ๋น๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํด์ง ๊ฑฐ์์.
- AI์์ ๊ฒฐํฉ: ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ์ ๋น๋๊ธฐ์ ์คํ๊ณผ ๊ฒฐ๊ณผ ์ฒ๋ฆฌ๊ฐ ์ผ์ํ๋ ๊ฑฐ์์.
- ์ฃ์ง ์ปดํจํ : ์ฌ์ฉ์์ ๊ฐ๊น์ด ๊ณณ์์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ํํ์ฌ ๋ ๋น ๋ฅธ ์๋ต์ ์ ๊ณตํ ์ ์์ ๊ฑฐ์์.
์ฌ๋ฌ๋ถ์ด ์ด ๊ธ์ ํตํด ๋ฐฐ์ด ๋ด์ฉ๋ค์ ์ด๋ฌํ ๋ฏธ๋ ๊ธฐ์ ์ ๊ธฐ๋ฐ์ด ๋ ๊ฑฐ์์. ๋ง์น ์ฌ๋ฅ๋ท์ด ๋ค์ํ ์ฌ๋ฅ์ ์ฐ๊ฒฐํ๋ฏ, ์ฌ๋ฌ๋ถ์ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ์ ์ ๋ฏธ๋์ ๊ธฐ์ ๋ค์ ์ฐ๊ฒฐํ๋ ๋ค๋ฆฌ ์ญํ ์ ํ ๊ฑฐ์์! ๐
์, ์ด์ ์ฌ๋ฌ๋ถ์ ์ฐจ๋ก์์. ์ด ์ง์์ ๊ฐ์ง๊ณ ์ด๋ค ๋ฉ์ง ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์ด๋ณผ ๊ฑด๊ฐ์? ์ฌ๋ฅ๋ท๋ณด๋ค ๋ ํ์ ์ ์ธ ํ๋ซํผ์ ๋ง๋ค ์ ์์์ง๋ ๋ชจ๋ฅด๊ฒ ๋ค์! ํ์ดํ ! ๐ช๐
- ์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์ฌ๋ฅ๋ท์ ์ต์ AI ๊ธฐ์ ๊ณผ ๋ฒ๋ฅ ์ ๊ธฐ๋ฐํ์ฌ ์์ฌ์ ์ง์ ์ฌ์ฐ๊ถ์ ์ ๊ทน์ ์ผ๋ก ๋ณดํธํ๋ฉฐ,
๋ฌด๋จ ์ฌ์ฉ ๋ฐ ์นจํด ํ์์ ๋ํด ๋ฒ์ ๋์์ ํ ๊ถ๋ฆฌ๋ฅผ ๋ณด์ ํฉ๋๋ค.
ยฉ 2025 ์ฌ๋ฅ๋ท | All rights reserved.
๋๊ธ 0๊ฐ