引用
声明:本文为《从程序员》8月期原创投稿文章,未经许可禁止任何形式的转载。
作者:秦鹏,MaxLeap服务与架构部负责人,负责公司云平台、云应用的后端研发和维护工作。多年分布式、高并发场景的实战经验;目前在分布式存储、缓存、中间件、容器技术、微服务、DevOPS等领域均有涉猎。毕业于上海交通大学,曾供职于SAP,后投身MaxLeap致力于为企业和开发者提供快稳定、可靠的云服务。
摘要:MaxLeap从一个对内的私有云服务平台,发展到对外服务的BaaS平台,其功能覆盖了移动领域开发、运营的完整服务链,近期还会推出PaaS服务。在这个过程中,支撑整个平台的基础架构也在不断演进。本文结合了云平台的业务发展,介绍基础架构演进过程的主要思路、遇到的难题、用到的开源技术和未来的规划。
前言
MaxLeap早期是一家研发、运营移动应用和手机游戏公司,发展过程中积累了很多通用组件。这些组件很大程度帮公司在移动研发过程中节省了时间和成本,有没有可能以云服务的方式开放出去,创造更大的价值?延续这个思路,公司成立了云服务部门,尝试服务的商业化。
从对内提供接口服务到对外提供云服务,经历了三个阶段发展:1.0时代,定位对内服务,为公司研发的几十款应用提供服务端功能,推送、统一用户管理等API接口,可以说是非常普通的接口服务;2.0时代,定位对外服务,除了支撑公司的移动研发以外,同时对外开放服务,提供更多的功能接口,也参考了行业的通用做法,形成了针对移动研发加速和提高运营效率的BaaS云平台;3.0时代,定位基础研发平台,工具链逐渐完整,从研发、上线、运维到运营,提供应用管理、支付、IM、推送等SaaS功能,也提供托管、发布、监控、日志等PaaS功能,逐步形成SaaS + PaaS的研发平台。
云服务概念
常见的云服务有几种方式:
1. IaaS(Infrastructure as a Service),基础设施即服务。提供云端的基础设施为主,比如提供主机、存储、网络、CDN、域名解析等功能,知名厂商有阿里云、AWS、Azure等;
2. PaaS(Platform),平台即服务。提供云端的发布、数据库服务、文件存储、缓存服务、容器管理等基础存储和管理组件,自动化了程序的配置、发布、管理,有Heroku、Google App Engine、Force.com等;
3. SaaS(Software as a Service),软件即服务。提供云端的应用服务,ERP、HR、CRM等在线系统,每个账户或者每家公司有独立的数据存储,通过账户进行权限和访问隔离,知名厂商有Salesforce、Successfactor、Zendesk等;
4. BaaS(Backen as a Service),后端即服务,起初专指针对移动端研发提供的云服务,降低移动研发的复杂度,让开发者关注与移动端开发即可。流行的服务有几大类:综合类:Parse、Kinvey;分析类:友盟、TalkingData、神策数据;支付类:Beecloud、Ping++;IM类:环信、网易;消息类:极光、个推等。
我们在2.0时代把自己定位于BaaS,随着功能的不断演进3.0着眼于PaaS和SaaS。
1.0 单应用架构
背景
当时公司有几十款App需要研发和运营,每个应用功能各异,种类包括浏览器、音视频工具、社交工具、清理大师、图片存储类和手游等,门类很多、很杂。如何提高研发效率,实现一套统一的研发、管理和运营体系,是当时的主要诉求。对主要功能进行梳理之后发现,各类应用共同需要依赖的组件包括,用户体系、云参数体系、推送服务、数据存储和广告服务。
图1 1.0业务模型
需求基本明确后,目标是快速上线,然后小版本迭代。
设计
当时4个后端研发人员,Java出身,人少但是技术精干。结合团队情况和产品需求,决定采用如下架构,简单但给力。
图2 1.0架构
典型的Web应用架构方式,使用Nginx做反向代理和负载均衡,后面跟了多个JVM实例。每个JVM实例由Jetty作为应用服务器,提供REST接口,服务层实现具体的逻辑。DAL层对DB和缓存进行封装,提供统一的数据访问接口。Redis作为缓存方案,支持多个shard水平扩容,TPS高、性能好。Cassandra作为数据存储引擎,无中心、可水平扩展、易维护,没有专门的运维人员,对研发人员非常友好,由于没有事务场景,NoSQL完全满足当时的需求。RabbitMQ作为消息中间件方案,不同进程间通信,支持HA,支持持久化。Zookeeper用于存储基础配置信息。
小结
这种简单的设计,有效支持了公司几十款应用的运行,日访问量达数十亿级别。统一后台基础服务和移动端SDK后,提高了移动应用的研发和上线速度,研发了用户管理、推送这些基础功能,在移动端几行代码搞定。通过控制台,能有效管理应用和配置信息。其实对于多数十多个研发人员的公司来讲,这样的单应用架构性价比最高,解决商业上的问题才是关键。
也有不少需要改进的地方,Cassandra作为业务数据的存储,查询非常不灵活,依赖设计时对row key和composit key的精确把握,扩展非常困难,再加上对翻页、排序等支持有限,在数据层做了很多特殊处理。整个系统没有脱单,Redis、Nginx还有单点问题,脱单是高可用系统中首要需要解决的问题。所有服务部署在一起,出问题时相互影响,项目耦合度高,扩展困难。同时,开发效率低,发布新功能时相互依赖等,这些都是单用架构设计最明显的问题。
2.0 服务化架构
背景
随着业务不断发展以及新的产品定位,单应用架构的弊端不断暴露出来,要求我们在新的规划中,重新设计整个后端架构。
新的需求如下:
- 定位公有云,服务标准化;
- 多租户支持,用户数据需要隔离,每个公司都有自己的后台管理和账号管理,不同工作人员区分权限职责,允许同时有多款应用,应用在逻辑上相互独立,每个应用可以使用所有服务;
- 更灵活的存储和查询服务;
- 提供基础数据分析功能,提供代码托管等更多云服务。
图4 2.0云服务架构
网络,最外层增加了ELB,IP地址直接暴露在公网是非常危险的方式,通过DNS配置CNAME指向域名,降低了被DDOS的风险,提高了Nginx的可用性。ELB本身会在访问增加时,自动伸缩,配合IaaS厂商提供的AutoScalling服务,可以抵御多数DDOS攻击。通过Nginx作为反向代理和负载均衡,不同服务指向不同的upstram地址和端口。服务间禁止相互依赖。
容器,每个服务都运行在Docker中,服务之间环境和资源隔离,能够快速迁移和部署,统一了交付和发布流程。每个容器无状态,服务迁移、扩容、宕机等问题迎刃而解,在服务化过程中起到很关键的作用。
数据,NoSQL部分主要依赖MongoDB,Wired Tiger + SSD,由于MongoDB的Schema-less特性,开发者可以根据自己的需求随时调整实体的定义。天生为分布式设计,支持复制集高可用方案,支持多Shard水平扩展。关系型数据库采用MySQL,用于实现支付、订单、配置信息等需要事务支持的业务,我们基于MHA实现MySQL的高可用和读写分离。不同服务所依赖的库必须分离,从数据着手保障用户资源的隔离。
存储/缓存,块数据依赖AWS的S3,权限控制、分桶策略比较实用,可用性有保障;缓存依然使用Redis,为了解决单点问题,对原有版本进行了升级,采用官方的3.0集群方案,支持分片和高可用,当然也有其它方案可选,比如codis等代理的方案。
云计算部分
图5 2.0云分析架构
数据收集部分采用REST + Kafka方式,其中很重要的一部分是DataTransform,用于数据标准化、过滤、流控等用途,基于vert.x实现。
计算部分参考Lambda架构实现,分为Speed Layer、Batch Layer、Serving Layer三层。
Speed Layer,基于Storm实现,引擎监听Kafka中收集到的新数据,把一些对实时性要求高的指标计算完成,写入展示层。Batch Layer,基于Hadoop生态实现,通过开源项目Camus,把Kafka中监听到的数据存储在HDFS中,然后通过HIVE或者M/R的Job,计算各种指标,工作流通过oozie来调度,最终结果也写入展示层,并且覆盖掉实时计算的结果。结果数据根据不同指标,按天、周、月分别存储在Cassandra中,有很高的写速度,无限水平扩展。展示层,数据同时用antlr4j实现了SQL解析,访问Cassandra中的计算结果。
小结
相比较1.0时期,架构上更合理,扩展性、维护性、鲁棒性都有很明显提升。功能上,完成移动应用研发大部分组件(统计分析、支付、IM、社交、在线参数、推送、营销、云数据、云存储、云代码)。应用的研发、上线、运维、运营形成闭环,顺利完成从对内服务到公共BaaS平台的升级。团队上,1-3人一个服务的研发,测试、上线的节奏可以自己把控。
当然,业务在演进,也有新的问题需要去解决。从功能角度,Nginx只能支持静态方式设置反向代理,然后reload,而平台有服务对应的后端服务和端口是有动态调整需求。从架构角度,在相对成熟的系统中,日志、监控这些基础组件需要统一收集、管理、处理。数据访问层、RPC等基础服务也要标准化。
3.0 平台化
背景
图6 3.0业务模型
对于创业公司而言,业务随时会有调整,作为技术人员,需要能够应对这种变化,架构上为这些变化做准备。产品向3.0演进由新的业务需求和架构自身的调整需求共同推动。新的业务需要支撑一个全网营销的SaaS产品线,产品支持配置操作生成App+微信商城+手机网站,以及营销,就是需要本来专注于移动端研发定位的BaaS,向PaaS化和SaaS前进。架构上是基础组件需要进行升级,数据访问层、RPC、日志、监控系统等。于是我们提出一个目标,就是平台化,数据访问的组件以PaaS形式提供给开发者和内部团队,标准化API网关、日志、监控系统。
设计
设计上依然延续稳定、成熟、解决问题的思路。网关服务作为所有请求的入口,稳定、性能、水平扩展是考虑的要素。数据访问层,就像一个项目的大动脉,所有的访问压力、瓶颈、安全问题会在这里汇合,如何构建一条数据访问的高速公路是我们的目标。日志和监控,虽然没有业务系统那么核心,但是关键时刻出现问题需要排查时他们很大程度会影响解决问题的效率,好的监控系统能第一时间把正确的信号通知到正确的人,而烂的监控只会为运维带来困扰。
网关
我们设计网关的初衷是替代掉Nginx,在自研的网关上控制规则转发、主机注册、容器状态检查、负载均衡、服务拒绝、限速等功能。Nginx是非常优秀的一个软件,也满足一部分网关的功能,但是无法满足我们不断进化的需求。
整个网关系统由规则控制组件和容器管理组件两部分组成。后的服务在启动后,向Hydra-容器管理组件,注册自己的服务、IP地址和端口信息,Hydra随后接管容器的生命周期管理,进行健康检查,Failover处理,并把相关的信息保存在Zookeeper和MySQL中。规则控制组件在请求到达后,进行规制匹配、路由转发、限制、限速等处理。
目前网关用在了大多数服务中,下步计划是所有服务统一由网关进行管理,下图是网关系统的最终形态。
图7 3.0网关架构
数据访问
结构化的业务数据主要存储在MySQL和MongoDB中,设计上我们增加了数据代理层,代理层完全兼容MySQL和MongoDB的数据访问协议,让开发人员对代理完全无感,表面上是在访问特定的数据库,实际上连接上数据代理后,由代理对数据操作做解析和路由。
当然,如果是仅仅实现代理的功能,有很多开源项目可以使用比如MyCat、MySQL Proxy等,我们对代理有这些需求,数据访问路由和配置变更,数据访问鉴权和处理,日志采集发送,流控和服务拒绝。
图8 3.0公共组件架构
日志系统
设计之初也有考虑自己研发,通过调研后发现ElasticSearch+Logstash+Kibana完全满足我们的需求,并且ES的生态和社区非常活跃。通过早期几个服务的试水,最终决定整个平台基于ELK构建日志系统。
我们是这样做的,在每台主机上部署Logstash Angent采集格式化的日志数据,向Logstash Server发送日志。为了降低运维成本,我们把Logstash Forward做成Docker镜像,通过Salt来管理所有的Agent。Logstash Server在拿到日志信息后,不做任何规则上的处理,将数据保存在ES中。其实Logstash Server自身有日志解析和格式化的功能,但这样做会严重影响它的吞吐量,于是我们的方案是把日志标准的流程控制在源头。接下来,在Kibana中建立各种服务的面板和视图,便可以进行浏览和检索了,还可以周期对日志进行rotate、分析。
图9 3.0日志系统
监控系统
基于日志系统的基础架构,不同服务将Metrics输出到文件系统,通过LogStash和ES收集。在Kibana中定义视图,Kibana使用ES作为自己的存储引擎。比如新增一个视图后,Kibana会在ES的.kibana这个索引中创建一份视图的定义。
有了Metrics数据和视图的展示,下一步是报警。利用Nagios的报警机制,基于JNRPE实现报警的逻辑。报警逻辑通过读取ES中.kibana某一个视图的定义,和对应的阈值设置,通过比较当前值和阈值,返回某一个服务对应特定指标的监控状态。Nagios拿到状态后,决定是否报警。
图10 3.0监控系统
小结
相比较2.0时期,统一了主要的基础组件,降低了不同服务之间重复劳动部分。通过日志系统也提升了定位问题的效率,接下来还会考虑实现一套自己的请求trace系统,希望能够跟踪整个请求的生命周期,为寻找问题和定位性能瓶颈做参考。
总结
从应用到平台,公司业务和产品定位在不断的演进,架构也随之发生了天翻地覆的变化。有一点是我们研发人员时刻要提醒自己的,不能脱离业务去谈技术,满足业务是原动力,一切抛开业务去空谈架构的做法都是耍流氓。
成熟简单的技术就是最合适的,踩坑在所难免,但是如何把有限的资源用于做对的事情,不仅对商业和产品适合,对研发也同样适合。互联网公司多数都有由小团队、小想法、小产品,一步步发展起来的,在这个过程中能够通过设计和决策,在正确的时间做正确的事情,让产品能够快速迭代,快速上线,才是架构人员最需要考虑的事情。
2 楼 fnet 2016-08-16 11:40
1 楼 g21121 2016-08-04 10:05