본문 바로가기
카테고리 없음

마이크로서비스 개발 1

by ^..^v 2022. 3. 17.
728x90
반응형

1 OAS(OpenAPI Spec) 설계

 

1.1 항공편 마이크로서비스 OAS

https://github.com/implementing-microservices/ms-flights/blob/master/docs/api.yml

openapi: 3.0.0
info:
  title: Flights Management Microservice API
  description: |
    API Spec for Fight Management System
  version: 1.0.1
servers:
  - url: http://api.example.com/v1
    description: Production Server
paths:
  /flights:
    get:
      summary: Look Up Flight Details with Flight No and Departure Date
      description: |
        Lookup flight details, such as: the unique flight_id used by the
        rest of the Flights management endpoints, flight departure and
        arrival airports.

        Example request:
        ```
          GET http://api.example.com/v1/flights?flight_no=AA2532&departure_date_time=2020-05-17T13:20
        ```
      parameters:
        - name: flight_no
          in: query
          required: true
          description: Flight Number.
          schema:
            type : string
          example: AA2532
        - name: departure_date_time
          in: query
          required: true
          description: Date and time (in ISO8601)
          schema:
            type : string
          example: 2020-05-17T13:20


      responses:
        '200':    # success response
          description: Successful Response
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    flight_id:
                      type: string
                      example: "edcc03a4-7f4e-40d1-898d-bf84a266f1b9"
                    origin_code:
                      type: string
                      example: "LAX"
                    destination_code:
                      type: string
                      example: "DCA"

                example:
                  flight_id: "edcc03a4-7f4e-40d1-898d-bf84a266f1b9"
                  origin_code: "LAX"
                  destination_code: "DCA"

  /flights/{flight_no}/seat_map:
    get:
      summary: Get a seat map for a flight
      description: |
        Example request:
        ```
          GET http://api.example.com/v1/flights/AA2532/datetime/2020-05-17T13:20/seats/12C
        ```
      parameters:
        - name: flight_no
          in: path
          required: true
          description: Unique Flight Identifier
          schema:
            type : string
          example: "edcc03a4-7f4e-40d1-898d-bf84a266f1b9"

      responses:
        '200':    # success response
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  Cabin:
                    type: array
                    items:
                      type: object
                      properties:
                        firstRow:
                          type: number
                          example: 8
                        lastRow:
                          type: number
                          example: 23
                        Wing:
                          type: object
                          properties:
                            firstRow:
                              type: number
                              example: 14
                            lastRow:
                              type: number
                              example: 22
                        CabinClass:
                          type: object
                          properties:
                            CabinType:
                              type: string
                              example: Economy
                        Column:
                          type: array
                          items:
                            type: object
                            properties:
                              Column:
                                type: string
                                example: A
                              Characteristics:
                                type: array
                                example:
                                  - Window
                                items:
                                  type: string
                        Row:
                          type: array
                          items:
                            type: object
                            properties:
                              RowNumber:
                                type: number
                                example: 8
                              Seat:
                                type: array
                                items:
                                  type: object
                                  properties:
                                    premiumInd:
                                      type: boolean
                                      example: false
                                    exitRowInd:
                                      type: boolean
                                      example: false
                                    restrictedReclineInd:
                                      type: boolean
                                      example: false
                                    noInfantInd:
                                      type: boolean
                                      example: false
                                    Number:
                                      type: string
                                      example: A
                                    Facilities:
                                      type: array
                                      items:
                                        type: object
                                        properties:
                                          Detail:
                                            type: object
                                            properties:
                                              content:
                                                type: string
                                                example: LegSpaceSeat

 

 

1.2 예약 마이크로서비스 OAS

https://github.com/implementing-microservices/ms-reservations/blob/master/docs/api.yml

  openapi: 3.0.0
  info:
    title: Seat Reservation System API
    description: |
      API Spec for Fight Management System
    version: 1.0.1
  servers:
    - url: http://api.example.com/v1
      description: Production Server
  paths:
    /reservations:
      get:
        summary: Get Reservations for a flight
        description: |
          Get all reservations for a specific flight
        parameters:
          - name: flight_id
            in: query
            required: true
            schema:
              type: string
        responses:
          '200':    # success response
            description: Successful Response
            content:
              application/json:
                schema:
                  type: array
                  items:
                    type: object
                    properties:
                      seat_no:
                        type: string
                        example: "18F"
                  example:
                    - { seat_no: "18F" }
                    - { seat_no: "18D" }
                    - { seat_no: "15A" }
                    - { seat_no: "15B" }
                    - { seat_no: "7A" }
      put:
        summary: Reserve or cancel a seat
        description: |
          Reserves a seat or removes a seat reservation
        requestBody:
          required: true
          content:
            application/json:
                schema:
                  type: object
                  properties:
                    flight_id:
                      description: Flight's Unique Identifier.
                      type : string
                      example: "edcc03a4-7f4e-40d1-898d-bf84a266f1b9"
                    customer_id:
                      description: Registered Customer's Unique Identifier
                      type : string
                      example: "2e850e2f-f81d-44fd-bef8-3bb5e90791ff"
                    seat_num:
                      description: seat number
                      type: string
                example:
                  flight_id: "edcc03a4-7f4e-40d1-898d-bf84a266f1b9"
                  customer_id: "2e850e2f-f81d-44fd-bef8-3bb5e90791ff"
                  seat_num: "8D"
        responses:
          '200':
            description: |
              Success.
            content:
              application/json:
                schema:
                  type: object
                  properties:
                    status:
                      type: string
                      enum: ["success", "error"]
                      example:
                        "success"
          '403':
            description: seat(s) unavailable. Booking failed.
            content:
              application/json:
                schema:
                  type: object
                  properties:
                    error:
                      type: string
                    description:
                      type: string
                  example:
                    error: "Could not complete reservation"
                    description: "Seat already reserved. Cannot double-book"

 

 

1.3 스웨거(swagger) 에디터로 렌더링 가능

https://editor.swagger.io/

항공 마이크로서비스 OAS와 예약 마이크로서비스 OAS를 스웨그 에디터에 입력하면 API 문서로 렌더링되어 출력되는 것을 확인할 수 있음

 

 

 

2 마이크로서비스에 특성에 맞는 백엔드 데이터 시스템 선택

마이크로서비스 간 독립적인 데이터의 필요성을 강조하기 위해 완전히 다른 백엔드 데이터 시스템을 사용 (항공편 서비스에는 MySQL을, 예약 서비스에는 레디스를 사용)



2.1 GNU make 유틸리티 설치 및 PATH 환경 변수 등록

GNU make 유틸리티 다운로드 및 설치

 

다운로드 후 압축 해제한 GNU make 유틸리티 디렉터리를 PATH 환경변수의 값으로 등록



2.2 예약 서비스의 데이터 모델을 위한 레디스(redis)

예약 시스템에서는 항공편 좌석의 예약 현황을 조회하고 아직 예약되지 않은 좌석이라면 예약할 수 있는 기능을 제공

⇒ 레디스는 이에 적합한 해시 데이터 구조를 제공

⇒ HSETNX 명령으로 신뢰할 수 있는 간단한 방법으로 중복 예약을 방지할 수 있음

 

소스코드 다운로드

c:\msur> git clone https://github.com/implementing-microservices/ms-reservations.git
c:\msur> cd ms-reservations

 

docker-compose.yaml 파일 수정

        … (생략) … 
  ms-reservations-redis:
    container_name: ms-reservations-redis
    image: redis:6-alpine
    restart: always
    command: redis-server /usr/local/etc/redis/redis.conf --requirepass 4n_ins3cure_P4ss
    ### you only need to host-map this port if you have an app (DB GUI Editor?)
    ### on host that needs access to the Redis DB. Otherwise, keep it commented.
    #ports:
    #  - "6379:6379"
    expose:
      - 6379
    volumes:
      - ms_reservations_redis_data:/data
#     - $PWD/redis.conf:/usr/local/etc/redis/redis.conf
      - ./redis.conf:/usr/local/etc/redis/redis.conf
    environment:
      - REDIS_REPLICATION_MODE=master

volumes:
  ms_reservations_redis_data:

 

ms-reservations-redis 컨테이너 실행

C:\msur\ms-reservations> make start		⇐ share path … 승인해줘야 함
docker-compose -p msupandrunning up -d
Creating network "msupandrunning_default" with the default driver
Creating ms-reservations-redis ... done
Creating ms-reservations       ... done

 

ms-reservations-redis 컨테이너에서 redis-cli 실행

C:\msur\ms-reservations> make redis
docker-compose -p msupandrunning exec ms-reservations-redis redis-cli -a 4n_ins3cure_P4ss
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379>

 

flight_id가 40d1-898d-bf84a266f1b9인 항공편에 여러 좌석을 예약하는 예

HSETNX key field value 명령 ⇒ 좌석의 중복 예약을 방지

[참고] https://redis.io/commands/HSETNX

 

field가 존재하지 않는 경우에만 key에 저장된 해시의 field를 value로 설정

key가 존재하지 않으면 해시를 포함하는 새 key를 생성 (field가 이미 있는 경우 이 작업은 효과가 없음)

127.0.0.1:6379> HSETNX flight:40d1-898d-bf84a266f1b9 12B b4cdf96e-a24a-a09a-87fb1c47567c
(integer) 1			⇐ field가 해시의 새 field이고, value가 설정된 경우
127.0.0.1:6379> HSETNX flight:40d1-898d-bf84a266f1b9 12C e0392920-a24a-b6e3-8b4ebcbe7d5c
(integer) 1
127.0.0.1:6379> HSETNX flight:40d1-898d-bf84a266f1b9 11A f4892d9e-a24a-8ed1-2397df0ddba7
(integer) 1
127.0.0.1:6379> HSETNX flight:40d1-898d-bf84a266f1b9 3A 017d40c6-a24b-b6d7-4bb15d04a10b
(integer) 1
127.0.0.1:6379> HSETNX flight:40d1-898d-bf84a266f1b9 3B 0c27f7c8-a24b-9556-fb37c840de89
(integer) 1
127.0.0.1:6379> HSETNX flight:40d1-898d-bf84a266f1b9 22A 0c27f7c8-a24b-9556-fb37c840de89
(integer) 1
127.0.0.1:6379> HSETNX flight:40d1-898d-bf84a266f1b9 22B 24ae6f02-a24b-a149-53d7a72f10c0
(integer) 1

 

이미 예약된 좌석의 중복 예약을 시도

127.0.0.1:6379> HSETNX flight:40d1-898d-bf84a266f1b9 12C 083a6fc2-a24d-889b-6fc480858a38
(integer) 0			⇐ field가 이미 해시에 있고 작업이 수행되지 않은 경우

 

특정 항공편에서 예약된 좌석 전체를 조회

127.0.0.1:6379> HKEYS flight:40d1-898d-bf84a266f1b9
1) "12B"
2) "12C"
3) "11A"
4) "3A"
5) "3B"
6) "22A"
7) "22B"

 

특정 항공편에서 예약된 좌석과 예약자(예약번호)를 조회 

127.0.0.1:6379> HGETALL flight:40d1-898d-bf84a266f1b9
 1) "12B"
 2) "b4cdf96e-a24a-a09a-87fb1c47567c"
 3) "12C"
 4) "e0392920-a24a-b6e3-8b4ebcbe7d5c"
 5) "11A"
 6) "f4892d9e-a24a-8ed1-2397df0ddba7"
 7) "3A"
 8) "017d40c6-a24b-b6d7-4bb15d04a10b"
 9) "3B"
10) "0c27f7c8-a24b-9556-fb37c840de89"
11) "22A"
12) "0c27f7c8-a24b-9556-fb37c840de89"
13) "22B"
14) "24ae6f02-a24b-a149-53d7a72f10c0"

 

컨테이너 종료

127.0.0.1:6379> exit

C:\msur\ms-reservations> make stop
docker-compose -p msupandrunning down
Stopping ms-reservations       ... done
Stopping ms-reservations-redis ... done
Removing ms-reservations       ... done
Removing ms-reservations-redis ... done
Removing network msupandrunning_default

 

디렉터리 삭제 ⇒ (여기에서는 레디스 동작을 확인하기 위해 임시로 사용) 뒤에서 예약 마이크로서비스 생성 시 다시 만들게 됨

c:\msur> del /s /f /q ms-reservations
c:\msur> rmdir /s /q ms-reservations

 

 

2.3 항공편 마이크로서비스의 데이터 모델을 위한 MySQL

항공편 마이크로서비스에서는 OAS에서 정의한 것과 같이 복잡한 JSON 객체를 이용해서 좌석 배치도를 표현 → JSON 객체를 다루기 위해서는 레디스 보다는 MySQL이 더 적합 (MySQL 5.7.8 부터 JSON 데이터 유형에 대한 강력한 기본 지원을 제공)

 

seat_maps, flights 테이블을 생성하고 seat_maps 테이블에 JSON 형식의 데이터를 추가하고 조회하는 예

CREATE TABLE `seat_maps` (
 `flight_no` varchar(10) NOT NULL,
 `seat_map` json NULL,
 `origin_code` varchar(10) NULL,
 `destination_code` varchar(10) NULL,
 PRIMARY KEY(`flight_no`)
);

CREATE TABLE `flights` (
 `flight_id` varchar(36) NOT NULL,
 `flight_no` varchar(10) NULL,
 `flight_date` datetime(0) NULL,
 PRIMARY KEY (`flight_id`),
 INDEX `idx_flight_date`(`flight_no`, `flight_date`),
 FOREIGN KEY(flight_no)
 REFERENCES seat_maps(flight_no)
);

INSERT INTO `seat_maps`(`flight_no`, `seat_map`, `origin_code`, `destination_code`) 
VALUES ('AA2532', '{"Cabin":[{"Row":[{"Seat":[{"Number":"A","Facilities":[{"Detail":{"content":"LegSpaceSeat"}}], "exitRowInd":false,"premiumInd":false,"noInfantInd":false,"restrictedReclineInd":false}],"RowNumber":8}],"Wing":{"lastRow":22,"firstRow":14},"Column":[{"Column":"A","Characteristics":["Window"]}],"lastRow":23,"firstRow":8,"CabinClass":{"CabinType":"Economy"}}]}', 'LAX', 'DCA');


select seat_map->>"$.Cabin[0].firstRow" from seat_maps;

 

728x90
반응형

댓글