网易云音乐这3年经历了用户量的爆炸式增长,作为一款口碑爆棚的音乐社区App,在业务快速发展的背景下,后端的架构又经历了怎样的发展历程呢?
本文回顾了一个大型互联网应用的后端发展历程,其中涉及到的一些技术内部基本有自研的替代品,出于通用性考虑替换成了相应的开源产品。
本文的读者对象假设已经具备一定计算机基础,如果你希望了解一个亿级用户互联网应用的服务端会涉及到哪些技术,那么请继续读下去吧~
故事从你打开网易云音乐的APP,点开一个歌单听歌开始。那么为了满足你听歌的简单愿望,我们的服务端攻城狮们都做了些啥呢?
你点开歌单,发起了一个HTTP请求,为了响应你的请求,我们搭建了一台服务器运行服务端程序,我们选择免费开源的linux+Tomcat。
>> 企鹅和猫啥时候成搭档了
为了编写服务端程序,需要一种编程语言和服务端编程框架,我们选择了业界流行的JAVA+Spring/SpringBoot。
>> 喝着咖啡就把代码写了,码农的春天来了
服务器有了,代码也写好了,现在我们可以开始服务不同用户的各种请求了。有一天你发现突然歌单打不开了,歌也听不了了,看上去服务器挂了。我们的工程师紧急联系PE发现服务器的load很高,CPU、内存、网卡都吃紧,看上去是我们的热心用户太多,服务器容量已经撑不住了。
经过这件事之后,大家一致觉得只有一台机器太不靠谱了,晚上都没法踏实睡觉。单台服务器无法支撑日益增长的业务请求,CPU、内存、网卡都到了瓶颈,而且一旦挂了就形成单点故障,影响服务的可用率,这时我们又添了几台机器搭建成集群,通过分布式集群来实现业务的平滑扩展。
>> 脑补的分布式集群
服务器越来越多,如果一个物理机只运行一个服务端进程,资源无法得到充分利用,这时我们引入虚拟化技术(KVM,Docker)在一台物理机上运行多台虚拟机,每个虚拟机共享底层的物理机资源(CPU、内存、网卡、硬盘),将物理资源进行虚拟化按需分配,这就是云计算。
业务稳步增长,机器越来越多,我们发现每天中午和晚上是用户活跃的高峰期,机器的load会随着升高,其他时间段则是低谷,机器则比较空闲。不同的请求量对服务器的资源配置提出了不同的要求,如果高峰期可以自动扩容,低峰期自动缩容,就可以实现资源的最大化利用,避免浪费,这时我们需要生产级别的容器编排系统(K8S)。
用户操作客户端时实际上是向指定的域名(music.163.com)发起HTTP调用,这个时候需要去DNS服务器查询域名对应的服务器IP,为了对外暴露统一的IP,实现后端服务器的负载均衡,我们在客户端和后端服务器间加入了一层反向代理(Nginx),如此一来所有的服务端API都通过Nginx来转发,服务的扩容可以只用修改Nginx增加内网机器IP就行。
>>Nginx相当于一个统一的出口代理
业务快速发展,接口爆炸式增长,每次上线都配置Nginx不仅繁琐,而且容易带来稳定性隐患,此时迫切需要一个API网关来统一收拢所有的API注册和露出。
用户开始使用我们的服务之后,存储用户的各种数据需要数据库,除了关系型数据库(MySQL),还有各种NoSQL数据库(Hbase,MongoDB)。随着数据容量的不断增长,单机数据库已经无法满足需求,这时自带分库分表的分布式数据库就开始派上用场了。
写数据库的增删改查代码比较繁琐,需要一个ORM框架(Mybatis)来实现对象和关系型数据库之间的映射,这样读取数据的时候,每一行数据都可以映射成内存中的一个对象,存储数据的时候每个对象又可以映射成数据库的一行数据。
用户量增加后,大量日常的文件存储(如用户头像、朋友圈图片)需要一个统一的文件存储中心,这时我们用上了分布式对象存储平台。
开放数字专辑售卖功能之后,我们发现用户的购买热情非常高,为了应对高并发大流量,减轻数据库的压力,我们引入分布式缓存(Memcache,redis)来抗一部分流量,避免数据库宕机。
解耦神器,非你莫属
为了避免业务的上游和下游强耦合,实现调用异步化,或者应对突发流量,实现业务的削峰填谷,我们用到了消息队列(Kafka,RabitMQ,RocketMQ),将上游业务消息缓存到队列中,由下游业务异步消费。
业务快速发展,团队也在扩张,原有的巨无霸单点应用部署已经越来越制约业务的快速迭代和多人协同开发。为了避免单点,实现业务模块的去耦合和故障隔离,我们开始了服务化拆分进程。
我们将原本部署在一个进程中的代码拆分到多个进程放到不同的集群中运行。服务化拆分之后相互之间调用不再是一个进程内调用,而是需要跨进程网络调用,这时需要注册中心和RPC框架来实现服务的注册、发现及跨进程调用。引入RPC框架之后,为了方便监控和在线调整线程池参数,又开发了RPC管控平台实现动态管控。
随着服务拆分的深入,用户的一个请求可能会经过几个甚至几十个服务,如何定位问题出现在哪个服务,以及查看各个服务的链路耗时,这时需要一个链路跟踪系统。服务拆分之后,根据重要程度对服务进行定级(P级),为了保障核心应用的稳定性和可用性,引入了限流熔断降级框架,可以实现应用网关层的全局限流和单机限流和降级。
线上服务越来越多,机器越来越多,日志分散,可检索性差,为了统一的日志查询,方便及时定位问题,需要一套日志平台(ELK)。
业务越来越复杂,团队开始爆炸增长,需求迭代相互交织,开发、回归、预发、线上环境管理越来越复杂,此时迫切需要一个持续集成平台管理环境和机器的自动分配、任务排期和发布计划。
为了实现前后端同步开发,接口的定义要优先于接口的开发,这时我们开发了一个接口管理平台来达到事前约束的目的。前后端开发可以愉快地协同开发了。测试同学也可以利用平台管理测试用例,接口覆盖率得到了极大的提升。
线上接口越来越多,各种异常满天飞,有些需要关注,有些可以忽略,这时我们需要一个异常报警平台,根据服务将报警通过各种渠道通知到负责人。
随着业务模型越来越复杂,老旧的架构开始腐化,链路也变得越来越脆弱,线上事故频发,9999的可用率无法得到保证,这时我们需要进行架构梳理和全链路压测,针对性地进行故障注入,全链路压测平台和故障注入平台应运而生。
随着用户量的数量级升级,单个机房的集群部署稳定性风险越来越高,可能光纤被挖断或者机房断电之后,服务就全部挂了,带来的损失不可估量。这时,同城双机房和异地多活单元化就提上了议事日程。
终于,服务的稳定性得到了极大提升,你可以放心地听歌了。好了,不多说了,我又来了一沓新需求。
下面是一张时间轴,展示了后端基础设施发展的整个历程,囊括了企业基础设施、基础运维设施、研发提效设施、中间件基础设施、测试基础设施、大数据基础设施等六大基础设施。
本文中涉及到的绝大部分技术方案都已经在内部落地,有一些还在进展中,不过相信很快就可以应用到生产环境。学无止境,勉励自己在后端技术之路能越走越远,成为一个懂业务的技术专家。
来源:网易工程师-王胜
整理总结不易,如果觉得这篇文章有意思的话,欢迎转发、收藏,给我一些鼓励~
有想看的内容或者建议,敬请留言!
最近利用空余时间整理了一些精选Java架构学习视频和大厂项目底层知识点,需要的同学欢迎私信我发给你~一起学习进步!有任何问题也欢迎交流~
Java日记本,每日存档超实用的技术干货学习笔记,每天陪你前进一点点~