Skip to content

0is2/GDmarket-Premium

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

11 Commits
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

GDmarket-Premium

GDmarket : ๊ทผ๋Œ€๋งˆ์ผ“ - ๊ทผ๊ฑฐ๋ฆฌ ๋Œ€์—ฌ ๋งˆ์ผ“ (Premium)

image

Table of contents

์ฒดํฌํฌ์ธํŠธ

  1. Saga
  2. CQRS
  3. Correlation
  4. Req/Res
  5. Gateway
  6. Deploy / Pipeline
  7. Circuit Breaker
  8. Autoscale (HPA)
  9. Zero-downtime deploy (Readiness Probe)
  10. Config Map/ Persistence Volume
  11. Polyglot
  12. Self-healing (Liveness Probe)

์„œ๋น„์Šค ์‹œ๋‚˜๋ฆฌ์˜ค

๊ธฐ๋Šฅ์  ์š”๊ตฌ์‚ฌํ•ญ

  1. ๋ฌผ๊ฑด๊ด€๋ฆฌ์ž๋Š” ๋ฌผ๊ฑด์„ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค
  2. ๋ฌผ๊ฑด๊ด€๋ฆฌ์ž๋Š” ๋ฌผ๊ฑด์„ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋‹ค.
  3. ๋Œ€์—ฌ์ž๋Š” ๋ฌผ๊ฑด์„ ์„ ํƒํ•˜์—ฌ ์˜ˆ์•ฝํ•œ๋‹ค.
  4. ๋Œ€์—ฌ์ž๋Š” ์˜ˆ์•ฝ์„ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋‹ค.
  5. ์˜ˆ์•ฝ์ด ์™„๋ฃŒ๋˜๋ฉด ํ•ด๋‹น ๋ฌผ๊ฑด์€ ๋Œ€์—ฌ๋ถˆ๊ฐ€ ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค.
  6. ๋Œ€์—ฌ์ž๊ฐ€ ๊ฒฐ์ œํ•œ๋‹ค.
  7. ๋Œ€์—ฌ์ž๋Š” ๊ฒฐ์ œ๋ฅผ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋‹ค.
  8. ๋ฌผ๊ฑด๊ด€๋ฆฌ์ž๋Š” ๋ฌผ๊ฑด์„ ๋Œ€์—ฌํ•ด์ค€๋‹ค.
  9. ๋Œ€์—ฌ์ž๊ฐ€ ๋Œ€์—ฌ์š”์ฒญ์„ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋‹ค.
  10. ๋ฌผ๊ฑด์ด ๋ฐ˜๋‚ฉ๋˜๋ฉด ๋ฌผ๊ฑด์€ ๋Œ€์—ฌ๊ฐ€๋Šฅ ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค.
  11. ๋ฌผ๊ฑด๊ด€๋ฆฌ์ž๋Š” ๋ฌผ๊ฑด ํ†ตํ•ฉ์ƒํƒœ๋ฅผ ์ค‘๊ฐ„์ค‘๊ฐ„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.
  12. (Premium) ๋ฌผ๊ฑด์ด ๋“ฑ๋ก๋˜๋ฉด ๋“ฑ๋ก ์•Œ๋žŒ์ด ๋ฐœ์ƒํ•œ๋‹ค.
  13. (Premium) ๋ฌผ๊ฑด์ด ์‚ญ์ œ๋˜๋ฉด ์‚ญ์ œ ์•Œ๋žŒ์ด ๋ฐœ์ƒํ•œ๋‹ค.

๋น„๊ธฐ๋Šฅ์  ์š”๊ตฌ์‚ฌํ•ญ

  1. ํŠธ๋žœ์žญ์…˜
    1. ๊ฒฐ์ œ์Šน์ธ์ด ๋˜์ง€ ์•ˆ์€ ๊ฑด์€ ๊ฒฐ์ œ์š”์ฒญ์ด ์™„๋ฃŒ๋˜์ง€ ์•Š์•„์•ผํ•œ๋‹ค. Sync ํ˜ธ์ถœ
    2. ๋“ฑ๋ก ์•Œ๋žŒ์ด ๋ฐœ์ƒ๋˜์ง€ ์•Š์€ ๊ฑด์€ ๋ฌผ๊ฑด๋“ฑ๋ก์ด ์™„๋ฃŒ๋˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค. Sync ํ˜ธ์ถœ (Premium)
  2. ์žฅ์• ๊ฒฉ๋ฆฌ
    1. ๋ฌผ๊ฑด๊ด€๋ฆฌ์‹œ์Šคํ…œ์ด ์ˆ˜ํ–‰๋˜์ง€ ์•Š๋”๋ผ๋„ ๋Œ€์—ฌ ์š”์ฒญ์€ 365์ผ 24์‹œ๊ฐ„ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. > Async
    2. ๊ฒฐ์ œ์‹œ์Šคํ…œ์ด ๊ณผ์ค‘๋˜๋ฉด ๊ฒฐ์ œ์š”์ฒญ์„ ์ž ์‹œ๋™์•ˆ ๋ฐ›์ง€ ์•Š๊ณ  ๊ฒฐ์ œ๋ฅผ ์ž ์‹œ ํ›„์— ํ•˜๋„๋ก ์œ ๋„ํ•œ๋‹ค. > Circuit breaker
    3. (Premium) ์•Œ๋žŒ์‹œ์Šคํ…œ์ด ์ˆ˜ํ–‰๋˜์ง€ ์•Š๋”๋ผ๋„ ๋ฌผ๊ฑด ์‚ญ์ œ ์š”์ฒญ์€ 365์ผ 24์‹œ๊ฐ„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค > Async
    4. (Premium) ์•Œ๋žŒ์‹œ์Šคํ…œ์ด ๊ณผ์ค‘๋˜๋ฉด ๋ฌผ๊ฑด๋“ฑ๋ก์„ ์ž ์‹œ๋™์•ˆ ๋ฐ›์ง€ ์•Š๊ณ  ์•Œ๋žŒ์„ ์ž ์‹œ ํ›„์— ํ•˜๋„๋ก ์œ ๋„ํ•œ๋‹ค. > Circuit breaker
  3. ์„ฑ๋Šฅ
    1. ๋ฌผ๊ฑด๊ด€๋ฆฌ์ž๊ฐ€ ๋“ฑ๋กํ•œ ๋ฌผ๊ฑด์˜ ํ†ตํ•ฉ์ƒํƒœ๋ฅผ ๋ณ„๋„๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. > CQRS

์„ค๊ณ„

๊ธฐ๋ณธ ๋ชจ๋ธ

  • item, reservation, payment ์„œ๋น„์Šค ๊ตฌํ˜„ model

Premium ๋ชจ๋ธ

  • alarm ์„œ๋น„์Šค๊ฐ€ ์ถ”๊ฐ€๋จ model-premium

๊ตฌํ˜„

Saga

  • Pub/Sub์„ ๊ตฌํ˜„ํ•œ๋‹ค.
  • (Pub) ํ˜ธ์ถœ ์„œ๋น„์Šค ๋ฐ Event : item / item์ด ์‚ญ์ œ๋จ
   // item > Item.java
   
    @PreRemove
    public void onPreRemove() {
        ItemDeleted itemDeleted = new ItemDeleted();
        itemDeleted.setItemNo(this.getItemNo());
        itemDeleted.setAlarmStatus("DeleteAlerted");

        ObjectMapper objectMapper = new ObjectMapper();
        String json = null;
        try {
            json = objectMapper.writeValueAsString(itemDeleted);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("JSON format exception", e);
        }
        KafkaProcessor processor = ItemApplication.applicationContext.getBean(KafkaProcessor.class);
        MessageChannel outputChannel = processor.outboundTopic();
        outputChannel.send(org.springframework.integration.support.MessageBuilder
                .withPayload(json)
                .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON)
                .build());
        System.out.println("@@@@@@@ itemDeleted to Json @@@@@@@");
        System.out.println(itemDeleted.toJson());
    }

9 itemDelete

  • (Sub) ํ”ผํ˜ธ์ถœ ์„œ๋น„์Šค ๋ฐ Policy : alarm / alarm ์ƒํƒœ ๋ณ€๊ฒฝ (Alerted -> DeleteAlerted)
   // alarm > PolicyHandler.java
   
   @StreamListener(KafkaProcessor.INPUT)
    public void wheneverItemDeleted_(@Payload ItemDeleted itemDeleted){
        if(itemDeleted.isMe()){
            System.out.println("##### listener  : " + itemDeleted.toJson());
            if("DeleteAlerted".equals(itemDeleted.getAlarmStatus())){
                Alarm alarm = (Alarm) alarmManagementRepository.findByItemNo(itemDeleted.getItemNo()).get(0);
                alarm.setAlarmStatus("DeleteAlerted");
                alarmManagementRepository.save(alarm);
            }
        }
    }

10 wheneverItemDeleted_

CQRS

  • command์™€ query์˜ ์—ญํ• ์„ ๋ถ„๋ฆฌํ•œ๋‹ค. (view ๊ตฌํ˜„)
  • item ์ด ๋“ฑ๋ก๋  ๋•Œ ์•Œ๋žŒ์ƒํƒœ(AlarmStatus)๋ฅผ View๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„
  • item ์ฝ”๋“œ ๊ตฌํ˜„
// item > Item.java

    @PostPersist
    public void onPostPersist(){
        ItemRegistered itemRegistered = new ItemRegistered();
        itemRegistered.setItemNo(this.getItemNo());
        itemRegistered.setItemName(this.getItemName());
        itemRegistered.setItemPrice(this.getItemPrice());
        itemRegistered.setItemStatus("Rentable");
        itemRegistered.setRentalStatus("NotRenting");
        itemRegistered.setAlarmStatus("Alerted");
        
        // view๋ฅผ ์œ„ํ•ด Kafka Send
        ObjectMapper objectMapper = new ObjectMapper();
        String json = null;
        try {
            json = objectMapper.writeValueAsString(itemRegistered);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("JSON format exception", e);
        }
        KafkaProcessor processor = ItemApplication.applicationContext.getBean(KafkaProcessor.class);
        MessageChannel outputChannel = processor.outboundTopic();
        outputChannel.send(org.springframework.integration.support.MessageBuilder
                .withPayload(json)
                .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON)
                .build());

        System.out.println("@@@@@@@ ItemRegistered to Json @@@@@@@");
        System.out.println(itemRegistered.toJson());
   }

11 A cqrs

  • view ์ฝ”๋“œ ๊ตฌํ˜„
// item > ItemInfoViewHandler.java

   @StreamListener(KafkaProcessor.INPUT)
    public void whenItemRegistered_then_CREATE_1 (@Payload ItemRegistered itemRegistered) {
        try {
            if (itemRegistered.isMe()) {
                // view ๊ฐ์ฒด ์ƒ์„ฑ
                ItemInfo itemInfo= new ItemInfo();
                // view ๊ฐ์ฒด์— ์ด๋ฒคํŠธ์˜ Value ๋ฅผ set ํ•จ
                itemInfo.setItemNo(itemRegistered.getItemNo());
                itemInfo.setItemName(itemRegistered.getItemName());
                itemInfo.setItemStatus(itemRegistered.getItemStatus());
                itemInfo.setItemPrice(itemRegistered.getItemPrice());
                itemInfo.setAlarmStatus(itemRegistered.getAlarmStatus());
                // view ๋ ˆํŒŒ์ง€ ํ† ๋ฆฌ์— save
                itemInfoRepository.save(itemInfo);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

11 cqrs

Correlation

  • ๊ฐ ๋งˆ์ดํฌ๋กœ ์„œ๋น„์Šค๋Š” ์ƒํ˜ธ ๊ด€๋ จ ํ‚ค๋ฅผ ๊ฐ–๋Š”๋‹ค.
  • CQRS ๊ตฌํ˜„์„ ์œ„ํ•ด, Alarm๊ณผ ItemInfo๋Š” ์ƒํ˜ธ ๊ด€๋ จ ํ‚ค 'itemNo', 'alarmStatus'๋ฅผ ๊ฐ–๋Š”๋‹ค.
  • Alarm.java
    13 alarm
  • ItemInfo.java
    12 item info

Req/Res

  • Sync ํ˜ธ์ถœ์„ ๊ตฌํ˜„ํ•œ๋‹ค.
  • (Req) ํ˜ธ์ถœ ์„œ๋น„์Šค ๊ตฌํ˜„
// item.java > onPostPersist()

// alarm REQ/RES
System.out.println("@@@ Alarm @@@");
System.out.println("@@@ ItemNo : " + getItemNo());

gdmarketpremium.external.Alarm alarm = new gdmarketpremium.external.Alarm();
alarm.setAlarmStatus("Alerted");
alarm.setAlarmNo(getItemNo());
alarm.setItemNo(getItemNo());

14 Item onPostPersist

  • (Res) ํ”ผํ˜ธ์ถœ ์„œ๋น„์Šค ๊ตฌํ˜„
// AlarmService.java

@FeignClient(name="alarm", url="${api.alarm.url}")
public interface AlarmService {
 @RequestMapping(method= RequestMethod.POST, path="/alarms")
    public void alert(@RequestBody Alarm alarm);
}

15 alarmservice

Gateway

  • ๊ฐ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค๋Š” gateway๋ฅผ ํ†ตํ•ด์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค
  • gateway ์„œ๋น„์Šค > application.yml ํŒŒ์ผ์— ๊ตฌํ˜„ํ•œ๋‹ค.
  • local ์„ธํŒ…
    16 local
  • docker ์„ธํŒ…
    17 docker

๊ตฌํ˜„ ๊ฒ€์ฆ

  • item ๋“ฑ๋กํ•จ
http POST item:8080/items/ itemName=Camera itemPrice=100 itemStatus=Rentable rentalStatus=NotRenting

1 ์•„์ดํ…œ๋“ฑ๋ก

  • Sync ํ˜ธ์ถœ๋กœ alarm ์ƒ์„ฑ๋จ (Req/Res)
http alarm:8080/alarms

2 REQRES ์ƒ์„ฑ๋จ

  • CQRS : alarmStatus๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Œ
http item:8080/itemInfoes

5 view

  • item ์‚ญ์ œํ•จ
http DELETE item:8080/items/1

3 ์•„์ดํ…œ์‚ญ์ œ

  • Async ํ˜ธ์ถœ๋กœ alarm ์ƒํƒœ ๋ณ€๊ฒฝ๋จ (Alerted -> DeleteAlerted) (Pub/Sub)
http alarm:8080/alarms

4 PUBSUB ์‹คํ–‰๋จ

  • gateway๋กœ reservation ์„œ๋น„์Šค GET ํ˜ธ์ถœ
http gateway:8080/reservations

18 gateway

์šด์˜

Deploy

  • (1-1) ์ปจํ…Œ์ด๋„ˆ๋ผ์ด์ง• : ๋””ํ”Œ๋กœ์ด ์ƒ์„ฑ ํ™•์ธ (gateway ์„œ๋น„์Šค๋Š” api ์‚ฌ์šฉ)
kubectl create deploy gateway --image=gdpremiumacr.azurecr.io/gateway:latest

6-0 kubectl create deploy

  • (1-2) ์ปจํ…Œ์ด๋„ˆ๋ผ์ด์ง• : ๋””ํ”Œ๋กœ์ด ์ƒ์„ฑ ํ™•์ธ (๊ทธ ์™ธ ์„œ๋น„์Šค๋Š” yml ์‚ฌ์šฉ)
kubectl apply -f kubernetes/deployment.yml

6 kubectl apply

  • (2) ์ปจํ…Œ์ด๋„ˆ๋ผ์ด์ง•: ์„œ๋น„์Šค ์ƒ์„ฑ ํ™•์ธ (gateway ํฌํ•จ๋ชจ๋“  ์„œ๋น„์Šค ๋™์ผ)
kubectl expose deploy gateway --type="ClusterIP" --port=8080

7 kubectl expose deploy

  • ๋ชจ๋“  ์„œ๋น„์Šค๊ฐ€ ์ž˜ Running ๋จ์„ ํ™•์ธ
kubectl get all

8 kube get all

CirCuit Breaker

  • CirCuit Breaker Framework : Spring FeignClient + Hystrix ์‚ฌ์šฉ
  • (ํ˜ธ์ถœ) item ์„œ๋น„์Šค > application.yml : timeoutInMilliseconds 610 ์œผ๋กœ ์„ค์ •
hystrix:
  command:
    default:
      execution.isolation.thread.timeoutInMilliseconds: 610

26 610

  • (ํ”ผํ˜ธ์ถœ) alarm ์„œ๋น„์Šค > Alarm.java : sleep 440 + ๋žœ๋ค 220 ์œผ๋กœ ์„ค์ •
Thread.currentThread().sleep((long) (400 + Math.random() * 220));

26 sleep

  • siege ํˆด์„ ํ†ตํ•œ ์„œํ‚ท ๋ธŒ๋ ˆ์ด์ปค ๋™์ž‘ ํ™•์ธ
  • ๋™์‹œ์‚ฌ์šฉ์ž 10๋ช… , 30์ดˆ ๋™์•ˆ siege ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ ์‹ค์‹œ
siege -c10 -t30S -r10 -v --content-type "application/json" 'http://item:8080/items POST {"itemName":"Camera"}'

25 ๋ถ€ํ•˜ํ…Œ์ŠคํŠธ

25 ๋ถ€ํ•˜ํ…Œ์ŠคํŠธ 2

Autoscale

  • item ์‹œ์Šคํ…œ์— ๋Œ€ํ•œ replica ๋ฅผ ๋™์ ์œผ๋กœ ๋Š˜๋ ค์ฃผ๋„๋ก HPA ๋ฅผ ์„ค์ •ํ•œ๋‹ค.
  • item ์‹œ์Šคํ…œ์˜ resource ์— ์ œํ•œ์„ ๊ฑธ์–ด๋‘”๋‹ค.
// item > deployment.yml

 resources:
   limits:
     cpu: 500m
   requests:
     cpu: 200m

28 a1

  • HPA ์„ค์ •์€ CPU ์‚ฌ์šฉ๋Ÿ‰์ด 15ํ”„๋กœ๋ฅผ ๋„˜์–ด์„œ๋ฉด replica ๋ฅผ 10๊ฐœ๊นŒ์ง€ ๋Š˜๋ ค์ค€๋‹ค.
  • CirCuit Breaker์™€ ๋™์ผํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์›Œํฌ๋กœ๋“œ๋ฅผ 50์ดˆ ๊ฑธ์–ด์ค€๋‹ค.
 kubectl autoscale deploy reservation --min=1 --max=10 --cpu-percent=15
 kubectl exec -it pod/siege-5459b87f86-wpwkt -c siege -- /bin/bash
 siege -c250 -t50S -r1000 -v --content-type "application/json" 'http://item:8080/items POST {"itemName":"Camera"}'

27 autoscale

  • ์˜คํ† ์Šค์ผ€์ผ ๋ชจ๋‹ˆํ„ฐ๋ง์„ ํ•œ๋‹ค.
kubectl get deploy reservation -w

27 autoscale 2

๋ฌด์ •์ง€ ์žฌ๋ฐฐํฌ

Config Map

  • alarm ์„œ๋น„์Šค๋ฅผ REQ๋กœ ํ˜ธ์ถœํ•˜๋Š” item ์„œ๋น„์Šค์— config map์„ ๊ตฌํ˜„ํ•œ๋‹ค.
  • item > application.yml : local
    19 item app local
  • item > application.yml : docker
    20 item app docker
  • item > deployment.yml : env ์„ธํŒ…
    21 item deployment env
  • item > external > AlarmService.java : env ์‚ฌ์šฉ
    22 item external alarmservice
  • config map ์ƒ์„ฑ ๋ฐ ํ™•์ธ
# ์ƒ์„ฑ
kubectl create configmap newurl --from-literal=url=http://alarm:8080

# ํ™•์ธ
kubectl get configmap newurl -o yaml

23 configmap ํ™•์ธ

Polyglot

  • ๋‹คํ˜•์„ฑ์„ ๋งŒ์กฑํ•˜๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค.

  • item, reservation ์„œ๋น„์Šค๋Š” H2 DB๋กœ ๊ตฌํ˜„ํ•˜๊ณ , ๊ทธ์™€ ๋‹ฌ๋ฆฌ payment, alarm ์„œ๋น„์Šค์˜ ๊ฒฝ์šฐ Hsql DB๋กœ ๊ตฌํ˜„ํ•œ๋‹ค.

  • item, reservation ์„œ๋น„์Šค์˜ pom.xml ์„ค์ •
    1 p1

  • payment, alarm ์„œ๋น„์Šค์˜ pom.xml ์„ค์ •
    1 p2

Self-healing

About

GDmarket : Premium version

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors