xx社交软件架构,总结(持续更新)
一、引言
这个图是笔者参与的一个项目的后端架构图,这篇文章主要是对此架构的一个分析、总结,涉及到架构的优点和可以改善的地方。
二、架构分析
整体架构分成了四层,自上而下:客户端->接入层->业务层->数据层,下面分别介绍下
1. 客户端
这个是前端了,作为一个App肯定包含了安卓和IOS两个客户端,另外还有H5客户端,供PC或手机浏览器访问。对浏览器来说,后端通过HTTP User-Agent请求头适配到不同的页面。比如:安卓User-Agent带有“Android”的字符串,就使用页面1,PC浏览器带有“Firefox”就使用页面2。为什么这么做,因为手机和PC的屏幕大小显然不一样,当然要分成不同的排版显示相同的内容。
看到客户端下面的分层线了吗?客户端通过DNS,访问后端服务域名。这里特别强调DNS是因为,在DNS上做了负载均衡。实际上就是同一个域名映射到多个IP,如果配置两个,那么所有的请求每个IP只承担一半的负载。
2. 接入层
接入层的主要作用就是分发请求,或者说是负载均衡。具体来说,后端的接入是通过HTTP+TCP长链接两种
- Nginx负责接收用户的HTTP请求,nginx的高性能、高并发,将大量的用户请求,分发给下游的应用服务器(tomcat、resin等),作为七层负载均衡软件使用,说俗点就是“接客的”。
- CDN接收用户的资源请求,资源包括:css/js、图片/语音等。对资源请求没有直接具体资源服务器,而是指向CDN,CDN作为缓存大大减少了资源服务器的读压力,而且根据CDN跨地域就近访问的特点,也提高了响应速度。
- LVS接收用户的TCP长链接请求,主要对实时群聊服务(ChatServer)做请求分发。LVS作为四层负载均衡软件使用,集成在Linux操作系统内核中,效率非常高,作为TCP负载均衡
3. 业务层
业务层,当然是作具体业务的了,就是干活的。接入层已经把客人接进来了,也分配给具体的业务服务器了,之后就享受业务层的服务吧。根据不同的业务需求,也拆分成了不同的业务角色。业务主要用Java实现,还包含Python等,主要包含五种
- Web容器:应用服务器,我们这里用的是tomcat,大部分主要的、核心的业务都在这里实现。具体又可以分为:www、api、oauth、admin等服务,分别对应于网站、客户端api、token授权、后台管理业务。
- 静态资源:Python进程,将less文件编译成css文件,属于前端技术不太了解。总之,所有的js和css最终的根源都是从这来的,虽然中间还有CDN和Nginx。
- Event:事件处理,或者称为消息队列。次要的、耗时的、非核心业务,都通过异步消息的方式处理。比如:动态分发、推送消息、短信。是使用的redis的list数据结构来实现的消息队列,lpush+brpop等。
- Runner:定时任务。经常跑一些报表,或其他计划性、周期性的任务
- ChatServer:群聊服务器,使用自定义的消息协议,主要是群聊消息的实时推送,Netty实现。这里,设计上为了简单性,基本所有的写请求,如:发送消息,都走HTTP协议,通过api完成,ChatServer只做纯的消息分发或只接受一些管理性的消息。
- Thrift服务:公用的、耗资源较高的服务,单独抽取出来,独立部署和做负载均衡。这是在业务层中更低一个级别的服务,使用传统的C/S模式。这样的好处有两点,一是服务的重用,二是减轻API的负载,因为服务被独立部署到其他机器了嘛。具体来说,上层(主要是Web容器,还可以是Event等)作为客户端,Thrift服务作为服务端,而在两者之间,用Zookeeper实现了Thrift服务的注册与订阅。Thrift服务启动的时候自动在Zookeeper注册,客户端读Zookeeper获取具体的服务地址,并在客户端实现了负载均衡算法。
4. 数据层
数据层,处于架构最底层,分为四种数据。通过统一的抽象(自实现的数据源框架ZKDataSource),每种数据都是一种数据源,在Zookeeper里面配置。当数据源改变,只需要更新Zookeeper配置,使用此数据源的客户端(业务层)就能够马上感知并更新配置。
- MySQL:重要的业务数据,应用到传统的优化手段,读写分离,根据业务垂直分库,根据数据量,水平分表。
- Memcached:kv内存数据库,作为访问MySQL之前的一层缓存,利用Memcached的高并发、高效率,大大缓解MySQL的读压力。
- Redis:kv内存数据库,和Memcached有相似之处,比如:作为Memcached的替换品,充当缓存系统。这里我们主要用Redis实现消息队列服务,和群聊的消息队列。此外利用redis提供的一些特性,诸如实时榜单等的数据存储也在redis上。部署上也是搭建了主从结构,利用redis一致性哈希,做了sharding(分片),增强了可扩展性。
- 云存储:大量的文件存储,图片和音频。简单快捷,还有一些实用功能,如:动态切图。利用云存储的好处就是不用自己再实现分布式的存储系统,而且云存储现在都比较可靠,基本不必担心数据丢失
5. 聊聊Zookeeper
至此,整体的四层结构已经讲过了,其实从整个技术栈来说,还是挺传统的,架构上很多组件在互联网软件中都是很常用的。但在这其中Zookeeper的作用比较特殊,大概可以认为是架构层次间的粘合剂吧。Zookeeper在本系统中的主要作用
- 数据源:Redis sharding中各个节点、MySQL数据源,散表(水平分表)配置;
- 配置中心:系统的配置、常量等信息在此
- 注册中心:Thrift服务启动后,到此注册
Zookeeper本身是作为Hadoop生态中的“分布式协调服务”角色出现的,但完全可以拿过来为其他系统所用。它对于本系统的好处在于,一是可靠,二是将配置集中,便于管理和维护。
- 可靠性:Zookeeper是分布式的系统,自身具有高可用性,不必担心Zookeeper的故障或单点问题。
- 配置集中:任何系统都是需要有配置管理的,可能是一些配置文件,或者将配置存储在数据库中。Zookeeper作为配置中心的额外好处是,“动态性”。Zookeeper提供一种类似于设计模式中的“观察着”模式的机制,配置改变后会被观察者接监测到,比如:切换想将原来的主库切换到从库上,那么改一下Zookeeper中数据源的配置,数据源就自动切换过去了,不需要重启服务。
当然,Zookeeper的强大还不限于此,分布式队列、分布式锁、领导者选举等,这些分布式系统中的技术,都是可以实现的。
三、优缺点
“我既有优点又有缺点,先听哪一个?” 那就先听优点吧,缺点可以选择性的忽略,毕竟总是要看到别人好的一面嘛( ̄ε  ̄)。
1. 优点
thrift服务跨语言优势
待续
2. 缺点
很显然,系统不具有高可用性(High Availability,HA),比如:一个MySQL主库挂了->收到报警短信->赶紧找可用的从库->修改Zookeeper切换到从库。这个过程看着简单,却需要手动操作,也挺惊心动魄的!操作流程稍有不慎。。。
高可用是可以做的,包括现有的成熟的方案,或者满足不了需求,自己设计方案。但这需要权衡,HA是不是当前紧迫要做。要考虑当前时间成本、人力成本、团队技术水平、系统规模是不是手动维护不过来等。下面只是一些可行的方案,并不一定全面、完善,就当是一个记录或参考而已。
待续
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于