티스토리 뷰
사전 지식
사용기술
- 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
개발 사전 체크
기획 내용의 검토
- Timeline 시나리오 설계 및 구축
- 특정 유저가 다른 유저 혹은 인플루언서를 팔로우할 경우 모아보기를 지원해야 함
- Only DB Query로 구축은 지양하고, 확장성 및 성능을 고려한 설계 필요(DB로 설계했을 때 방안도 고려)
- AWS ELK를 활용한 검색 시나리오 설계 및 구축
- 사용자가 작성한 글/크롤링한 데이터/커뮤니티 검색 지원
해결하고자 하는 문제
- 확장성 및 성능을 고려한 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 토픽 데이터 저장(스트림 프로세싱 단순화)
- YouTube
파이프라인(Kafka 클러스터)
- EC2로 Kafka 클러스터(+Zookeeper) 파이프라인 구축
- Consumer가 broker로 부터 메시지를 pull 하는 방식
- Consumer가 처리 가능할 때 메시지를 가져와 처리
- 자원 효율적 사용
- 메시지를 disk에 저장 하기 때문에 이미 처리한 큐도, 다시 가져와서 처리가 가능 함
- Consumer 장애 시에도 데이터 누락 없이 처리 할 수 있음
- 메시지를 쌓아 두었다가 한번에 처리하는 배치 처리도 가능
- Consumer가 처리 가능할 때 메시지를 가져와 처리
- 클러스터로 장애 내성을 갖음
- Consumer가 broker로 부터 메시지를 pull 하는 방식
- 데이터 규모에 따라서 클러스터 규모 산정
- 최소 설정은 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 서버
- 비동기 태스크 큐 처리
- 검색 키워드 저장
- 검색 결과 클릭 카운팅
- 검색 결과 캐시 생성
- 신규 포스트 데이터 검색 시스템에 저장
모니터링 시스템
- 처리량 모니터링
- 부하 발생 하거나, 유입량 보다 처리량이 낮으면 노티
- 스케일 아웃 처리
- 에러 모니터링
- 에러 발생시 노티
댓글
warpmemory
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
페이지
TAG
- 이슈처리
- RESTful
- Web
- apache
- Ansible
- limits
- 명령어
- MariaDB
- code
- deview
- 외부링크
- Python
- error
- monitoring
- mysql
- engineering
- 번역
- 코드
- command
- File
- client
- Module
- Windows
- httpd
- configuration
- check
- 예제
- PowerShell
- Linux
- example
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함