姚东旭 美芽 CTOgit
美芽做为一个美妆视频社区,在 2015 年 2 月份上线以后,极受女性用户的欢迎。这次美芽 CTO 姚东旭在 UPYUN Open Talk No.4 厦门场,分享了美芽从零到一的整个产品生命周期,带给创业公司不少值得借鉴的地方。程序员
美芽在萌芽过程当中,同不少初创产品同样,有常见的三个特色:数据库
面对这样的境况,相比较代码的执行效率或线上接口的响应效率,更为注重开发效率是美芽的应对之策。而影响开发效率主要包括三方面:一是沟通成本,以客户端和后端同窗的沟通为主;二是重复轮子,已经有成熟的开源实现了,却用本身的代码重复实现了;三是过分设计。后端
1)协议缓存
在协议方面,不少项目在设计先后端交互协议时很是随意,好比 /Post/Show/xx ,实现起来也没有统一标准。服务器
从请求没法明确看出该以哪一种方式获取数据,客户端同窗必须询问服务端,或者在文档里清晰的描述出来。特别是对于新加入的开发者,须要一个熟悉的过程。好比删除一个帖子,使用 DELETE 或 GET 方法,也并无统一的标准,针对这个问题,美芽是选用 REST风格。网络
REST能够翻译为表现层状态转化,这里应该还有个主语,那就是 Resource(资源),特指网络上的具体信息,好比帖子和评论。美芽在设计客户端请求接口的时候都是针对一个资源作操做。REST定义了一个对资源操做的标准,使用 HTTP 的四个动词表示对资源的操做,GET,POST,DELETE,PUT。以用户帖子为例:架构
不管新加任何功能模块,包括评论或点赞等都执行这一标准。在开发客户端的过程当中,就避免了添加新功能时对接口作其余的约定。框架
以模型 Post 举例,接口能够变成在获取帖子时,将 id 传过去,返回来就是须要的对象。帖子在后端或数据库中的字段,在客户端对应的就是 Post 模型的属性。运维
再也不须要有文档去介绍它,只须要自动生成一份数据库字典就把全部东西解决了,少了不少中间成本。在客户端要建立帖子就变得极其简单,客户端用定义好的方法请求到后端,服务端收到请求后就往数据库里新建一个资源。美芽在客户端接口设计的时候都是针对资源操做。
总结来讲,接口设计面向资源、而非功能。在客户端有各类功能和操做,在接口上面确定不能全部的东西都按客户端的要求设计,这样会增长很大成本。咱们在接口设计上只关注数据,至于怎么操做是客户端的事情,将数据和表现分离。
2)流程
开发流程,刚出道的时候因为流程不完善,会出现各类问题,好比刚上线的代码或刚修正了一个 Bug随意发布,发布上去后又发现有问题。
针对这点,美芽制定了本地环境 - 开发环境 - 预发环境 - 生产环境四个环节。每一个人在本地环境完成后将代码提交,会自动发布到集成开发环境;预发环境的存在,是想在上线以前,在一样的生产环境下,作最终的确认,以后再更新到用户环境中。
代码管理的流程,从仓库来讲,首先有 master 和 dev 两个长期分支,master 是主干分支,dev 是开发的集成环境 。当要修改 bug或者开发新特性时会新建一个新分支,问题修复后须要将这个分支 merge 到 dev 分支,须要上线时就合并到 master,这是一个特定的生命周期。
代码在推向预发环境前要通过其余成员的审核,审核以后才会合并。合并后使用 git hooks 工具,自动将代码更新到预发环境,在App客户端 内部会作一些开关控制它用哪一个环境。
在整个过程当中,对全部同窗都是透明的,咱们使用了 Slack 做为消息枢纽,Slack 订阅了 Github 通知事件。团队里面的每一位成员,只要关注项目都会看到全部的动态,包括特性上线、Bug修复等。还有一个工具 fabric, 这是一个 异常上报 组件,客户端集成 fabric sdk后就能够将异常上报到 fabric,fabric再通知到 Slack, 团队成员就能在 slack 中看到客户端运行动态了。
先看框架。其一,为了保证开发效率,但愿框架使用起来可以足够简单,新的团队成员也可以很好地适应。关于颇受争议的 ORM 须要观察它的适用状况,在用户规模尚小、数据量较小时,ORM 可以快速实现业务需求,而当量级渐长就该果断舍弃;其二,框架必须保证功能强大,以尽量减小开发量。
基于以上的综合考虑,美芽选择选择使用了如下PHP框架和工具:
一、PHP 采用 Laravel 框架,框架在设计的时候支持 RESTful,在代码层面当新加一个路由资源的时候,新加一个 Controller 就能够解决了。
二、DB migration,这个是修改数据表结构的一个工具。刚刚说起的需求会较不稳定,常常会遇到字段的增减,而此类操做若是只是手动修改,并须要同步到其它环境,将极其不利于管理。DB migration 这个机制是用要代码表示数据库字段的增删。
譬如在增设字段时,新增一个类表示对数据表的操做,其中,up 方法就是执行修改,down 是回滚修改。等到上线时,就只需更新 PHP代码,这就统一了表结构的统一操做,全部的东西都用代码呈现,呈现又是文本,能够进行版本管理。人员对数据库的全部操做都有纪录。
三、Command。好比,开发一个命令行工具,让用户输入一个名字,根据名字调用信息,须要包含输入参数,和选项参数以及输出。Command 会将这些东西作包装,不须要开发除了产品业务逻辑以外的东西。
四、Queue,进行不少操做时不能同步等待,好比推送一条消息,发布一条评论让对方收到消息通知,确定不能在请求里同步处理,而是要放到队列里异步执行,再推送到苹果的服务器最后推送到用户。这个例子是项目中用的,咱们添加队列的时候只需在服务器上执行一条命令打开这个队列。
五、 Tinker,这也是命令行的工具,能够作到在执行这条命令的时候,把整个项目环境加载进去。并且是一个交互式的操做,好比要取一个对象就能够直接查询,把信息打出来。相比较调试代码时用url或者添加各类参数,这种处理方式会很是方便。
六、还有一个是对 Log 的处理,使用时只须要配置一下,在当前环境下须要打的 Log 级别,在代码中直接使用便可,或者在生产中将这类信息都保留。
上面使用的每一项都不是太复杂,或者难度特别大,本身作也均可以。但在资源有限的状况下,初创团队更重要的是投入更大的时间和精力在业务上。这个框架是集成了开发中一些通用的内容,减小了不少额外的开发工做。
虽然看上去 Laravel 框架很是美好,但美好都是有代价的,Laravel 框架很是的慢。由于它提供了各类封装、加载了不少东西,致使一个空的接口响应时间也须要几十毫秒。因此更适合量不大的初创产品。但与此同时,美芽也正在积极解决效率问题。
再来看 iOS 类库,REST 只是定义了标准,而没有提供完整的工具来实现,一般服务端返回的是 JSON 格式数据,客户端将收到的 JSON 格式转换成 NSDictionary,再由 NSDictionary 转换成 NSObject, 这可能对应到客户端的一个 Model 或者一个具体对象;客户端发请求到服务端时,就须要将 NSObject 转化成 NSDictionary, 再转换成 JSON 格式,而后发送到服务端。这个过程很是烦锁,并且须要对每一个类都实现一套 encode decode 的逻辑,而实质上咱们关心的只是 Value 而已。咱们引进了 Mantle 库,这个库会帮你实现这一系列封包解包的过程。
再加上 TMCache AFNetworking 这两个库(前者用来实现快速的对象缓存,然后者基本上每一个 iOS 程序员都熟悉的一个网络框架),就能实现整个产品的 Model 层。
最后介绍一套开源软件 ELK(Elasticsearch Logstash Kibana),这一套软件主要用来处理日志,进而分析问题,其中Elasticsearch 负责存储+搜索、Logstash 负责搜集、Kibana 负责展现,经过 ELK咱们能够随时观察事件的发生,并做出及时稳当的处理。
好比客户端访问服务器时返回系统繁忙这些错误,或者是帖子加载过慢这些问题均可以经过这一套软件展现出来。虽然看似复杂,但实际操做却极其简单,如今咱们主要分析程序内部日志,Nginx access log 和 Nginx error log。
这些日志会先经过 logstash 采集,存储到 ES 上,再经过 Kibana 展现出来。
同时,这一套工具还有对运营数据分析的支持。接入这套工具,美芽实现了各类业务的简单统计,包括注册统计、地区分析、时间分析、用户活跃时间等等。接入 ELK 也是很是简单的,只需将原始数据导入,调用一些查询语句就能够展示,只须要调用一下接口、填入统计数据便可,业务上不须要作什么操做和修改,更无需修改数据库和代码主逻辑。
美芽 总体宏观架构以下图所示:美芽用户经过 APP 或者PC 版跟 Nginx 交互再访问 API,这里所产生的日志都会写文件,在文件写入以后就会有 Logstash Agent 会翻译成固定的格式存到 Elsearch, 同时 API 内部也会将日志会先输出到消息队列中,由消息队列再异步输出到 Logstash Agent,Dashboard 会调用 kibana 的接口,以运营能接受的形式展示出来,以下图:
会管理线上服务器的客户端开发,才是一名好运维。
特别介绍下美芽的运维,尽一人多用之能事,运维也兼作开发。在代码的上线流程中并不须要运维的参与,但软件安装、配置更新就须要运维处理。美芽的运维,主要是经过 Saltstack,用 YAML 来描述服务器的状态。YAML 做为一种比较简洁的数据格式,是纯文本的,也就是说服务器的全部状态均可以进行版本管理,服务器的状态可根据每一个版本里面的配置文件体现出来服务器当前是什么样的状态。
看下面一个简单的示例,下图是一个 logstash 的 saltstack 配置:
首先是有一个 master 节点,这是一个中心节点,而后有不少的 minion 节点须要被更新。
执行如下一条命令就能够将全部的 minion 更新了,命令有两个参数,一个是 prod,是一个分组的概念,好比五台服务器,把五台服务器都放到分组里面;后面一个参数 production, 表明生产环境。操做时,前半部分是针对五台服务器作的工做。