Estou no início da criação de um sistema de notificação no estilo do Facebook para nossa página (tipo de jogo social) e agora estou pesquisando qual seria a melhor maneira de projetar esse sistema. Não estou interessado em enviar notificações ao usuário ou algo assim (por enquanto, até mesmo). Estou pesquisando como criar o sistema no servidor (como armazenar notificações, onde armazená-las, como buscá-las, etc ...).
Então ... alguns requisitos que temos:
- nos horários de pico, temos cerca de um mil usuários simultâneos conectados (e muitos outros convidados, mas eles não são importantes aqui, pois não terão notificações) que gerarão muitos eventos
- haverá diferentes tipos de notificações (o usuário A adicionou você como amigo, o usuário B comentou seu perfil, o usuário C curtiu sua imagem, o usuário D venceu você no jogo X, ...)
- a maioria dos eventos gera 1 notificação para 1 usuário (o usuário X gostou da sua imagem), mas haverá casos em que um evento gerará muitas notificações (é o aniversário do usuário Y, por exemplo)
- as notificações devem ser agrupadas; se, por exemplo, quatro usuários diferentes, como uma imagem, o proprietário dessa imagem receber uma notificação informando que quatro usuários gostaram da imagem e não quatro notificações separadas (assim como o FB)
OK, então o que eu estava pensando é que eu deveria criar algum tipo de fila para armazenar eventos quando eles acontecerem. Então, eu teria um trabalho em segundo plano ( gearman ?) Que examinaria essa fila e geraria notificações com base nesses eventos. Esse trabalho armazenaria notificações no banco de dados para cada usuário (portanto, se um evento afetar 10 usuários, haveria 10 notificações separadas). Então, quando o usuário abria uma página com a lista de notificações, eu lia todas as notificações para ele (pensamos em limitar isso a 100 notificações mais recentes), agrupá-las e finalmente exibi-las.
Coisas que me preocupam com essa abordagem:
- complexo como o inferno :)
- é o banco de dados com o melhor armazenamento aqui (estamos usando MySQL) ou devo usar outra coisa (redis também parece ser um bom ajuste)
- o que devo armazenar como notificação? ID do usuário, ID do usuário que iniciou o evento, tipo de evento (para que eu possa agrupá-los e exibir o texto apropriado), mas meio que não sei como armazenar os dados reais da notificação (por exemplo, URL e título da imagem que foi gostado). Devo apenas "assar" essas informações ao gerar a notificação ou armazenar o ID do registro (imagem, perfil, ...) afetado e puxar as informações para fora do banco de dados ao exibir a notificação.
- o desempenho deve ser bom aqui, mesmo que eu precise processar 100 notificações em tempo real ao exibir a página de notificações
- possível problema de desempenho em cada solicitação, porque eu precisaria exibir o número de notificações não lidas para o usuário (o que poderia ser um problema por si só, pois agruparia as notificações). Isso poderia ser evitado, se eu gerasse a exibição de notificações (onde elas estão agrupadas) em segundo plano e não em tempo real
Então, o que você acha da minha solução proposta e das minhas preocupações? Por favor, comente se você acha que devo mencionar qualquer outra coisa que seja relevante aqui.
Ah, estamos usando PHP para nossa página, mas acho que não deve ser um grande fator aqui.
fonte
Respostas:
Uma notificação é sobre algo (objeto = evento, amizade ..) sendo alterado (verbo = adicionado, solicitado ..) por alguém (ator) e relatado ao usuário (sujeito). Aqui está uma estrutura de dados normalizada (embora eu tenha usado o MongoDB). Você precisa notificar certos usuários sobre alterações. Portanto, são notificações por usuário. Ou seja, se houver 100 usuários envolvidos, você gera 100 notificações.
(Adicione campos de tempo onde achar melhor)
Isso é basicamente para agrupar alterações por objeto, para que você possa dizer "Você tem 3 solicitações de amizade". E agrupar por ator é útil, para que você possa dizer "O usuário James Bond fez alterações em sua cama". Isso também oferece a capacidade de traduzir e contar notificações conforme você desejar.
Mas, como objeto é apenas um ID, você precisaria obter todas as informações extras sobre o objeto que deseja com chamadas separadas, a menos que o objeto realmente mude e deseje mostrar esse histórico (por exemplo, "usuário alterou o título do evento para ... ")
Como as notificações estão quase em tempo real para os usuários no site, eu as vincularia ao cliente nodejs + websockets com o php pressionando update para nodejs para todos os ouvintes à medida que as alterações fossem adicionadas.
fonte
is_notification_read
nanotification
tabela e marcá-lo adequadamente, se forunread
,read
oudeleted
.Esta é realmente uma pergunta abstrata, então acho que teremos que discuti-la em vez de apontar o que você deve ou não fazer.
Aqui está o que penso sobre suas preocupações:
Sim, um sistema de notificação é complexo, mas não como o inferno. Você pode ter muitas abordagens diferentes na modelagem e implementação de tais sistemas, e elas podem ter uma complexidade média a alta;
Pesonally, eu sempre tento fazer coisas orientadas a banco de dados. Por quê? Como posso garantir o controle total de tudo o que está acontecendo - mas esse sou apenas eu, você pode ter controle sem uma abordagem orientada a banco de dados; confie em mim, você vai querer controlar esse caso;
Deixe-me exemplificar um caso real para você, para que você possa começar de algum lugar. No ano passado, modelei e implementei um sistema de notificação em algum tipo de rede social (não como o Facebook, é claro). O jeito que eu costumava armazenar notificações lá? Eu tinha uma
notifications
tabela em que mantinha ogenerator_user_id
(o ID do usuário que está gerando a notificação), otarget_user_id
(meio óbvio, não é?), Onotification_type_id
(que se referia a uma tabela diferente com os tipos de notificação) e todos o material necessário que precisamos preencher nossas tabelas (timestamps, flags, etc). Minhanotification_types
tabela costumava ter uma relação com umanotification_templates
tabela, que armazenava modelos específicos para cada tipo de notificação. Por exemplo, eu tinha umPOST_REPLY
tipo, que tinha um tipo de modelo{USER} HAS REPLIED ONE OF YOUR #POSTS
. A partir daí, eu apenas tratei o{}
como uma variável e#
como um link de referência;Sim desempenho deve e deve estar ok. Quando você pensa em notificações, pensa no servidor empurrando da cabeça aos pés. Se você fizer isso com solicitações de ajax ou o que for, precisará se preocupar com o desempenho. Mas acho que é uma segunda preocupação;
É claro que esse modelo que eu projetei não é o único que você pode seguir, nem o melhor. Espero que minha resposta, pelo menos, siga você na direção certa.
fonte
Parece uma boa resposta em vez de ter duas coleções. Você pode consultar por nome de usuário, objeto e isRead para obter novos eventos (como 3 solicitações de amizade pendentes, 4 perguntas, etc ...)
Deixe-me saber se houver algum problema com este esquema.
fonte
Pessoalmente, não entendo muito bem o diagrama da resposta aceita; portanto, anexarei uma base de diagrama de banco de dados ao que aprendi com a resposta aceita e outras páginas.
Melhorias são bem recebidas.
fonte