Extra Form
PHP PHP 7.2
CMS Rhymix 2.x

최근 라이믹스 친구 기능을 구독기능으로 활용을 하고 있는데요.

 

관심이 있는 것 중 하나가 

 

구독자(친구 등록한 회원)들에게 새글 작성시 알림센터 알림을 보내는 기능입니다.

 

그런데 한가지 글 작성 직후 (AfterInsertDocument) 에 알림센터 알림을 발생하는 코드를 진행하면 

친구가 굉장히 많은 경우까지 생각한다면 이 작업은 글 작성 이후에 별도로 실행해 주는게 성능면에서 좋아보여서 생각해 봤는데요. 글 작성 등록 후 오래 기다려야하는 문제가 발생할 수 있기 때문인데요.

 

crontab에 등록하여 별도 작동하는 방법도 있겠지만 이것 말고 

 

AfterInsertDocument 시점에서 새글의 정보와 새글 작성자의 회원번호 정도만 어떤 비동기로 작동하는 곳에 전달하여 해당 하는 곳에서 전달받은 정보로 알림센터 알림을 생성하는(반복문을 사용한)  작업을 하게 하는 방법이 있다면 좋겠다는 생각을 해봤습니다.

 

방법이 있나요?

  • profile
    curl 로 알림보내는 기능을 담은 외부파일을 비동기로 실행하면 어떨까? 하는 상상까지 해봤습니다.
  • ?

    메세지 큐를 사용해서 오래 걸리는 작업은 다른 프로세스한테 줘버리세요.
    물론, 오래걸리는 작업을 처리하는 프로그램(php, nodejs, 파이썬 등)은 직접 작성해야합니다.

  • ? profile
    말씀 감사합니다. 제가 이해하기는 어려운 부분이라 더 공부해보겠습니다.
  • profile

    글 작성시 알림을 보낼 사람과 내용만 저장해 둔뒤, 크론이나 기타 다른 방법을 이용해 별개로 실제 알림을 발송하는 방법이 유일한 방법입니다. 즉,

    1. 알림 내용 임시 저장용 테이블 생성
    2. 알림 생성 부분을 임시 저장용 테이블에 알림 내용을 저장하도록 수정
    3. 주기적으로 크론을 통해 알림 생성 스크립트를 실행해서 임시 저장용 테이블의 내용대로 알림 생성

    이런식으로 구현할수 있습니다. 다만 크론 실행 주기에 따라 알림이 바로바로 생기지 않을수 있는점은 단점이라 볼수 있습니다(5분 간격 실행시 알림이 가기까지 5분 소요될수도) 또한 중복실행 방지 처리를 하지 않으면 알림이 중복 생성될수도 있습니다.

    실시간으로 구현하기 위해서는 윗분 댓글에도 있는 메세지 큐 서버(beanstalkd 등) 이용하시면 되나 이경우 구현이 조금 까다로운 편입니다.(원리를 알면 코드 자체는 어렵지 않습니다만 모르신다면 힘드실수 있습니다)

  • profile profile

    지금 제가 가닥을 잡은건

    1.외부파일로 알림을 보낼 코드를 작성하여 만듭니다.
    2.글 작성 완료 직후 이 외부파일을 비동기로 실행한다.

    이것을 고려하고 있습니다. 이게 불가능한가요?

    curl 로 기본 정보만 담아서 외부파일을 실행하면 작동할 것 같아서요. 우선 알림 발송 성공유무나 로그는 생각 안하고 기본 작동만 하게 하려고 하고 있어요.

  • profile profile
    exec("알림보내는php파일.php >/dev/null 2>&1 &");

    이런식으로 하면 불가능한건 아닙니다만 권장되지는 않습니다.
  • profile profile
    제가 당장 구현할 수 있는 방법 중 우선 순위로 두고 있는 것인데 권장되지 않는다고 하시는 이유를 좀 알 수 있을까요?

    curl 을 사용할 생각입니다.
  • profile profile
    윗분 댓글에도 있지만 메세지 큐를 쓰는게 정석이기 때문입니다. 훨씬 편리할 뿐만 아니라 실패시 재시도 처리나 오류 기록도 간편하죠. 마치 서울에서 부산까지 걸어서 갈수는 있지만 그렇게 하지 않고 고속버스나 KTX를 이용하는 것을 생각해 보시면 될것 같습니다.
  • profile profile
    네. 그럼 일단 제가 할 수 있는 단계에서 가능한 부분이니 먼저 시도해보겠습니다. 나중에 더 좋은 방법은 제가 역량이 좀더 커진 후 시도해 보는거로 하구요.
  • profile

    현실적으로는 curl을 상당히 많이 사용합니다만, 몇 가지 단점이 있으므로 주의하셔야 합니다.

     

    1. curl은 기본적으로 웹 브라우저를 흉내내는 것이므로, 웹에서 요청한 것과 마찬가지로 타임아웃이 적용됩니다. 몇 초간 기다리는 불편을 해소하는 데는 도움이 되겠지만, 30초가 넘어가면 이것도 끊긴다는 뜻이지요. 처음 만들 때는 괜찮았는데 어느 날 갑자기 알림이 랜덤으로 몇 개씩 누락되는 골치아픈 상황이 발생할 수 있습니다.

     

    2. 서버단에서 느끼는 부하도 동접수가 하나 더 올라간 것과 같은 효과입니다. 만약 5명이 글을 쓴다면 curl도 5개 실행되어서 동접수는 10명이 됩니다. curl에 많이 의존하는 사이트는 이 문제 때문에 PHP-FPM 튜닝값마저 달라지곤 합니다.

     

    3. 특정 모듈의 특정 액션을 호출하는 방식이 아니라 그냥 php 파일을 따로 만들어 쓰려는 유혹이 무척 강합니다. 빠르고 가볍게 만든다는 핑계로 XML 쿼리 같은 것도 모두 버리고 날코딩하는 분이 많습니다. 코어의 안전장치를 모두 무력화시킨 셈이니, 보안취약점이나 퍼미션 문제 등이 발생할 수 있습니다. curl로 쓰려고 만들어 놓은 파일 경로가 우연히 노출되어서 외부인이 위험한 값들을 막 전달한다고 생각해 보세요.

     

    즉, 안전하게 잘 만든다면 상관없지만, 잘 만드는 경우를 거의 보지 못했기에 주의를 요합니다. 그래도 시도해 보시겠다면 화이팅 해드립니다.^^

  • profile profile

    1. 네. 저희 사이트의 외부파일을 비동기로 호출하는 거라 문제는 없을 것 같습니다. 크론탭으로 실행하는 경우도 보았으나 크론탭 보다는 이게 더 좋아보이구요. 알림센터에 알림을 넣는 php 동작은 외부 푸시연동과 달리 빠른 시간에 동작이 완료될 것 같아 30초 이내 작동문제도 안될 것 같았습니다.

     

    글 작성시 처리하게 해도 어차피 30초 문제는 동일하고 글 작성 완료를 기다리는 시간이 과다해지니까요.

    2.글을 동시에 쓴다해도 크게 문제가 되지는 않을 것 같습니다. 특성상 동시에 다 한꺼번에 글을 쓴다기보다는 대부분 뷰 접속이고 일부가 각각 글을 쓰기 때문이기도 하고 curl시 접속되는건 문제 안될 것 같습니다.

    글쓴이의 친구만 db에서 가져와(XML 쿼리) 해당 회원에게 알림센터 알림을 발생시키는 코드라 접속시 필수정보가 정확하게 있는 경우만 작동하게 할 것이라 보안이나 안전문제는 크게 발생하지 않을 것 같습니다.

  • profile

    서버단의 부하와 같은 부분은 뇌 바깥으로 던져두고,

    '등록된 친구에게 알림을 보내는데, 친구의 등록수가 많아 글 작성 이후 대기시간이 길어짐' 의 문제만을 해결한다고 생각하면

    아래 방법도 있습니다.

     

    $cl = ob_get_length();
    header('Content-Length: ' . $cl);
    header('Connection: close');
    
    ob_end_flush();
    ob_flush();
    flush();
    session_write_close();
    
    // 친구들에게 알림을 발송하는 코드

     

     

     

    1번 라인은 지금까지 출력하기 위해 버퍼(라는 일종의 저장소)에 저장해 둔 출력데이터의 길이를 측정하는 코드입니다.

    원래 버퍼에 저장하려면 출력하기 전에 ob_start() 라는 함수를 실행해야 하지만,

    라이믹스 기준 classes/Context/Context.class.php 파일에 선언된 init 함수(index.php 파일에서 호출됨)에서 이미 실행을 해 주었기 떄문에, 라이믹스 환경에서는 신경쓰지 않아도 됩니다.

     

    2~3번 라인은 브라우저에게

    '이 숫자가 우리가 출력할 길이야. 이만큼만 출력하고 이제 너랑 통신 끊을거야.' 라는 HTTP 헤더를 추가하는 코드입니다.

     

    5~7 라인은 버퍼에 보관해둔 출력물을 실제로 브라우저에 보내주고, 버퍼를 비우고, 버퍼를 닫아버리는 코드입니다.

    2~3번 라인에서 출력길이를 제한하고, 연결을 닫아버렸으니, 이제 무언가 작업을 해도 브라우저에 내용을 전달하지 않습니다.

     

    8번 라인은 열어져있던 세션을 닫아주는 코드입니다.

    세션이 열려있으면 이상하게 맥을 못추고 계속 어기적댑니다.

     

    그 다음부터는 원하는 작업을 마음껏 하셔도!

    이미 브라우저는 연결을 닫고 서버와 통신할 생각을 하지 않기 떄문에 글 작성자가 글 작성 후 대기시간에 골머리를 앓지 않을겁니다.

    물론, 브라우저에서 발발된 요청인만큼 time_limit 이 걸릴 수 있습니다. 보통 30초 정도로 세팅되어 있겠지요.

    깔끔하게(???) set_time_limit(0); 으로 시간제한을 푸시고 마음껏 즐기시면 되겠습니다.

  • profile profile
    오 따로 파일로 분리해서 비동기로 파일 실행할 필요 없이 코드를 작성할수 있군요. 다음에 시도해봐야겠습니다.