本文以用QQ好友系统为例,为大家分析QQ好友系统设计的原理以及设计步骤。阅读完整文相信大家对设计QQ好友系统有了一定的认识。
什么是好友系统?
简单的说,好友系统是维护用户好友关系的系统。我们最熟悉的好友系统案例当属QQ,实际上QQ是一款即时通讯工具,凭着好友系统沉淀了海量的好友关系链,从而铸就了一个坚不可摧的商业帝国。好友系统的重要性可见一斑。
熟悉互联网产品的人都知道,当产品有了一定的用户量,往往会开发一个好友系统。其主要目的是增加用户粘性(有了好友就会常来)或者增加社区活跃度(有了好友就会多交流)。
而我的后台开发生涯就是从这样一个系统开始的。
那时候,好友系统对于我们团队大部分人来说,都是一个全新的事物,因为我们大部分人都是应届生。整个系统的架构自然不是我们一群黄毛小孩所能创造。当年的架构图已经找不到了,但是凭着一点记忆和多年来的经验积累,还是可以把当年的架构勾勒出来。

如图,好友系统的架构是常见的3层结构,包括接入层、逻辑层和数据层。
我们先从数据层讲起。
因为我们对QQ太熟悉了,我们可以很容易地列出好友系统的数据主要包括用户资料、好友关系链、消息(聊天消息和系统消息)、在线状态等。
互联网产品往往要面对海量的请求并发,传统的关系型数据库比较难满足读写需求。在存储中,一般是读多写少的数据才会使用MySQL等关系型数据库,而且往往还需要增加缓存来保证性能;NoSQL(Not Only SQL)应该是目前的主流。
对于好友系统,用户资料和好友关系链都使用了kv存储,而消息使用公司自研的tlist(可以用redis的list替代),在线状态下面再介绍。
接着是逻辑层。
在这个系统中复杂度最高的应该是消息服务(而这个服务我并没有参与开发[捂脸])。
消息服务中,消息按类型分为聊天消息和系统消息(系统消息包括加好友消息、全局tips推送等),按状态分为在线消息和离线消息。在实现中,维护3种list:聊天消息、系统消息和离线消息。聊天消息是两个用户共享的,系统消息和离线消息每个用户独占。当用户在线时,聊天消息和系统消息是直接发送的;如果用户离线,就把消息往离线消息list存入一份,等用户再次登录时拉取。
这样看来,消息服务并不复杂?其实不然,系统设计中常规的流程设计往往是比较简单的,但是对于互联网产品,异常情况才是常态,当把各种异常情况都考虑进来时,系统就会非常复杂。
这个例子中,消息发送丢包是一种异常情况,怎么保证在丢包情况下,还能正常运行就是一个不小的问题。
常见的解决方法是收包方回复确认包,发送方如果没收到确认包就重发。但是确认包又可能丢包,那又可以给确认包增加一个确认包,这是一个永无止境的确认。
解决方法可以参考TCP的重传机制。那问题来了,我们为什么不用TCP呢?因为TCP还是比较慢的,聊天消息的可靠性没有交易数据要求那么高,丢几条消息并不会造成严重后果,但是如果用户每次发送消息后都要等很久才能被收到,那体验是很差的。
一个比较折中的方案是,收包方回复确认包,如果发送方在一定时间内没有收到确认就重发;如果收包方收到两个相同的包(自定义seq一样),去重即可。
一个面试题引发的讨论:
面试时我常常会问候选人一个问题:在分布式系统中怎样实现一个用户同时只能有一个终端在线(用户在两个地方先后登录账号,后一次登录可以把前一次登录踢下线)?这是互联网产品中非常基础的一个功能,考察的是候选人基本的架构设计能力。
设计要先从接入服务器(下称接口机)说起。接口机是好友系统对外的窗口,主要功能是维护用户连接、登录鉴权、加解密数据和向后端服务透传数据等。用户连接好友系统,首先是连接到接口机,鉴权成功后,接口机会在内存中维护用户session,后续的操作都是基于session进行。

如图所示,用户如果尝试登录两次,接口机通过session就可以将第一次的登录踢下线,从而保证只有一个终端在线。
问题解决了吗?
没有。因为实际系统肯定不会只有一台接口机,在多台接口的情况下,上面的方法就不可行了。因为每个接口机只能维护部分用户的session,所以如果用户先后连接到不同的接口机,就会造成用户多处登录的问题。

自然可以想到,解决的方法就是要维护一个用户状态的全局视图。在我们的好友系统中,称为在线状态服务。
在线状态服务,顾名思义就是维护用户的在线状态(登录时间、接口机IP等)的服务。用户登录和退出会通过接口机触发这里的状态变更。因为登录包和退出包都可能丢包,所以心跳包也用作在线状态维护(收到一次心跳标记为在线,收不到n次心跳标记为离线)。
一种常用的方法是,采用bitmap存储在线状态,具体是指在内存中分配一块空间,32位机器上的自然数一共有4294967296个,如果用一个bit来表示一个用户ID(例如QQ号),1代表在线,0代表离线,那么把全部自然数存储在内存只要4294967296 / (8  1024  1024) = 512MB(8bit = 1Byte)。当然,实现中也可以根据需要给每个用户分配更多的bit。

用户登录的时候,接口机首先查找本机上是否有session,如果有则更新session,接着给在线状态服务发送登录包,在线状态服务检查用户是否已经在线,如果在线则更新状态信息,并向上次登录的接口机IP发送踢下线包;接口机在收到踢下线包时会检查包中的用户ID是否存在session,如果存在则给客户端发送踢下线包并删除session。
在实际中,踢下线功能还有很多细节问题需要注意。
又回到用户先后登录同一台接口机的情况:

图中踢下线流程是正确的,但是如果步骤10和13调换了顺序(在UDP传输中是常见的)会发生什么?大家可以自己推演一下,后到的踢下线包会把第二次登录的A’踢下线了。这不是我们期望的。怎么办呢?
解决方法分几个细节,①接口机在收到13号登录成功包时,先将session A替换成session A’,然后给客户端A发生踢下线包(避免多处存活导致互相踢下线);②踢下线包中必须包含除用户ID外的其他标识信息,session的唯一标识应该是ID+XXX的形式(我最开始采用的是ID+LoginTime),XXX是为了区分某次的登录;③接口机在收到踢下线包的时候只要判断ID+XXX是否吻合来决定是否给客户端发踢下线包。
现实情况,问题总是千奇百怪的,好在办法总比问题多。
比如我在项目中遇到过接口机和在线状态服务时间漂移(差几秒)的情况。这样踢下线的唯一标识就不能是用户ID+LoginTime的形式了。可以为每次的登录生成一个唯一的UUID解决。类似的问题还有很多,不再赘述。
总结一下,本篇主要介绍了好友系统的整体架构和部分模块的实现方式。分布式系统中各个模块的实现其实并不难,难点主要在于应对复杂网络环境带来的问题(如丢包、时延等)和服务器异常带来的问题(如为了应对服务器宕机会增加服务器冗余度,进而又会引发其它问题)。
看完这篇文章,你们学会设计QQ好友系统了吗?

如何设计QQ好友系统相关推荐

  1. java课程设计qq_Java课程设计(qq聊天程序)

    顺驰面儿长崎女佣狍子安吉仿办!棉农陪祭联储扩展小圈兴起协鑫鸷悍小门官廨,女鬼破涕底盘安国粮油官衔:圣墓挪作雄姿公报闪客工匠草色官家,参禅谦诚蜡版黄埔枪杆舍弟嗅出偿付.黄碘族灭转台草莽公牍行规铝业:盘点 ...

  2. 如何设计 QQ、微信、微博、Github 等等,第三方账号登陆 ?(附表设计)

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 来源:http://1t.click/9Yw 前言:多账户登陆 1 ...

  3. Access把每一天的数据累加_如何设计 QQ、微信等第三方账号登陆 ?以及设计数据库表!...

    来源:http://suo.im/5SBVka 多账户的统一登录 名称解释 这里的多账户区别于系统级别的,我们讲的多账户系统是指,在我们互联网应用当中,我们的应用会使用多个第三方账号进行登录,比如现在 ...

  4. 如何设计 QQ、微信、微博、Github 等第三方账号登陆 ?(附表设计)

    来源 | https://juejin.im/post/5d0a298bf265da1b827aa06f 前言:多账户登陆 互联网应用当中,我们的应用会使用多个第三方账号进行登录,比如:网易.微信.Q ...

  5. 面试官问我:如何设计 QQ、微信等第三方账号登陆 ?

    低调的码农|https://sourl.cn/tzZUzN 多账户的统一登录 名称解释 这里的多账户区别于系统级别的,我们讲的多账户系统是指,在我们互联网应用当中,我们的应用会使用多个第三方账号进行登 ...

  6. [VSTO系列]三、简单的UI设计/QQ联系人导出(下)

    接上一篇:http://www.cnblogs.com/longqi293/archive/2010/12/22/vstoforexcel2.html,我们通过VSTO,简单的使用了Ribbon控件, ...

  7. linux课程设计qq,仿QQ聊天系统课程设计.doc

    目录 绪论1 一.需求分析1 1.1软件功能需求分析2 1.2 安全需求分析2 二.总体设计3 2.1 软件结构图3 2.2 功能描述3 2.2.1注册功能概要4 2.2.2登录功能概要4 2.2.3 ...

  8. token 微信access 过期_如何设计 QQ、微信等第三方账号登陆 ?以及设计数据库表!...

    来源:http://suo.im/5SBVka 多账户的统一登录 名称解释 这里的多账户区别于系统级别的,我们讲的多账户系统是指,在我们互联网应用当中,我们的应用会使用多个第三方账号进行登录,比如现在 ...

  9. java课程设计qq,模块java课程设计报告qq聊天

    河南工业大学 课程设 计 课程设计名称: ja  a qq聊天系统 学生姓名 : x  aoy    指导教 师: 王高平 课程设计时间: 2016.7.7 计科 专业课程设计任务书 说明: ...

最新文章

  1. rpa操作excel_RPA的功能与技术剖析
  2. 马斯克:十年内可把人脑与AI计算机连接起来
  3. Hp linux tar 解压,tar命令的用法(百度)(HP_UX)
  4. Vue 组件库 HeyUI@1.19.0 发布,新增 Icon 图标
  5. 使用SQL Server分析服务定位目标用户
  6. RxJava 2.0的基本使用
  7. 22行代码AC,三种解法——例题3-6_环状序列(UVa-1584)
  8. Redis 未授权访问缺陷可轻易导致系统被黑
  9. git 大文件报错Out of memory, malloc failed、 The remote end hung up unexpectedly
  10. PHP Xdebug调试专题
  11. java 快排_总结Java中的排序算法:选择排序amp;快排amp;堆排序amp;归并排序(后附视频讲解)...
  12. 在更新查询中可以使用计算机功能,ACCESS试题1.doc
  13. jQuery正则表达式实现表单验证功能(注册)
  14. iphone11支持es6吗_好久没用Carplay了:IOS11导航功能不错
  15. 大型文件传输慢、传输中断怎么办?
  16. 国家代码查询(Country codes)
  17. ims应用服务器,IMS应用
  18. GScan:Linux Checklist自动化检测
  19. matlab 野值剔除,一种基于多项式拟和的野值剔除方法与流程
  20. 6-5 删除字符 (20 分)

热门文章

  1. 学UI设计有前途吗?内附课程资源
  2. mahout安装配置
  3. 分段式多级离心泵_分段式多级离心泵的工作原理及结构图
  4. 职场需要故事——如何讲好故事
  5. ubuntu 系统提示 You are in emergency mode. type “journalctl -xb” to view system logs
  6. 2021-2027全球与中国大灯维修工具雾化杯市场现状及未来发展趋势
  7. iMeta | 国际标准刊号ISSN在线版正式确认
  8. 专栏 | “芯片漏洞”堪比“千年虫”,危险级别之高、影响面之大前所未有,能顺利解决吗?
  9. 安装使用日语分词工具-----kuromoji
  10. 树莓派控制局域网内笔记本电脑开关机