Skip to content

알림 시스템 설계 #33

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
junha-ahn opened this issue Jul 16, 2023 · 9 comments
Closed

알림 시스템 설계 #33

junha-ahn opened this issue Jul 16, 2023 · 9 comments
Assignees
Labels
documentation Improvements or additions to documentation major Major topic question Further information is requested

Comments

@junha-ahn
Copy link
Member

junha-ahn commented Jul 16, 2023

Description

북마크한 공연이 아직 예매 시작 전일때, 시작 시간에 X일전에 알림을 사용자에게 보내주세요.

To do

  • 관련 자료 조사
  • 시스템 설계도, 흐름도 등 전반적인 Diagram 설계
    • 러프한 손 다이어그램부터 프로그램을 사용한 다이어그램
  • 단계별 설계
    • 가장 간단한 설계 => 문제상황 => 확장(해결방법) => 새로운 문제 상황 => 새로운 확장(해결방법) => ...
  • 학습내용/레퍼런스/Diagram 정리를 댓글로
  • 최종 단계 Mock 서버 고려
    • 실제 Email/Kakao 전송등을 비용의 이유로 Interface만 구현해야할 가능성 존재
    • 다만 그럴때 어디까지, 어떻게 트래픽 시나리오를 구성할 수 있을지 고려해주세요
    • 가짜 전송 서버
      • X초후 성공/실패 응답
      • 10% 실패 (재시도 프로세스 필요)
      • 만약 해당 서버가 단일 장애 지점이 된다면, 외부 서비스에 대한 의존성을 어떻게 관리할 수 있는지 테스트할 수 있다 (해당 서버는 대체로 성능을 증가시키지 않는다)
@junha-ahn junha-ahn added the question Further information is requested label Jul 16, 2023
@junha-ahn junha-ahn moved this to Todo in Kanban backend Jul 16, 2023
@junha-ahn junha-ahn added the documentation Improvements or additions to documentation label Jul 17, 2023
@junha-ahn junha-ahn moved this from Todo to In Progress in Kanban backend Jul 21, 2023
@ParkJeongseop
Copy link
Collaborator

ParkJeongseop commented Jul 25, 2023

ERD

알림시스템

단계별 설계

1단계

image
알림 시스템을 구현하기위한 최소 설계

  • WAS, Batch에서 사용자 알림거부 여부, 발송연락처 조회해서 메시지 내용생성하여 메시지큐로 추가
  • 웹 알림 보관함에는 바로 메시시 생성 저장
  • 큐에 들어간 요청은 워커가 계속 돌아가며 처리
  • 발송실패시 다시 큐에 삽입
  • 재시도 횟수 초과시 요청 폐기
  • 실시간요청 알림을 우선 처리

2,3단계

  • 메시지 처리량이 늘어나면 큐와 워커를 추가
    Untitled-2023-07-25-22322
    Untitled-2023-07-25-22323

메시지큐 데이터

{
    "type": "kakaotalk",
    "phone_number": "01012345678",
    "message": "프동프동 컨퍼런스가 결제되었습니다."
    "retry": 0
}

Mock 서버 정의

  • 외부 시스템은 Response Time, 서버 멈춤등 우리의 제어영역에 없기에 이와 같은 상황들을 고려하도록 랜덤 Response Time, 고의 중단 등 가정하며 테스트

@junha-ahn
Copy link
Member Author

junha-ahn commented Jul 27, 2023

  1. 알림 전송 성공/실패 여부 및 재전송 로직은 어떻게 구현하시나요. 한마디로 알림 상태는 어떻게 관리됩니까?
  2. 또한 메세지 큐에는 어떠한 정보를 어떻게 담을건지에 대한 내용도 부탁드립니다. 러프하게 json-object 형식으로 부탁드립니다. (실제로 필요한 모든 정보를 다 담을것인지, 아니면 worker에서 추가 DB조회가 있는지 여부 / 그리고 noti 테이블에는 어떤 채널로 전송되는 noti인지는 없는 것 같습니다. 그냥 생성 후 queue에 type 넣어서 각 worker로 보내기 때문인가요)
  3. 알림내역 테이블은 위 설계 중 어디서 INSERT 되는건가요? sent_at의 값은 언제 세팅됩니까? worker에서 세팅하는건가요? 그게 아니라면 sent_at이라는 값은 실제 전송 시간이 아닌것 같습니다. (created_at에 가까운것 같네요)
  4. CHAR보다 VARCHAR를 선호합니다. (CHAR VS VARCHAR)
  5. 메세지에 BLOB를 써야하는 이유가 있나요?
  6. OPTINFO가 어떤 뜻입니까? 이름이 명확하지 않은 것 같습니다. (추가로 수신여부:OPT또한 명확하지 않은 이름같습니다. 개인적으로는 is_xxx, has_xxx, should_xxx 등의 명명 규칙을 사용하곤 했습니다 - 참고)
  7. updated_at 이 좀 더 좋을것 같습니다 - 설정 변경 일시
  8. 알림 타입의 경우는 TINYINT(1)로 나타낼 수 없을 것같고, 외부 테이블에서 외래키로 받는게 좋을 것 같네요.
  9. 또한 모든 테이블은 PK(=ID)를 명시적으로 선언해주십시요

명시적인 PK가 없는 경우 InnoDB는 그 값을 생성합니다. 비록 사용자에게는 노출되지 않는다 하더라도. FROM

  1. (8)번 device_type + user_id 조합에 따라 나오는 고민 - Surrogate Key vs Natural Key 에 대해서 고려 후 설계/의견공유 부탁드립니다. 참고

  2. 최종 단계 Mock 서버 고려 => Mock 서버 정의

    • 위 댓글, 이렇게 이름 변경해주세요 1단계 => 2단계 => 최종 단계 이런 느낌 같습니다
  3. 3단계에서 특정 Worker / 또는 Queue에 부하가 심하면 어떤 확장 방법이 있습니까? (물런 4단계 구현은 안할것 같긴하지만 방향성이 궁금합니다)

@junha-ahn
Copy link
Member Author

junha-ahn commented Jul 27, 2023

API workflow등으로 검색해서 나오는 흐름도처럼, 실제 notification의 흐름을 처음부터 끝까지 만들어주는것도 좋을것 같습니다

Twitter Notification 발표를 보고

모두 다 변경할 필요는 없고(특히 당장 중요하지 않은 부분을 구현하는건 낭비라고 보입니다), 그냥 새로운 주제 던져봅니다.

  • 예를들어 가장 처음인 13의 경우 우리가 굳이 noti type을 구현할 필요 없다 봅니다. (알림 시스템을 구현하고 확장한다는 ‘목적’에 맞지 않습니다)
  1. noti type 구분 (계정 알림, 새 글 알림 등등) => type에 따른 알림 허용 여부
  2. 특정 공연(싸이 등등)에 경우 특정시간(오픈 X일전)에 Hot-key 문제를 가짐 - 언제가 Spike일지 ‘예측’ 가능함 (발표에서 Spike 라고 표현)
  3. Priority Queues,로그인 알림, 예매 성공 알림등은 지연되면 안된다.
  4. WEB Notification Timeline은 push 구조가 아니라 pull한다. RDB noti table을 쓰지 않고 캐시를 사용(Long live Cache)

@bohblue2
Copy link
Collaborator

bohblue2 commented Jul 29, 2023

  1. 알림 수신 여부 테이블을 OPTINFO 에서 NOTIFICATION_OPT로 변경하는 것이 어떨까요?
  2. 알림 내역 테이블을 NOTIFICATION 에서 NOTIFICATION_HIST로 변경하는 것이 어떨까요?
  3. 여기 를 참조하면 알림 실패시 워커가 다시 메시지를 retry 카운트를 하나 늘린후 메시지 큐에 넣음으로서 재전송 로직을 만들 수 있을것 같습니다.
  4. 1단계에서 메시지 큐를 둠으로서 SFOP문제를 잘 해결하신 것 같습니다. 워커가 알림 전송 실패시 재전송 로직만 잘 수행하면 무리 없을 것 같습니다.
  5. 2,3단계는 많은 트래픽이 발생했을때 구조인 것 같은데, 메시지 큐가 scale-out 되었을시 Exactly Once 발송 문제가 발생할 수 있을 것 같습니다. 이는 알림 전송의 유실과 알림 중복 전송 간의 트레이드 오프가 발생할 수 있는데 알림 전송의 유실을 막는것에 주안점을 준다면 일정 부분 성능 감소를 감내하고 해당 요구사항을 달성할 수 있을 것 같습니다. Eactly Once를 참조하면 좋습니다. 대용량 메시지 큐의 대표격인 카프카를 사용하면 몇 가지 설정을 통해 Exactly Once 전송을 달성할 수 있어 보입니다.

@junha-ahn
Copy link
Member Author

junha-ahn commented Jul 29, 2023

@bohblue2

  1. OPT 뜻이 무엇인가요? 저는 user_notification_channel/device (또는 noti로 줄여서 표현) 등으로 사용하는게 좋을것 같습니다. 너무 긴 느낌이 있긴하네요 (그래도 user : device/channel 에 대해 N:N 구조니까... 뭐 이름이..)
  2. HIST는 반대합니다. HIST는 보통 DB에서 붙이지 않는게 좋다고 생각합니다 (예를들어 payment가 있고, payment 상태 변화때마다 기록하기 위해서 payment_history 테이블을 만들어 놓는 경우 정도에 사용한다고 생각합니다)
  3. 2,3단계 (자세히 보면) Queue를 Scale up한게 아니라, channel에 따라 큐를 나눈건데 화살표가 겹쳐있는겁니다. batch에서는 비실시간 알림이 push되는거고, webapp에서는 실시간알림(유저비밀번호변경,예약성공 알림등)이 나가는 구조. 그래서 1번과 본질적으로 차이가 없습니다.

@ParkJeongseop
Copy link
Collaborator

ParkJeongseop commented Aug 2, 2023

  1. 알림 전송 성공/실패 여부 및 재전송 로직은 어떻게 구현하시나요. 한마디로 알림 상태는 어떻게 관리됩니까?
    • 내용 추가하였습니다. 메시지 실패시 다시 메시지큐에 재시도 요청을 추가합니다. 이때 count를 포함하여 일정 재시도 횟수까지 시도 후 폐기합니다.
  2. 또한 메세지 큐에는 어떠한 정보를 어떻게 담을건지에 대한 내용도 부탁드립니다. 러프하게 json-object 형식으로 부탁드립니다. (실제로 필요한 모든 정보를 다 담을것인지, 아니면 worker에서 추가 DB조회가 있는지 여부 / 그리고 noti 테이블에는 어떤 채널로 전송되는 noti인지는 없는 것 같습니다. 그냥 생성 후 queue에 type 넣어서 각 worker로 보내기 때문인가요)
    • 메시지요청을 생성하는 WAS, Batch에서 필요한 정보를 생성후 큐에 추가하여 Worker는 DB요청을 없도록 설계하였습니다.
  3. 알림내역 테이블은 위 설계 중 어디서 INSERT 되는건가요? sent_at의 값은 언제 세팅됩니까? worker에서 세팅하는건가요? 그게 아니라면 sent_at이라는 값은 실제 전송 시간이 아닌것 같습니다. (created_at에 가까운것 같네요)
    • 알림 내역 테이블은 웹 알림함 내역으로 테이블 이름을 변경하여 명확하게 변경하였습니다. 이외에 3-party 알림 서비스로 알림 발송한 내역도 따로 DB에 저장해두어야겠습니까?
  4. CHAR보다 VARCHAR를 선호합니다. (CHAR VS VARCHAR)
    • VARCHAR로 변경하였습니다.
  5. 메세지에 BLOB를 써야하는 이유가 있나요?
    • VARCHAR로 변경하였습니다.
  6. OPTINFO가 어떤 뜻입니까? 이름이 명확하지 않은 것 같습니다. (추가로 수신여부:OPT또한 명확하지 않은 이름같습니다. 개인적으로는 is_xxx, has_xxx, should_xxx 등의 명명 규칙을 사용하곤 했습니다 - 참고)
    • opt-in, opt-out을 생각해서 그렇게 지었는데 subscribe로 변경하고 is_subscribing으로 변경하였습니다.
  7. updated_at 이 좀 더 좋을것 같습니다 - 설정 변경 일시
    • updated_at로 변경하였습니다.
  8. 알림 타입의 경우는 TINYINT(1)로 나타낼 수 없을 것같고, 외부 테이블에서 외래키로 받는게 좋을 것 같네요.
    • 알림타입을 저장하는 테이블 생성해서 외래키로 참조하도록 변경하였습니다.
  9. 또한 모든 테이블은 PK(=ID)를 명시적으로 선언해주십시요
    • 변경하였습니다.

명시적인 PK가 없는 경우 InnoDB는 그 값을 생성합니다. 비록 사용자에게는 노출되지 않는다 하더라도. FROM

  1. (8)번 device_type + user_id 조합에 따라 나오는 고민 - Surrogate Key vs Natural Key 에 대해서 고려 후 설계/의견공유 부탁드립니다. 참고
    • 해당 경우에는 두키모두 Surrogate Key 이지만 외래키조합으로 기본키를 설정하는것은 좋지않다고하여 별도 기본키를 구성하는것으로 변경하였습니다.
  2. 최종 단계 Mock 서버 고려 => Mock 서버 정의
    • 변경하였습니다.
  3. 3단계에서 특정 Worker / 또는 Queue에 부하가 심하면 어떤 확장 방법이 있습니까? (물런 4단계 구현은 안할것 같긴하지만 방향성이 궁금합니다)
    • 해당 경우에는 이제 각 부분별로 독립적으로 수행하기때문에 수평적 확장이 용이할것입니다. 각각 Worker 추가, Queue 추가로 해결할 수 있을것같습니다. 이에 어떻게 생각하십니까?
  4. noti type 구분 (계정 알림, 새 글 알림 등등) => type에 따른 알림 허용 여부
    • 작성예정
  5. 특정 공연(싸이 등등)에 경우 특정시간(오픈 X일전)에 Hot-key 문제를 가짐 - 언제가 Spike일지 ‘예측’ 가능함 (발표에서 Spike 라고 표현)
    • 작성예정
  6. Priority Queues,로그인 알림, 예매 성공 알림등은 지연되면 안된다.
    • 실시간 알림을 우선 처리하도록 Priority Queues로 변경하였습니다.
  7. WEB Notification Timeline은 push 구조가 아니라 pull한다. RDB noti table을 쓰지 않고 캐시를 사용(Long live Cache)
    • 작성예정

@junha-ahn
Copy link
Member Author

junha-ahn commented Aug 4, 2023

3. sent_at관련

  • sent_atcreate_at과 동일한 이상, 테이블에 따라 이름을 다르게 구분할 필요는 없을것 같네요. 나중에 send_at이 다른 특정한 시간대를 가르키면 그때 이름을 sent_at으로 새로운 필드로 관리합시다. (대체로 created_at, updated_at을 사용할 것 같습니다)

3. 3-party 알림 서비스로 알림 발송한 내역도 따로 DB에 저장해두어야겠습니까?

  • 아니요. 이건 나중에 알림 전송 log를 파일을 저장하고, 관리(elasticsearch등으로 검색 가능화)한다면 충분히 가능할 문제라고 생각합니다 (web_notification부분도 16번에서 추가 기술)

8. notification_type은 너무 모호한 이름이라고 생각됩니다. (타입이라고 하면 알림 자체의 종류를 의미하는것 같습니다 - 계정관련 알림, 결제 관련 알림 등) 채널 등의 용어가 어떻습니까?

12. worker만 추가한다면 한 큐에 대해 여러 worker가 동시에 읽을때 sent only once를 어떻게 준수할지 고민해야할 것 같고(위 @bohblue2 님이 지적한 Exactly Once 문제 참고) , queue를 추가한다면 server, batch 로직에서 각 queue를 어떻게 잘 분산해서 push할지 고민해야겠네요 (예를들어서 queue가 추가될때마다 로직에 config를 다시 설정해서 서버를 다시 띄우는건 좀 번거롭고...) 일단 이정도에서 논의 마치시죠.

16. 트위터 발표를 보니, web notification 알림을 굳이 RDB로 유지할 필요가 없다고 생각합니다. long live cache를 사용해도 충분히 문제가 없을것 같습니다!

  • 다만 해당 캐시서버는 인메모리에만 데이터를 저장해서 재기동시 데이터가 날라가는게 아니라, 디스크에도 데이터를 저장시켜놔야겠네요. (redis에는 이런 기술이 존재합니다)
  • 또한 expired date가 30일등 장기간이여도(가능한진 모르겠지만) 결국 하나의 채널에서는 반드시 알림이 보내질 필요가 있습니다 (메일 알림은 is_subscribing이 필수이라던가)
  • 예를들어서 휴먼으로 계정폐기처리 알림은 유저가 웹으로는 확인 안할태니, 메일등으로 반드시 전송되어야 합니다
  • retry 10번 이후 폐기되는건 어떠한 경우에 미처리될 수 있습니다. (최소 몇일동안 메일 worker 및 메일 외부 API에 문제가 발생하여도 전송이 보장되어야함)
    • retry는 x시간 사이 간격으로 진행
    • retry 10번 이후 폐기 데이터는 특별히 ... 저장/로깅/관리

@ParkJeongseop
Copy link
Collaborator

ParkJeongseop commented Aug 4, 2023

3. sent_at관련
- create_at으로 변경하였습니다.

8. notification_type은 너무 모호한 이름이라고 생각됩니다. (타입이라고 하면 알림 자체의 종류를 의미하는것 같습니다 - 계정관련 알림, 결제 관련 알림 등) 채널 등의 용어가 어떻습니까?
- 변경하였습니다.

12. worker만 추가한다면 한 큐에 대해 여러 worker가 동시에 읽을때 sent only once를 어떻게 준수할지 고민해야할 것 같고(위 @bohblue2 님이 지적한 Exactly Once 문제 참고) , queue를 추가한다면 server, batch 로직에서 각 queue를 어떻게 잘 분산해서 push할지 고민해야겠네요 (예를들어서 queue가 추가될때마다 로직에 config를 다시 설정해서 서버를 다시 띄우는건 좀 번거롭고...) 일단 이정도에서 논의 마치시죠.

16. 트위터 발표를 보니, web notification 알림을 굳이 RDB로 유지할 필요가 없다고 생각합니다. long live cache를 사용해도 충분히 문제가 없을것 같습니다!

  • 다만 해당 캐시서버는 인메모리에만 데이터를 저장해서 재기동시 데이터가 날라가는게 아니라, 디스크에도 데이터를 저장시켜놔야겠네요. (redis에는 이런 기술이 존재합니다)
  • 또한 expired date가 30일등 장기간이여도(가능한진 모르겠지만) 결국 하나의 채널에서는 반드시 알림이 보내질 필요가 있습니다 (메일 알림은 is_subscribing이 필수이라던가)
  • 예를들어서 휴먼으로 계정폐기처리 알림은 유저가 웹으로는 확인 안할태니, 메일등으로 반드시 전송되어야 합니다
  • retry 10번 이후 폐기되는건 어떠한 경우에 미처리될 수 있습니다. (최소 몇일동안 메일 worker 및 메일 외부 API에 문제가 발생하여도 전송이 보장되어야함)
    • retry는 x시간 사이 간격으로 진행
    • retry 10번 이후 폐기 데이터는 특별히 ... 저장/로깅/관리

@junha-ahn
Copy link
Member Author

설계는 여기서 마치도록 하죠 ! 👍

@github-project-automation github-project-automation bot moved this from In Progress to Done in Kanban backend Aug 7, 2023
@junha-ahn junha-ahn added the major Major topic label Aug 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation major Major topic question Further information is requested
Projects
Status: Done
Development

No branches or pull requests

3 participants