24
本文由云+社区发表,作者:韩伟

互联网开发的核心问题

当我1999年进入互联网行业工作的时候,华为刚刚通过了著名的CMM认证。当时作为一个小程序员,非常向往业界经典的软件开发模式。因为看上去,如果企业实行了CMM,我们程序员就不用再天天为了老板一个拍脑袋的主意而加班开发了,各种各样的奇葩需求和无理变更,也会烟消云散。但是,在接下来的十几年,几乎没有那个互联网公司再去通过CMM认证。

是否CMM这种软件开发模式,就根本不适合互联网行业呢?这是一直以来我都在思考的问题。反而是跟随着互联网企业的一步步长大,我无意识的体验了很多现在流行概念的早期实践:敏捷、重构、持续集成、DevOps,这些实践一开始都非常的幼稚粗糙,但是却真正的伴随着互联网业务的逐步成长。所以,在讨论互联网服务的开发模式时,我认为必须要先搞清楚互联网服务开发的核心问题是什么。

img

本质:服务,而不是产品

软件到底是“服务”还是“产品”,这个话题一直都非常具有争议。作为程序开发者,实际上是非常希望软件能够是一个产品,因为软件的后续维护和修改,往往是“导致”项目失败的最常见原因。然而事与愿违的是,在互联网企业中,打多数的软件项目,表现出来的是典型的“服务”特征:

  • 没有明确的需求合同。这导致了没有办法为软件设计固定的开发方案,也难以确定长期目标。
  • 没有预付款和客户验收。互联网服务用户来了就用,爽了就给钱,不爽了就走,连沟通的机会都不会有。
  • 甚至连明显的销售环节都没有。很多互联网公司只有市场推广部门,而没有所谓“销售”部门,因为推广就几乎等于销售,在推广的同事,就必须把销售的事情一起做了。

因此,在互联网行业中,软件开发更多的是以一种服务的形式存在。这种特征,在对需求的分析管理;开发技术的选择;集成与测试;运营和客服四个方面,都导致了不同于“产品”型软件的巨大差异:

  • 对于一项服务来说,需求是持续变化的,你可以找到一些通用的模式,但是必须保持变化。
  • 开发效率是第一重要的,因为市场竞争中,应对需求变化快的单位将获得更多的客户。

由于服务必须保持长期的稳定可用,又要具备快速的更新部署能力,所以系统集成的效率和质量要求非常高。所幸的是系统运行的环境大多数都是在可控制的空间里(比如开发公司自己的机房内)。

服务是公司和客户的一种持续沟通和交互的过程,并非一个单向的发售行为,所以互联网服务需要更多细致的运营和维护的工具,否则难以做到迅速而细致的满足海量的互联网用户的需求。

img

小米的MIUI开发节奏

管理:手段.vs.工具

在各种项目管理的课程里面,陈述了大量针对人去工作的方法。各种会议、报告、表格、评估、测量多不胜数,然而软件项目进度的控制,依然是一个难度堪比登月的事情。——对于很多项目经理来说,程序员们基本是一个黑盒子,他们自己都不知道一个事情需要多长时间干完,就更别提别人怎么去预估和控制。这里最大的问题,我觉得是:我们往往总是想着怎样“控制”住软件项目的进度,而忽视了如何减少不利于项目进度的因数。实际上影响软件开发进度的主要因数,一般有一下几个:

  • 程序员的能力水平。有一些项目其中的技术,是程序员完全没接触过的类型,这里包含了学习、调试的时间。
  • 开发过程中的各种修改变更。由于对可行性、需求确认等方面的因数,开发往往会走“回头路”。有些项目做到一般会发现技术上不可行,需要修改需求;而另外一些项目是在项目做到一半甚至快完成的时候,需求方发现需要修改产品设计,因为在产品可体验之前,完全无法想象到最后会是现在的样子。
  • 各种和开发无关的过程中的事务。这里包括开会、写报告、沟通、等待开发电脑编译、处理开发服务器故障、各种开发环境和测试环境的问题处理等等……这些事情往往都看起来不是非常“有技术含量”,但是实际上会严重影响开发进度。因为开发工作需要一个稳定、专心的工作环境,频频的被各种事务打断,会让程序员反复的花费时间去“进入”工作状态——面对成千上万行程序代码,要找到之前写到哪个部分,其实不是那么简单。

针对上面说的几个问题,很多都可以通过应用更好的开发工具来解决。比如一些新的需求类型,我们可以求助于互联网上丰富的开源软件和开源库;面对需求变更,我们可以使用设计模式、单元测试等工具;开发中的事务问题,更是可以有大量业界先进工具可用:SVN,Git,Jira,Project,IDE,Chef,Docker……

img

与其我们拿着鞭子抽打程序员,还不如给程序员更好的开发工具,这样对于项目进度的推动,其实更有好处。

资产:代码.vs.流程

互联网公司是由人组成的,人是会流动的,有一些小型的公司,往往会因为一两个核心员工的离职,造成整个系统的代码无法看懂,无法修改,从而最后导致公司完蛋。这种糟糕的情况,不止一次的出现过。然而,如果我们能有一套完善的开发流程,或者是习惯,以及配合良好的开发环境,加上有一定质量的代码,是完全能做到把项目代码,在不同程序员之间顺利交接的。可惜我们很多公司管理者,并不重视程序员用什么工具开发软件,也不知道如何去提高代码的可读性,所以造成我们的项目特别害怕人员变动。如果我们把人员变动看成是一个必然会发生的事情,那么我们就会更重视整个代码的开发环境和开发过程,从一开始就把开发规范确定下来,规定使用什么环境,应用何种工具,并且坚持执行,同时在实践过程中不断的改进。只有这样有预备的去做,最后才会保留的住公司真正的资产。

img

一家互联网公司,我们在评估其开发资产的时候,并不应看他“拥有”多少行代码,因为这些代码是无法直接卖钱的。而互联网公司的开发速度,以及这个速度背后的能力才是最重要的。

敏捷开发的意义和实践

敏捷开发是我们现在最常见的一个“开发模式”,然而很多时候,我们看到“敏捷”两个字,似乎就是让程序员多加点班,或者忽略一些过程加快把代码弄出来,而真正理解“敏捷”含义的并不多。实际上,敏捷并不会加快单位代码的开发速度!敏捷最主要的目标,是应对需求不明确和需求变更,而这两者正式互联网服务中最常见的情况。

img

需求变更的原因

在互联网服务中,由于没有直接的“客户”下单要求,所以很多需求,都是由公司内部的人“代表”的,最典型的就是我们的“老板”们了。正式因为没有明确的“下订单”的过程,所以很多传统的需求分析变得没法做了,因为不管是老板还是产品经理,都是面对着成千上万的客户去猜测他们的需求,如果他们自己能代表客户还好,如果猜错了,项目的代码肯定要修改。很多互联网公司都非常重视“数据”,原因就是这些“数据”往往代表了用户对产品的看法,而这些看法成了互联网产品设计的唯一客观标准。然而这些数据本身,会包含了大量复杂性,由于统计方式、产品形态、季节时间等等,都会产生偏差。我们的项目需求,往往就是在这些偏差中确定。这就难免产生需求的变更了。

互联网的客户个体多,服务内容丰富,功能变化快,是互联网项目中需求变更很多的主要原因。因此这也让敏捷开发,成为互联网项目开发中最重要的方法。——敏捷强调的是用原型来验证需求,在互联网服务里就是,尽快推出服务,通过数据来验证想法。如果我们能越频繁的修正原型,就能越快的接近真正的需求,也就是说,如果我们的互联网服务能越快的修正各种问题,同时越快的推出新的版本,就能让用户越牢固的“黏在”这个服务上。

架构设计实体化:单元测试

img

敏捷开发讲究要快速的修改代码,我们往往会发现,代码修改的越频繁,BUG越多,这似乎是一个无法解决的矛盾。然而,在敏捷开发方法论中,有一个重要的措施,就是用来防止这种修改造成的BUG增加的。这就是——单元测试。 单元测试本质上,充当着自动的QA人员的角色,如果我们把所有的设计和需求,都先按单元测试的形式“固化”编写下来,那么我们在修改代码后,就能快速的、自动的、反复的去验证我们的代码有没有问题。如果这些测试足够全面和详细,那么我们是不会担心代码修改导致大量的BUG的,因为单元测试会自动帮我们支出问题所在。一旦我们知道了问题,修正起来反而变成是最简单的事情了。

假如一个项目的代码丢失了,但全面的单元测试都还在,那么要重建这个项目并不困难,因为所有的需求,都被蕴含在这些测试代码中,程序员们几乎不需要去重新啃文档,谈需求,他们只要把代码弄成能通过单元测试就好了。这种需求的“代表物”不但是程序员开发的概念和目标,而且还可以自动的帮程序员去验证他们的实现。所以,如果你要使用敏捷开发,要尝试频繁修改原型,就一定要使用TDD(测试驱动开发),特别是高度重视单元测试的作用。

统一软件设计思路的重要性

曾几何时,我们认为,使用什么语言开发,用结构化编程,还是面向对象编程……这些一般人难以深入理解的事情,都是程序员这伙顽固的家伙的怪癖,基本属于私人喜好的范畴。外人既不应该深入干预,也没办法去影响,因为如果你不识好歹去在这些事情上冒犯程序员,他们随时可能一言不合就辞职。既然我们只需要可以运行的代码,我们为什么冒风险去激怒程序员呢?然而,在互联网服务的开发过程中,代码本身并不是某一个固定的、静态的东西,它需要不断的与时俱进,需要跟随这业务的发展而变化,同时也会从某一个程序员手里,流向整个开发团队。在这种情况下,软件开发习惯、代码的风格、程序的设计思路,就变成一个非常重要的事情了。

代码交流:面向对象

img

确实现在还存在大量的讨论,说“面向对象不是万能的”。说得对,但是,世界上有什么东西是万能的呢?我只能说,在需求变更非常快的情况下,面向对象思想,是现在我们能选择的最好工具了。在“数据结构+算法=程序”的时代,软件主要是以计算任务为主,电脑是为了代替人脑进行超乎想像的运算任务而存在。而在互联网时代,软件主要的任务已经变成了处理这个真实世界的信息了。信息的存储、交换的任务,已经远远超过了“计算”的任务数量。虽然我们知道,所谓的信息处理,最底层还是依赖大量的“计算”,然而,我们的程序员们,早已不再需要编写大量“计算”的代码,我们面临的挑战,是如何用代码准确而快速的表达这个世界。

面向对象思想包括分析、设计、编码三个部分(OOA/OOD/OOP)。这些思想看起来繁文缛节,似乎非常啰嗦。然而,其核心思想却非常简单:从表达过程,转向表达对象。人类的思维中,对象、或物体,是一个个具备自己的信息特征的个体,而行为和过程,往往是依附于这些个体的。比如鸟会飞、账号会锁定、汽车会死火等等。所以如果我们的代码,是以表达对象,把信息和行为统一起来,是最接近于我们的认识规律的。

在互联网开发领域,由于网络无处不在,涉及到的领域异常广泛,如果我们没有一个能把代码世界和现实世界联系的纽带,我们的项目将非常难以理解。——难以理解的项目,就难以变化,从而就失去了互联网最显著的特征。所以我认为,面向对象的思想,是每一个互联网开发人员都应该理解的,并且应该是面对大部分业务时,首先考虑选择的。

代码架构与重构

我见过无数的代码架构图,里面画满了进程和服务器的拓扑,各种线条上标注了通讯协议,编码格式,还有各种流程图和协作图,然而,这些架构设计,无一例外的对于需求变更毫无帮助。因为它们描述的是一种现状,甚至连现状都不是,只是一种猜测,一种关于现状的猜测。随着项目代码的不断变化,代码数量和关系都会膨胀,这种进程、通讯级别的结构,除了越来越复杂以外,根本对于指导项目如何应对各种“代码腐化”毫无用处。

因此我们想到了流行的“重构”,然而,如果我们只是重构进程的关系,通信的层次,那些错综复杂的代码调用关系一样存在。各种回调、事件、耦合还是让代码无法理解。我们只是在试图把混乱塞到一些瓶子里面,并没有解决混乱本身。所以,我们需要的另外一个思想武器:代码结构。只有我们从另外一个角度,另外一个视图去观察代码,才能把握代码之间耦合的情况。正如建筑里的平面图和立面图,都是不可或缺的。

img

所以我们应该高度重视“代码架构”,也就是描述代码之间的关系的架构,而不是进程之间的关系的架构。在关注代码互相调用、耦合的关系上,我们能把混乱复杂的代码关系理清,整理出一个便于理解,便于修改的代码外观。这些工作看起来完全是针对开发人员的,但是实际上,这些工作是能提高整个开发效率的。它能让代码从难以修改,变得容易修改,从而得以支持快速的业务需求变化,这是对业务、对产品最重要的支持能力。

持续集成的意义和实践

不管是敏捷开发的快速迭代,还是重构系统,我们都将频繁的编译代码、部署、测试,也就是所谓的集成。如果我们的系统集成效率太低,那么快速的迭代可能变成慢速的迭代,重构系统的频率也会大大降低。有一些项目,每一次集成,都要最少经历两三个小时,如果不顺利的话,搞一个通宵都未必能完成。“发版本”是很多程序员和运维管理人员的常见加班原因。对于这个问题,很多小型公司开始的时候,并没有给与足够的重视,认为这些事情不过是程序员或者运维的本分工作之一,也是最日常的工作。真正得到出问题了,才发现重要性。

在任何一个互联网应用业务中,我们都会需要“发版”:出新功能、修改BUG、启动运营活动、甚至是机房搬迁。所有的这些,如果没有一套合适的工具来保障,每次发版都会是一场噩梦。所以持续集成(CI),很自然的成为互联网企业中最流行的、研究最广泛的技术之一。

所有资产纳入版本管理

持续集成的所有东西,都应该来源于版本管理系统(SVN/Git)。除此之外,软件资产不应该存放在任何其他地方。版本管理系统应该是开发团队的保险箱和金库,除了代码以外,所有的数据文件,配置,脚本,文档,都应该放入这个保险库。由于版本管理系统可以追溯到任何一个是时间点,这可以让故障恢复,问题回溯有良好的支持。

img

关于源代码使用版本管理系统,已经有很长历史了。但是互联网服务中,除了代码,还有很多其他的资源,比如图片、数据、脚本等等。除了产品项目外,我们的很多额外系统,比如运维工具、产品文档等等,都是需要妥善保管的,这些也都应该存放到版本管理系统中。

一般现在的版本管理系统,都有“分支”的功能,简单来说就是类似于“拷贝”了一份新的资源出来,在这之上的修改,可以由我们选择合并到其他分支或者放弃。所以SVN的常用方案,是启动三个类型的分支:trunk/branch/tag,专门针对“测试”、“开发”、“运营”。如果我们按预定的分支模型来设计版本管理系统的使用,那么我们的持续集成就可以很细致的选择集成哪一个版本的内容。

而在Git里面,每个使用者,都可以拥有自己的资源库,这对于开发测试可以更加的灵活,但是对于使用者的要求更高一些:在不同的资源库合并的过程中,需要更好的版本管理策略。持续集成系统可以自己拥有一个或者多个Git资源库,这样他们可以完全脱离版本管理服务器来独立运行。

自动化部署

我们曾经无数次的登录服务器,无数次的拷贝文件,无数次的修改配置,无数次的导入数据到数据库,无数次的……如果我们对这些重复,而且容易出错的工作熟视无睹,我们将永远的被这些本该机器去做的事情困住。 自动化部署,是整个持续集成工作中最重要的步骤。当我们每次发版都要很仔细的修改很多文件的时候,我们是无法避免在某次倒霉的事故后被挨批的。只有我们能把部署工作,也用我们的开发能力去解决,编写自动部署工具之后,我们才真正的能提升部署这个事情到一个新的台阶————我们终于可不再担心发版。

img

和自动化测试一样,自动部署脚本,也是把一系列的技术需求,从纸面文档+人手处理,改成用代码实体化,并且可积累改善的方法。自动化部署工具在开源界也非常热门,比如jekins,还有chef等等,都是为了解决部署问题而发明的软件工具。也许对于你来说,自己用bash开发一套脚本才是合乎你的品味,但是不管怎样,一定要有这样的工具。就算要花费较长的开发时间,调动项目开发的程序员,一起来认真的开发一段时间自动部署功能,都是非常值得的。因为从今以后,你就可以拥有一个自己的部署系统,这个系统不但可以积累你的运营部署经验,还能加入很多错误、故障的自动检查,让你不再需要导出找“永远不出错的”运维人员。

自动化部署系统中,最核心的部分就是配置管理。拥有一个对现有环境资源集中管理的数据仓库是非常重要的。如果每个你的脚本可以识别自己所在的环境,以主动的方式去“申请”自己的配置文件和安装任务,是非常好的一个模式。因为从一个节点主动去分发程序,比不上多个节点向中心集群请求部署任务,来的更容易稳定。因为在节点上的部署代理程序,能更准确的知道自己环境的情况,也可以做本地的测试。

自动化集成测试

前面曾经说过,敏捷开发非常依赖于自动化的单元测试。实际上持续集成,也非常依赖于自动化的集成测试。集成测试可以把自动化部署的结果进行检验,避免手工进行反复验证。如果只有自动化部署,而没有自动化测试,那么集成工作,其实还是非常浪费人力的。更重要的是,我们在每次“发版本”之后,总会担心新的修改,导致一些旧的功能失效。这种问题实际上是很常见的,如果无法自动化的做这种回归性的测试,那么我们每次发版还是要忍受漫长的测试工作进度。

img

自动化集成测试也有很多开源的工具可供选择,特别是基于B/S模式开发的WEB程序,但如果是手机APP的项目,或者客户端C/S程序(比如网络游戏),对于这类服务器系统的集成测试,往往需要我们自己根据业务来编写测试程序。对于服务器系统来说,一般我们针对其通信协议编写测试程序即可,而对于客户端系统,如果是GUI系统的,我们还可以根据GUI的内部调度命令(安卓就有这样的套件)来测试,但如果是类似游戏这类业务,就只能用图形识别技术了。

在持续集成的流程中,集成测试往往是最后一步的检验关口。如果集成测试失败,应该给所有关注集成的人员发送警报(实际上,如果成功也应该报告)。现在企业往往会用邮件、IM、微信、短信或者别的一些东西接收这种消息。

DevOps的意义和实践

在互联网企业初始的阶段,运维工作往往是服务器端开发人员兼任的。当我在承担这种既是开发又是运维的工作时,往往非常羡慕那些“开发、运维分离”的公司。因为作为开发人员,没有三班倒的值班备份人力,往往是7X24小时的待命状态,工作压力非常大。然而,当我自己参与到一些真正开发、运维分离的项目的时候,却发现,项目运营事故中,最少有70%的事故,是由运维的原因造成的。

除了常见的硬件、网络故障,操作系统配置出错,日志清理出问题,部署配置搞错,进程不小心杀掉等等都出现过。看来服务器端开发和运维还真是难解难分,而DevOps的思想,就是为了努力解决这种矛盾。我们不应该再把开发和运维对立起来,而应该认识到,运维是开发的一种延续,运维的需求也是服务器端系统的功能需求;运维是开发的目地,便利的、通用的运维工具,本身是能提高开发效率的一种专业产品。

运维与开发的一体性:运维、运营、QA

img

可以把DevOps看作开发(软件工程)、技术运营和质量保障(QA)三者的交集

一个互联网软件的上线运营,往往是由开发人员编写出来,然后经过QA人员测试,最后放在运营环境里进行运营。这个过程并非是单向的过程,基于前文说的,互联网服务都是在反复修改迭代中完善的,所以项目本身,一定是由多个版本,反复在开发、QA、运维之间循环交接。举例来说,一个网络游戏,在第一次开发出来后,都会经过比较仔细的QA测试,然后通过运维人员进行上线部署,最后由运营推广人员进行宣传,同时也要配合这些宣传开启游戏内部的一些功能,客服人员也会在开始运营后参与进来,除了提供客户咨询外,抓作弊玩家和封帐号也会持续进行。而作为开发人员的游戏策划,立刻会关注游戏系统的各种统计数据,以期在下一个版本中改善游戏设计。这个过程,可以看到在产品开发出来之后,整个团队几乎都还是需要以各种方式“使用”此服务器端系统的。所以我们在开发互联网服务的时候,不能仅仅面向互联网上的一般用户,同时也需要考虑整个开发团队的使用需求。

现代的互联网软件系统往往都带有服务器端部分。而这些服务器程序需要7X24运行,因此产生了两类非常明显的需求:

  • 运维需求:这类需求往往表现为非功能性需求,它要求服务器程序能够适应大规模用户访问和持续稳定运行。
  • 运营需求:这里需求通常是功能性需求,因为产品上线后,产品和运营、客服、测试人员,还需要持续不断的使用这个系统,和互联网的海量用户进行互动。

运营:客服、活动

在互联网服务中,运营是一个非常重要的环节。客户除了直接使用互联网软件的功能外,背后其实往往还有大量的从业人员在通过这个软件提供服务。

其中最常见的就是客服服务。客服往往最需要的是查询功能————能够查到系统中特定用户的使用数据,从而协助客户解决问题。客服的另外一个主要工作,是封帐号和封IP。现在互联网黑色产业链非常庞大,互联网企业保护自己的手段其实不多,而客服是其中一个重要的环节,避免黑色产业侵袭自己的利益,就需要互联网服务系统有人工干预其数据的能力。

运营互联网服务另外一个常见的行为就是“活动”,也就是开放一些限时的服务。就和超市一样,互联网服务也要定时或不定时的加入或关闭一些特别的服务。这些工作非常细致和琐碎,需要服务器系统能够提供人工参与或者机器定时启动的一些功能。在《魔兽世界》这个网游中,大部分的活动都是自动的和定时的,可以从游戏里的一个日历功能查到。而在国产的互联网产品中,的很多是临时加入,需要人工维护的,如“双十一购物节”这种。这些对于服务器系统的版本更新,功能修改,都提出了更高的要求。

img

因此一般我们在设计互联网服务系统的时候,就应该一开始就把运营需求,也作为版本目标纳入开发计划中。一些比较好的团队,会抽象和总结同类互联网项目(比如游戏、电商类型)在客服、运营活动上的共性,形成一套标准的服务规范以及实现这个规范的接口。由互联网服务开发团队去实现这些规范的接口,提供功能上的支持,而另外一个运营开发小组,则负责根据这个接口,开发供运营团队人员使用的界面、内部管理系统等。比如游戏的运营规范会要求游戏提供查询角色区服、帐号的名字、等级等数据,提供接口在游戏中发布任务;电商系统的运营规范会要求网店提供本店销售排行查询、优惠券折扣接口等等。

运维:部署(虚拟机)、监控、统计

作为非功能性的需求来说,部署需求是第一位的。频繁的部署是互联网服务快速演变的基础能力。另外,互联网用户的增加(和消退)也是非常迅速的,这导致了我们可能需要快速的进行服务器扩容,或者缩容。这种情况都需要涉及到部署。所以我们在开发服务器系统的时候,部署需求是第一个需要考虑。加上如果我们希望实行持续集成,那么就更加需要重视部署的能力。作为服务器端系统,如果被设计成带有非常复杂的进程种类和进程通讯关系的话,要做好部署就会变得更加复杂。加上可能部署的环境还不统一,可能出现的问题就更复杂了。所以现在有大量的技术尝试改善这个方面。首先被大家广泛接受的是虚拟机技术,也就是所谓云服务器(IAAS),这种技术能让你无需直接操作硬件,不用扛机器到机房来进行部署,是一种巨大的进步。

而后现在我们有了Docker这种基于Linux容器技术的工具,这可以把服务器操作系统层的差异环境,都统一成一个个image文件,部署的时候只要运行image文件即可。但是这些依然无法简化错综复杂的服务器进程关系,所以现在有了各种“队列服务”技术,比如Kafka,RabbitMQ, ActiveMQ等等,这些队列服务把进程间通讯简化成专门的服务,减少了部署的复杂性。而ZooKeeper的广泛使用,让我们在多进程间协调和监控有了更多的手段。在具体部署工具方面,Chef这一类软件做了各种有益的尝试,这些都是能让我们优化部署需求功能的工具。

img

互联网服务的24X7持续服务能力,实际上会收到各种挑战,除了版本发布可能导致的问题外,在大量机器硬件里面,硬件故障率是一个固定的比例。网络抖动,机房线路故障也常常会出现。更容易出现的是异常的用户访问波动:一大波用户汹涌而来,但是也有可能是DDOS攻击。不管怎样,你都需要随时掌握服务器系统的工作状态。这时你就需要一个监控系统,但如果产品上线才发现要做,那往往已经很迟了。因为一个系统是否有问题,并不是简单的从内存、CPU、网卡流量就能看出端倪的,我们往往需要在服务开发之初,就定义好各种需要监控的指标,传统常见的指标有:每秒主循环的次数、每秒处理业务包的次数、服务器中缓存的会话数等等……一些做的好的系统,还会有很多业务层面的监控指标,比如某个特定服务的处理效率、处理成功率等等。

既然一个系统有大量的监控指标,就涉及如何生成和管理这些数据的问题。传统的做法是在系统中“埋入”这些监控程序,系统一边运行一边统计这些指标,然后定时生成日志或者通过网络上报给某个监控系统。但是这种做法的缺点是:如果你需要更多的指标,或者修改指标的统计方法,你就被迫要修改代码,重启服务,这样会影响正在运行的服务。现在另外一个做法是,由系统把运行的原始信息记录成日志,然后把日志集中上报到一个监控系统中,这个监控系统一般都带有分布式的文件存储系统和分布式计算统计能力。在搜集到大量实时日志的同时,这个系统根据预设的指标统计方法,不停的进行日志统计,一旦发现统计结果有问题,就会报警。而这种统计由于是在大数据处理能力的平台上生成的,所以往往发现问题的时间差能缩小到分钟级甚至秒级。这种做法由于搜集的是原始日志记录,所以就可以灵活的在系统运行时定制很多统计和报警的策略,但完全不会增加服务系统的压力,也不需要修改服务系统的代码。

img

最后说说统计,任何一个互联网系统,都是在用户的使用中不断优化的,这个优化的依据,最重要的客观依据,就是统计数据。而统计数据,一般由两部分构成:

  1. 用户的行为数据。比如登录行为,就可以给系统留下用户的IP、登录时间、登出时间等数据;购买行为,就可以留下购买商品,购买价格,购买时间这些数据。
  2. 根据用户的行为的关联,统计出来的数据。比如根据登录行为,我们可以统计出用户的在线时长,用户重复登录的次数,用户重复登录的间隔,还有什么次日存留、七天存留等等……;根据购买行为,我们更是可以整理出用户的购买商品倾向,ARPU值,甚至同类用户的购买共性,这些也是所谓大数据做商品统计的主要方向。

根据上面的分析,我们可以发现,实际上统计系统也是应该分两个部分设计,一个是尽量记录用户行为的基础数据,第二个是以复杂多变的统计条件,去挖掘这些用户行为数据中包含的规律。对于第一部分,一个可以存放海量日志数据的分布式存储系统非常重要;对于第二部分,分布式的统计运算系统是必不可少的。对于这个体系,Google的Hadoop提供了业界的示范。但是如果你愿意,也可以使用这个思路自己来建设自己的统计系统,也许你的数据量无需要用到Hadoop那么复杂。

总结

互联网开发模式,是针对于互联网本质上是一个“服务”而发展起来的。因为是“服务”而不是产品,所以应对快速变化的能力是最高的技术标准。我们倾向采用更适合表达需求的软件开发技术、自动化程度更高的开发工具,来提高我们的开发效率,而不是靠单纯的“激励主观能动性”来做管理。

因此我们在基于自动化测试、自动化部署等持续集成工具的平台上,使用重视原型迭代的方法来开发项目,在反复以原型确认需求,以及适应需求变化的过程中,逐步的完善整个开发生产线。并且把开发和运营视为一个整体,在服务的运营过程中,不断的完善互联网服务的运营工具,让开发和运营在同一个生命周期里生长。

此文已由作者授权腾讯云+社区在各渠道发布

获取更多新鲜技术干货,可以关注我们腾讯云技术社区-云加社区官方号及知乎机构号


腾讯云开发者
21.9k 声望17.3k 粉丝