AWS S3 ์ด๋ฏธ์ง€ ๊ด€๋ จ ๋กœ์ง๊ณผ DB๋กœ์ง ํŠธ๋žœ์žญ์…˜ ๋ถ„๋ฆฌ (DB ์ปค๋„ฅ์…˜ ๋ฌธ์ œ)

์ฝ”๋“œ๋ฅผ ์งœ๋‹ค๋ณด๋ฉด ๊ฒŒ์‹œ๊ธ€๊ณผ ๊ฐ™์€ ์—”ํ„ฐํ‹ฐ๋ฅผ ๋“ฑ๋กํ•  ๋•Œ ํŒŒ์ผ์„ ์ถ”๊ฐ€๋กœ ์—…๋กœ๋“œํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งค์šฐ ๋งŽ๋‹ค.

 

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ๋„ ๊ณต์—ฐ ํฌ์ŠคํŠธ๋ฅผ DB์— ์ €์žฅํ•˜๋ฉด์„œ ์ธ๋„ค์ผ ์ด๋ฏธ์ง€์™€ ๋‚ด์šฉ์— ๋“ค์–ด๊ฐˆ ์ด๋ฏธ์ง€ ๋“ฑ์ด AWS S3์— ํ•จ๊ป˜ ์ €์žฅ๋˜์—ˆ๋‹ค. 

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์กฐํšŒํ•  ๋•Œ๋„ AWS S3์—์„œ ์กฐํšŒํ•˜๋Š” ๋กœ์ง๊ณผ DB์—์„œ ํฌ์ŠคํŠธ๋ฅผ ์กฐํšŒํ•˜๋Š” ๋กœ์ง์ด ํ•จ๊ป˜ ์ˆ˜ํ–‰๋œ๋‹ค. 

 

 

 

์ด๋•Œ ์™ธ๋ถ€์—์„œ ๋ฆฌ์†Œ์Šค๋ฅผ ์กฐํšŒํ•ด์˜ค๋Š” ๋กœ์ง๊ณผ DB์—์„œ ์กฐํšŒํ•ด์˜ค๋Š” ๋กœ์ง์„ ํ•œ ํŠธ๋žœ์žญ์…˜์— ๋ฌถ์œผ๋ฉด ์•ˆ ์ข‹์ง€ ์•Š์„๊นŒ?? ๋ฌธ๋“ ์ด๋Ÿฐ ์ƒ๊ฐ์ด ๋“ค์—ˆ๊ณ  ๊ตฌ๊ธ€๋ง ํ•ด๋ณด๋‹ˆ ์—ญ์‹œ๋‚˜ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๋„ ์ด๋ฏธ ๊ณ ๋ฏผํ–ˆ๋˜ ํ”์ ๋“ค์ด ๋ณด์˜€๋‹ค.

 

 

 

์™œ ํ•œ ํŠธ๋žœ์žญ์…˜์— ๋ฌถ์œผ๋ฉด ์ข‹์ง€ ์•Š์„๊นŒ?? 

ํŠธ๋žœ์žญ์…˜์˜ ํŠน์ง•์— ์ฃผ๋ชฉํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค. 

ํ•œ ํŠธ๋žœ์žญ์…˜์ด ์‹œ์ž‘๋˜๋ฉด DB์™€์˜ ์ปค๋„ฅ์…˜์„ ๋งบ๊ณ  ํŠธ๋žœ์žญ์…˜์ด ๋๋‚ ๋•Œ๊นŒ์ง€ ์ปค๋„ฅ์…˜์„ ๋Š์ง€ ์•Š๋Š”๋‹ค.  

 

์•„๋ž˜ ์ฝ”๋“œ์—์„œ ์ด๋ฅผ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

@Service
@RequiredArgsConstructor
public class MemberService {

    private final MemberRepository memberRepository;
    private final MemberResourceService resourceService;
    private final DataSource dataSource;

    @Transactional
    public Member create(CreateMemberRequest request) {
        printConnectionStatus();

        Member member = new Member(request.getUsername());
        memberRepository.save(member);

        resourceService.upload(request.getUserImage());

        printConnectionStatus();
        return member;
    }

    private void printConnectionStatus() {
        final HikariPoolMXBean hikariPoolMXBean = ((HikariDataSource) dataSource).getHikariPoolMXBean();
        System.out.println("################################");
        System.out.println("ํ˜„์žฌ active์ธ connection์˜ ์ˆ˜ : " + hikariPoolMXBean.getActiveConnections());
        System.out.println("ํ˜„์žฌ idle์ธ connection์˜ ์ˆ˜ : " + hikariPoolMXBean.getIdleConnections());
        System.out.println("################################");
    }

}

 

 

 

ํŠธ๋žœ์žญ์…˜ ์ง„์ž… ์งํ›„ ์ปค๋„ฅ์…˜ ํ’€ ์ƒํ™ฉ๊ณผ ํŠธ๋žœ์žญ์…˜ ์ข…๋ฃŒ ์ง์ „์˜ ์ปค๋„ฅ์…˜ ํ’€ ์ƒํ™ฉ์„ ์ถœ๋ ฅํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜จ๋‹ค.

 

 

 

์ฆ‰, ์—…๋กœ๋“œํ•  ํŒŒ์ผ์˜ ํฌ๊ธฐ๊ฐ€ ํฌ๋‹ค๋ฉด DB ์ปค๋„ฅ์…˜์„ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์ ์œ ํ•˜๋ฉด์„œ ์ž์›์„ ํฌ๊ฒŒ ๋‚ญ๋น„ํ•˜๊ฒŒ ๋œ๋‹ค.

 

 

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ช‡๋ช‡ ๋ฐฉ๋ฒ•๋“ค์„ ๋ดค์ง€๋งŒ ๋‚˜๋Š” ํŠธ๋žœ์žญ์…˜ ๋ถ„๋ฆฌ๋ฅผ ์‹œ์ผœ ํ•ด๊ฒฐ์„ ์‹œ๋„ํ–ˆ๋‹ค. 

 

 

์‹œ๋„ 1) ํŠธ๋žœ์žญ์…˜์„ ๋‹ฌ์ง€ ์•Š์€ ๋ฉ”์†Œ๋“œ์—์„œ ํŠธ๋žœ์žญ์…˜์„ ๋‹จ DB ์ €์žฅ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ €์žฅํ•  ๋•Œ๋งŒ ํŠธ๋žœ์žญ์…˜ ์‚ฌ์šฉ - ์‹คํŒจ

 

๋‚ด ์ฝ”๋“œ๋Š” ์•„๋‹ˆ์ง€๋งŒ ๋น„์Šทํ•œ ์ข‹์€ ์˜ˆ์ œ๊ฐ€ ์žˆ์–ด์„œ ๊ฐ€์ ธ์™”๋‹ค.

 

public Member create(CreateMemberRequest request) {
    printConnectionStatus();

    Member member = createEntity(request.getUsername());

    resourceService.upload(request.getUserImage());

    printConnectionStatus();
    return member;
}

@Transactional
public Member createEntity(String username) {
    Member member = new Member(username);
    memberRepository.save(member);
    return member;
}

 

์œ„ ์ฝ”๋“œ์—์„  @Transactional  ์–ด๋…ธํ…Œ์ด์…˜์ด ์ ์šฉ๋œ createEntity ๋ฉ”์„œ๋“œ๊ฐ€ ์‚ฌ์‹ค ํŠธ๋žœ์žญ์…˜์ด ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค. 

์ด์œ ๋Š” Spring AOP๋Š” ํ”„๋ก์‹œ ํŒจํ„ด์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. 

์ฆ‰, A๋นˆ์—์„œ B๋นˆ์„ ํ˜ธ์ถœํ•˜๊ธฐ ์ „์— B์˜ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋œ๋‹ค.

ํ•˜์ง€๋งŒ A ์ธ์Šคํ„ด์Šค์—์„œ ์ž์‹ ์„ ํ˜ธ์ถœํ•œ๋‹ค ํ•ด๋„ ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ํ˜ธ์ถœ๋˜์ง€ ์•Š๊ณ  @Transactional๋„ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค. 

 

 

์‹œ๋„ 2) ๋ฉ”์†Œ๋“œ ๋‹จ์—์„œ ๋ถ„๋ฆฌํ•˜์ง€ ๋ง๊ณ  ๋นˆ์„ ๋ถ„๋ฆฌํ•ด๋ณด์ž

์œ„ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„  ์„œ๋น„์Šค ํด๋ž˜์Šค๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ๋นˆ์ด ๋ถ„๋ฆฌ๋˜๋ฏ€๋กœ ํŠธ๋žœ์žญ์…˜์„ ์ •์‚ญ ๋™์ž‘ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

 

๋ถ„๋ฆฌ๋œ ์„œ๋น„์Šค ํด๋ž˜์Šค๋“ค์„ Facade ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด์„œ ๊ณ„์ธต์„ ํ•˜๋‚˜ ๋” ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•๋„ ์ข‹์•„๋ณด์˜€๋‹ค.

 

 

ํผ์‚ฌ๋“œ ํŒจํ„ด(Facade Pattern)์€ ๊ตฌ์กฐ ํŒจํ„ด(Structural Pattern)์˜ ํ•œ ์ข…๋ฅ˜๋กœ์จ, ๋ณต์žกํ•œ ์„œ๋ธŒ ํด๋ž˜์Šค๋“ค์˜ ๊ณตํ†ต์ ์ธ ๊ธฐ๋Šฅ์„ ์ •์˜ํ•˜๋Š” ์ƒ์œ„ ์ˆ˜์ค€์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ํŒจํ„ด์ด๋‹ค.

 

 

 

์—ฌ๋Ÿฌ SubSystem๋“ค์˜ ๊ธฐ๋Šฅ์„ ํ•˜๋‚˜์˜ Facade Object๋กœ ์ •์˜ํ•˜๊ณ , Client๊ฐ€ Facade Object๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ˜•ํƒœ์ด๋‹ค.

 

 

๋‚ด ์ƒํ™ฉ์—์„  ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ์™€ DB์— ์—”ํ‹ฐํ‹ฐ ์ €์žฅ ๊ธฐ๋Šฅ์„ ํ•˜๋‚˜์˜ Facade Object๋กœ ์ •์˜ํ•˜๊ณ  ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ด๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋•Œ Facade Object์—๋Š” ํŠธ๋žœ์žญ์…˜์ด ๋‹น์—ฐํžˆ ๋ถ™์ง€ ์•Š์•„์•ผ ํ•˜๊ณ  ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ๋ถ€๋ถ„์—๋งŒ ํŠธ๋žœ์žญ์…˜์„ ๋ถ™์—ฌ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

 

 

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์งง์€ ํŠธ๋žœ์žญ์…˜์„ ์œ ์ง€ํ•˜๋ฉด์„œ ์ œ ๊ธฐ๋Šฅ์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌํ˜„ ๊ฐ€๋Šฅํ•˜๋‹ค. 

ํ•˜์ง€๋งŒ ํ•œ๊ฐ€์ง€ ๋ฌธ์ œ์ ์ด ์žˆ๋‹ค.

AWS S3์— ์ด๋ฏธ์ง€๋Š” ์—…๋กœ๋“œ ๋˜์—ˆ์ง€๋งŒ ์—”ํ‹ฐํ‹ฐ ์ €์žฅ ์ค‘์— ์—๋Ÿฌ๊ฐ€ ๋‚˜์„œ ๋กค๋ฐฑ์ด ๋˜์—ˆ๋‹ค๋ฉด ์—…๋กœ๋“œ๋œ ์ด๋ฏธ์ง€๋Š” ์“ฐ๋ ˆ๊ธฐ ๊ฐ’์ด ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

์ด ๋ฌธ์ œ๋Š”  DB ์ €์žฅ์—์„œ ์‹คํŒจํ•˜๋ฉด ์—๋Ÿฌ๋ฅผ ๋˜์ง€๊ณ  ์ด ์—๋Ÿฌ๋ฅผ Facade ์ธ์Šคํ„ด์Šค์—์„œ catch๋กœ ์žก์•„์„œ ๋ฐ”๋กœ ํ•ด๋‹น ์ด๋ฏธ์ง€๋ฅผ S3 ์ €์žฅ์†Œ์—์„œ ์‚ญ์ œํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์•˜๋‹ค.