• Feeds

  • 开发效率与系统稳定性杂谈

    在互联网系统中,开发效率与系统稳定性与产品成败非常相关。开发效率在一定程度反映了团队的执行力,快速开发能力带来了产品的竞争优势。系统稳定性(包括安全及性能等)则是产品的后防线,稍有失误则会给产品带来很大伤害。因此开发效率与系统稳定性是衡量互联网系统开发成熟度最重要的两个指标。

    在软件开发周期不同阶段,这两者如何控制?

    在需求阶段,对开发效率的影响常见的是沟通理解偏差带来的技术风险,之外最常见的还有需求变更的风险。后者大多是来自市场环境的变化作出调整,技术主管更多的是积极心态去应对。但对前者沟通理解偏差导致效率问题也不罕见,更值得警惕。

    在技术设计阶段最大的风险是技术方案,找个无需多讲,考验团队的架构能力以及对当前系统的驾驭程度。

    开发阶段最大的风险是单元测试不到位或缺失。很多号称“敏捷”型项目依赖在线上测试及修改,当模块增多后,这样代码健壮性就会变得比较脆弱,不少团队也会越走越慢。

    Review阶段风险是简洁性及性能。除了压力测试能达标之外,警惕那些不易懂的代码,这些代码将来会成为事故多发地带。

    部署阶段最大的风险是上线计划把控,上线过程中操作错误的情况并不罕见,如去年Amazon EC2的故障就是由于操作失误造成。

    从宏观看来,技术方案的风险最大,由于模块很多,具有丰富经验的高手不可能参与每一个环节,这就会出现木桶的短板效应,架构师认为不重要的地方总是会出问题。给用户体验造成极大伤害。

    另外还有团队文化的风险。大部分团队很难形成书面交流的习惯。口头沟通需求、讨论方案对创业团队非常适合。在团队变大之后,这样的习惯会造成信息流动障碍,可能会给工作效率带来更多负面问题。同时大部分团队也对流程、模板、规范缺乏了解与重视,过多依赖参与人的内部驱动力及能力,无法依靠制度与流程来取胜。

    服务管理框架的尝试

    大型软件系统开发需要模块化,在分布式系统中,模块化通常是将功能分成不同的远程服务(RPC)来实现。比如可以用Java RMI、Web Service、Facebook开源的Thrift等一些技术。同样,在一个大型系统中,服务化之后服务的可维护、可管理、可监控以及高可用、负载均衡等因素同服务本身同样重要。

    服务管理目前并无直接解决方案,Thrift作者Mark Slee提到

    It’s also possible to use Thrift to actually build a services management tool. i.e. have a central Thrift service that can be queried to find out information about which hosts are running which services. We have done this internally, and would share more details or open source it, but it’s a bit too particular to the way our network is set up and how we cache data. The gist of it, though, is that you have a highly available meta-service that you use to configure your actual application server/clients.

    Source: [Thrift] Handling failover and high availability with thriftservices

    如果开发一个自己的服务管理框架,需要具备以下功能

    • 快速失败,这个在本厂意义重大,很多远程服务调用是在关键路径中,它可以容忍失败,但是不能容忍堵塞
    • failover,客户端failover支持,并支持自动失效探测及恢复调用
    • 中心化配置及推送功能,所有client在同一时刻配置的一致性,并且client会跟配置中心保持长连
    • 负载均衡策略:支持round robin,least active, consistent hash,或者基于脚本的动态路由策略。这个都是由配置中心来控制
    • 动态启用及停用服务及节点:可以动态启动及停用服务(热发布),由于有推送功能,相对容易实现
    • 跨语言:支持client能使用常见主流语言来访问
    • 版本管理:同一服务可以有不同的版本并存
    • 访问统计及动态运行参数查看:可以对方法级别进行访问统计及实时观察

    访问策略

    服务框架倾向于直连的方案,即client是直接连接server,而不会增加中间物理上的代理层,服务框架只做中心配置、访问策略、服务发现、配置通知等职责。

    路由的特殊需求

    通常的服务访问,使用上述round robin等3种策略即可,但是在实际工程实践中,我们发现有些不同的需求。比如计数这样的远程服务,读操作可随机访问一台远程节点,但写操作需要访问所有的服务节点才能实现。因此我们需要有广播式的访问需求。由于计数服务对实时性和一致性要求较高,不适合采用异步如Pub/Sub这样方式去实现,因此在client还需要支持同步的广播调用。

    耦合及侵入的矛盾

    在设计服务管理系统之前,我们希望不跟一种具体的技术(如Thrift)绑定,比如client和server服务实现方不需要太多关心底层技术。但是在实际实现过程中碰到不少矛盾。

    IDL侵入

    在使用Thrift之后服务实现很难绕过Thrift IDL,使用方需要自己维护IDL以及Thrift生成的代码,服务框架支持将Thrift服务注册到配置系统中。虽然也可以绕过IDL来实现服务,但是框架相关功能的实现和维护成本比较高。

    RPC框架的侵入

    Thrift Transport可以使用TCP(Socket)或者是HTTP
    这个也是非常好的特性,在某些情况Transport使用HTTP会带来很多便利,使用HTTP虽然有一些额外开销,但是HTTP的周边配套设施的完善足够抵消这种开销。使用TCP很多状态实时监控都需要服务系统从头做起。

    Thrift的Version与服务的version存在一定的重复
    服务牵涉到版本管理,我们希望通过发现服务来管理,但是Thrift本身也有版本的设计。

    这些矛盾的本质就是服务框架需要的一些功能是自己实现还是依赖Thrift来实现,很多Thrift使用方如Twitter rpc-client干脆就直接在Thrift框架基础上增强。

    虽然存在上述一些待解决问题,厂内第一个使用服务框架管理的服务即将上线,很快每天会有数十亿的调用将会在此之上产生,同时也会有新的挑战出现。


    Figure 1: Facebook Service Management Console
    (来源:http://www.slideshare.net/adityaagarwal/qcon Slide 27)

    《Erlang编程指南》读后感

    “Single core architecture has been inefficient for 10 years”

    在云时代,我们需要有更好的能利用多核功能及分布式能力的编程语言,Erlang在这方面具有天生的优势,因此我们始终对它保持强烈关注。

    按:此为客座文章,投稿人为新浪微博基础研发工程师赵鹏城(http://weibo.com/iamzpc),以下为原文。

    在对一个分布式KV存储系统的研究过程中,我有幸遇到了Erlang语言。因此,我研究工作的第一目标就是快速入门Erlang语言并在实际研究过程中进一步深入理解Erlang的精髓。在为数不多的Erlang中文书籍,我选择了《Erlang编程指南》一书。

    首先,我认为此书是一本值得推荐的Erlang入门书籍。第一章的讲解把一头雾水的Erlang门外汉快速带入了Erlang文化中,从中我了解了Erlang的历史、特性及为什么要使用Erlang,还了解了几个Erlang案例,让我对Erlang的兴趣大增。接下来的第二章到第十一章是Erlang的基础部分,从中我学习到了Erlang的基础数据类型,顺序和并发编程及其进程设计模式,在我读membase中的ns_server的过程中,大部分知识点都得到了充分的验证,尤其是Erlang的函数是编程思想和进程设计模式,让我清晰快速的了解了ns_server的基础流程。

    其次,我认为此书是一本非常全面和深入的Erlang高级参考手册。在我研究ns_server的过程中,遇到了OTP行为包的使用问题,通过behaviour关键字,我快速定位到了本书的第十二章,第十二章对OTP的原理和使用进行详细的介绍,让我在实践中快速的理清了思路,深刻体会了Erlang在分布式和并发开发上的便捷。在进一步的实践中,我还遇到了Mnesia数据库的问题,此书用专门一章的内容详细阐述了Mnesia的知识,大大提高了我的研究效率。

    总之,此书是一本既适合入门学习又适合开发中参考的Erlang权威书籍。

    虽然此书如此优秀,但是还是有一些不足的,主要体现在个别中文翻译上,包括名词和一些语句的翻译,着实有些不易理解,望日后能够重新酌定。