AWS 서비스 구조

Lambda 로직

재생 데이터 INSERT

전송받은 데이터 그대로 play_data_vod 테이블에 저장

uuid별로 데이터를 계속해서 갱신하여 테이블에는 가장 최신 재생 내역이 저장된다.

play_data_vod 테이블 DynamoDB Stream 동작

DynamoDB의 스트림 기능을 활성화 하면 재생 로그가 계속해서 저장된다. play_data_vod에 INSERT/MODIFY 동작이 발생할 때 Lambda가 실행된다. Batch 사이즈는 1000개로 설정되어있다. Batch에 들어온 이벤트들(INSERT, MODIFY)로 통계 테이블에 INSERT 또는 UPDATE 중 필요한 작업을 구분하여 내부 데이터 구조에 일차적으로 저장하여 각 channel별 object들의 새로운 통계 정보를 갱신한다. 내부 데이터 구조에 저장하는 것은 DB 접근을 최소화하기 위함이다.

이벤트가 입력되면 재생한 미디어의 정보가 테이블에 존재하는지 여부를 확인해야 한다. 이후 INSERT를 할 지 UPDATE를 할 지 여기서 결정되기 때문이다. 내부 데이터 구조에 임시 저장을 하고 있기 때문에 데이터 구조에 해당 객체 재생 데이터가 있는지도 검사해야 한다.

Stream Lambda function logic

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/68a35d46-fe32-4876-aba5-37d0981dfbc6/IMG_0163.jpg

전체 미디어의 20%, 40%, 60%… 로 section별 재생 여부를 계산하기 위해 DynamoDB Stream 옵션에서 데이터 MODIFY 이벤트시에 갱신 이전 데이터(OldImage)와 새로운 데이터(NewImage)를 모두 가져오도록 했다. 이를 사용해 OldImage의 재생값과 NewImage의 재생값이 다른 경우 통계 테이블의 count 수를 올리는 방식이다.

const SECTION = ["play20", "play40", "play60", "play80", "play100"];

SECTION.forEach((section) => {
  console.log(section, "DONE");
  if (oldVal[section] !== newVal[section]) {
    console.log("SECTION CHANGED", oldVal[section], newVal[section]);
    if (ch_object in dataRefined)
      dataRefined[ch_object]["newVal"][section] += 1;
    else {
      dataRefined[ch_object] = {
        type: 1,
        date: date,
        newVal: { play20: 0, play40: 0, play60: 0, play80: 0, play100: 0 },
      };
      dataRefined[ch_object]["newVal"][section] = 1;
    }
  }
});

통계의 종류가 시간별 / 날짜별로 두 가지가 있기 때문에 통계 데이터 저장 테이블도 두 개로 나누었다. 여러 경우의 수를 고려해 코드를 작성하고 디버깅했다. 특히 DB 접근 횟수를 줄이기 위해 고민을 많이했는데, 예를 들어 시간 별 통계 테이블에 해당 channel-object 개체 재생 정보가 없는 경우, 이 object에 대한 데이터는 날짜 별 테이블에도 존재하지 않는 것이 분명하다. 따라서 직관적으로 생각했을 때 두 번 해야 하는 테이블 조회를, 시간 별 통계 테이블 조회 한 번에 작업할 수 있도록 하였다.

play_data_get 데이터 조회 logic

  1. 요청된 각 channel에서 조회 기간에 재생된 미디어가 있는 object 들을 골라낸다.

    const queryResult = await ddb.query(queryParams).promise();
    console.log(queryResult);
    
    if (queryResult.Count !== 0) {
      const objSet = new Set();
      queryResult.Items.forEach((item) => objSet.add(item));
      return objSet;
    }
    return;
    
  2. 각 object들이 기간내 재생된 횟수를 구한다. (objectId를 기본키로 하는 인덱스 사용)

  3. 재생 횟수에 따라 channelId-objectId를 배열에 넣고 오름차순 정렬한다.