티스토리 뷰

사전 지식

사용기술

  • AWS
    • Elastic Load Balancing(ELB)
    • Elastic Computing(EC2)
    • ElastiCache(Redis Cluster)
    • Elasticsearch(ELK)
    • EC2 Autoscailing
  • Linux
    • CentoOS
  • Nginx
    • UWSGI
  • Python
    • Django
    • Celery
  • MySQL
  • Kafka
  • Storm

개발 사전 체크

기획 내용의 검토

  1. Timeline 시나리오 설계 및 구축
    1. 특정 유저가 다른 유저 혹은 인플루언서를 팔로우할 경우 모아보기를 지원해야 함
    2. Only DB Query로 구축은 지양하고, 확장성 및 성능을 고려한 설계 필요(DB로 설계했을 때 방안도 고려)
  2. AWS ELK를 활용한 검색 시나리오 설계 및 구축
    1. 사용자가 작성한 글/크롤링한 데이터/커뮤니티 검색 지원

해결하고자 하는 문제

  • 확장성 및 성능을 고려한 Timeline 시스템 구축
  • 데이터 크롤링 및 검색 시스템 구축

개발 범위

  • Timeline 시스템
    • 사용자가 post 시 팔로워 timeline에 post 추가
    • Only DB Query 구축 지양, 확장성 및 성능을 만족
      • Redis 클러스터를 이용한 캐시 시스템
  • 검색 시스템
    • 크롤링 시스템
      • URL, Keyword 등 설정에 따른 크롤링
      • 크롤링 사이트, 속도 제한
    • 파이프라인 시스템
      • 데이터 버퍼링
      • 데이터 유실 없어야 하고
      • 장애 내성
    • 스트림 프로세싱
      • 파싱
      • 필터링
      • 인덱싱
    • 검색 시스템
      • 데이터 저장
      • 검색
      • 검색 결과 랭크
    • 통계 시스템
      • 인덱스 통계
      • 검색 통계
    • 캐시 구축
      • 검색 결과 캐시
    • API 구축
      • 검색
      • 검색 결과 랭크
      • post 등록 시 검색 인덱스 저장

주요 프로세스 및 시나리오

시스템 구성 및 프로세스

 

 

핵심 로직

Timeline 시스템

MySQL 구성

  • Relational Database Service(RDS)가 EC2 기반으로 서비스됨
  • 비용 측면에서 RDS 사용하지 않고, EC2에 직접 DBMS 구축해서 사용해도 됨
  • DB 이중화 및 주기적인 백업 시스템 필수
  • 멀티 마스터 구조 또는 Master - Slaves 구성인 경우 라이브러리 단에서  Read/Write 구분하여 사용
  • 데이터가 많아지면 데이터 베이스 샤딩/파티셔닝 고려
  • 운영 이슈가 심각해지면 RDS로 이전 고려

MySQL 스키마

CREATE TABLE `user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `email` varchar(256),
  `name` varchar(256),
  `influencer` char(1) DEFAULT 'f',
  `created_at` datetime DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  UNIQUE KEY `IDX_user_email` (`email`),
  KEY `IDX_user_name` (`name`),
  KEY `IDX_user_influencer` (`influencer`),
  KEY `IDX_user_created_at` (`created_at`)
) ENGINE=INNODB DEFAULT CHARSET='utf8';
CREATE TABLE `follower` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(10) unsigned,
  `follower_user_id` int(10) unsigned,
  `created_at` datetime DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  KEY `IDX_follower_user_id` (`user_id`),
  KEY `IDX_follower_created_at` (`created_at`),
  FOREIGN KEY (`user_id`) 
  REFERENCES user(`id`) ON UPDATE CASCADE ON DELETE RESTRICT
) ENGINE=INNODB DEFAULT CHARSET='utf8';
CREATE TABLE `post` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(10) unsigned NOT NULL,
  `contents` text NOT NULL,
  `tags` text,
  `locale` varchar(256) NOT NULL DEFAULT '',
  `created_at` datetime DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  KEY `IDX_post_user_id` (`user_id`),
  KEY `IDX_post_locale` (`locale`),  
  KEY `IDX_post_created_at` (`created_at`),
  FOREIGN KEY (`user_id`) 
  REFERENCES user(`id`) ON UPDATE CASCADE ON DELETE RESTRICT
) ENGINE=INNODB DEFAULT CHARSET='utf8';

MySQL 타임라인 조회

  • 사용자의 팔로워가 많아지면 많아질수록 부하 문제 발생
SELECT
    *
FROM
    post
WHERE
    user_id in (
        SELECT
            user_id
        FROM
            follower
        WHERE
            follower_user_id = {user_id}
    )
    OR user_id = {user_id}
ORDER BY created_at DESC LIMIT 20;

MySQL 사용자가 팔로우하는 인플루언서 조회

SELECT
    u.id, u.influencer
FROM
    follower AS f JOIN user AS u ON u.id=f.user_id
WHERE
    f.follower_user_id={user_id} AND u.influencer='t';

Redis 스키마

  • 키 : 벨류
USER_{user_id}_INFLUENCERS : Sets(1, 3, 5, 7)
USER_{user_id}_FOLLOWINGS : Sets(2, 4, 6, 8)
USER_{user_id}_POSTS : Lists[1, 2, 3, 7, 8, 9]
POST_{post_id} : Strings '{
    "user_id": 1,
    "user_name": "사용자1",
    "contents": "포스트1",
    "created_at": "2020-07-02 10:09:10"
}'

Redis 타임라인 조회

  • Redis 클러스터에 액티브(2주 안에 접속한) 사용자에 대한 타임라인을 미리 생성 저장하여 서비스
    • 캐시가 없는 경우에는 MySQL에서 가져와서, 캐시 생성
    • ttl 시간을 2주로 설정, 해당 키 접근 시 마다 ttl 시간이 2주가 되도록 설정
  • 인플루언서의 post가 아닌 경우는, post 등록 즉시 팔로워들의 POSTS 캐시에 바로 추가(Push 방식)
  • 인플루언서의 post인 경우는, 팔로워가 접속했을 때, 팔로워의 POSTS 캐시에 인플루언서 포스트를 가져와 병합(Pull 방식)
  • MySQL과 최종 정합성 고려

API 서버

  • EC2로 구축
    • Nginx : 웹 서버
    • uWSGI(Web Server Gateway Interface) : Nginx서버와 Python 애플리케이션 간 통신 인터페이스 모듈
    • Django REST framework(DRF) : Django RESTful 프레임워크
    • REST Swagger : API 문서 자동화
  • Amazon EC2 Autoscailing 사용하여, 서버 부하에 대응
  • RESTful 조건에 만족하도록 개발
  • GET /api/v1/posts
    • user_id
  • POST /api/v1/posts
    • user_id
    • contents
    • tags
    • locale

Celery 서버

  • 비동기 태스크 큐로 post가 들어왔을 때, Redis 클러스터에 Timeline Cache 생성

검색 시스템

수집(Crawler)

  • 검색 대상 URL 및 검색 키워드 설정에 따라 데이터 수집
    • 수집 대상 설정 가져오는 기능
  • crawler 속도 제한 기능 필수
  • robots.txt 확인하여, crawler 제한된 사이트 제외
  • 사이트 도메인별로 Kafka 토픽 데이터 저장(스트림 프로세싱 단순화)
    • Twitter
    • Facebook
    • YouTube

파이프라인(Kafka 클러스터)

  • EC2로 Kafka 클러스터(+Zookeeper) 파이프라인 구축
    • Consumer가 broker로 부터 메시지를 pull 하는 방식
      • Consumer가 처리 가능할 때 메시지를 가져와 처리
        • 자원 효율적 사용
      • 메시지를 disk에 저장 하기 때문에 이미 처리한 큐도, 다시 가져와서 처리가 가능 함
        • Consumer 장애 시에도 데이터 누락 없이 처리 할 수 있음
      • 메시지를 쌓아 두었다가 한번에 처리하는 배치 처리도 가능
    • 클러스터로 장애 내성을 갖음
  • 데이터 규모에 따라서 클러스터 규모 산정
    • 최소 설정은 3개 클러스터에 복제 1개 이상
  • 수집 데이터 보관 기간 설정(log.retention.hours=72)
    • 수집 용량 및 스트림 스로세싱 시스템 장애등을 고려해서 조정

스트림 프로세싱(Storm 클러스터)

  • EC로 Storm 클러스터(+Zookeeper) 스트림 프로세싱 구성
    • 분산 처리 프레임워크로 사용
  • 파이프라인으로 들어온 데이터 가공
    • 필터링
      • 중복 데이터 제거
    • 파싱
      • 도메인 및 데이터 타입별로 데이터 파싱
    • 필터링
      • 중복 데이터 제거
    • 인덱싱/태깅
      • 인덱스 생성
    • 메타데이터 생성
      • 날자
      • 지역

검색 시스템(Elasticsearch 클러스터)

  • 스트림 프로세싱으로 가공된 검색 데이터 저장
    • url
    • title
    • summary
    • content_type
    • created_at
    • locale
    • tags
    • click_count
  • 검색 정보 저장
    • keyword
    • locale
    • created_at
  • Query 기능

통계 시스템(Kibana)

  • 인덱스 통계 데이터 제공 및 시각화

캐시 시스템(Redis 클러스터)

  • 검색 결과를 캐시

API 서버

  • Timeline API 서버 구성 사용

Celery 서버

  • 비동기 태스크 큐 처리
    • 검색 키워드 저장
    • 검색 결과 클릭 카운팅
    • 검색 결과 캐시 생성
    • 신규 포스트 데이터 검색 시스템에 저장

모니터링 시스템

  • 처리량 모니터링
    • 부하 발생 하거나, 유입량 보다 처리량이 낮으면 노티
    • 스케일 아웃 처리
  • 에러 모니터링
    • 에러 발생시 노티

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
페이지
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함