本文于2015年底完成,发布在个人博客网站上,标题为《项目总结–纪念我参与过的IPTV SQM项目》。
考虑个人博客因某种原因无法修复,于是在博客园安家,之前发布的文章逐步搬迁过来。


时间很快,离开SQM团队已接近10个月,对于参与了5年的项目,很早就想写些什么来纪念;现在终于找到了时间,用自己半生不熟的语言,站在自己的视角来回顾这个项目的历程。


10年,项目伊始

在先前的移动数据业务SQM项目努力坚持了两年之后,领导为我们找到了新的归宿,与IPTV产品联合开发新的SQM产品,名字为IPTV SQM。

IPTV SQM并不是新名词,在与我们项目组联合之前,IPTV已投入人力试水了一年多,但效果不佳,公司内外均无法得到认可;而我们项目组彼时陷入困境,原有的SQM产品辛苦研发两年仍然无法上市,虽说积累了很多经验,但无法变现,从领导到项目组充满了悲观的情绪;因此双方的合作可谓是一拍即合,IPTV可以利用我们的人力和经验来扩展思路,而我们则需要他们的经费来解决团队的生存问题。

双方的领导对这个项目寄予厚望,因此研发资源的投入有了保证,我们项目组出人,而IPTV则出经费。在联合开发团队组建之后,团队规模膨胀到40人左右,我们项目组重新恢复了生气。

当然现实是骨感的,出于各种原因,第一个版本从5月份启动,10月份才完成发布验收,中间磕绊无数,项目组顶住上层领导的压力,终于坚持了下来,迈出了切换产品之后的第一步。

第二个版本也在年底前发布,并在一线某局点成功上线,项目组上下充满了乐观的情绪。

本年度发布了C20、C21版本。

重要工作编译、打包脚本

这个责无旁贷,反正前两年也是我自己在维护Ant脚本。

系统安装脚本

安装盘无疑是很重要的,没有安装盘,测试团队怎么准备环境呢?于是我就开心的背上了这个包裹,直到后来进入项目的旺叔自告奋勇承担起相关的工作。

不过我有自知之明,我写shell的能力只能勉强算是让及格,第一个版本的安装盘脚本其实问题很多。好在后来加入项目组的旺叔同学在shell方面很牛,现在看来,安装盘脚本交给他开发算是选对了人。在后来项目开发过程中,从他那边学到了很多高大上的技巧,在他的指导下,我的shell开发能力有了相当的提升,不过这些都是后话。

mina版本升级

项目初始启动时,基础平台使用的是mina 1.x版本。

后来基础平台发布了新的版本,相比于项目组使用的老版本,新版本提供了更多的特性,界面UI做了美化;于是领导决策我们项目基于新的基础平台来交付项目;但新版本的基础平台使用了mina 2.0.x版本,为了使用新平台,于是我们修改已开发好的通信层的代码,适配升级后的mina。

好在mina官方的文档比较全面,切换版本时并没有花太多时间,也没有给后续开发引入太多的坑。

消息交互图的设计和开发

这个特性比较可怜,第一个版本开发并通过测试验证,但没和底层部件联调;第二个版本和底层部件做验证过程中,测试人员发现底层部件的性能完全不达标,为了让版本按照GA,这个特性被领导一票否决,于是这个特性还未在一线应用,即被砍掉了。

11年,痛并快乐

随着我们研发的IPTV SQM版本开始在国内、海外成功试点,来自一线的需求像雪片一样纷至沓来。项目组的压力陡然猛增,但好在双方领导对项目的关注不减,投入不变,因此压力还在可控范围内。

本年度发布了C22、C23、C25、C26版本。

重要的工作界面UI规范的整理

前期研发节奏过快导致的问题逐步暴露出来,如UI界面设计不良、实现不合理等作为其中的代表,被一线和各级领导诟病。联合开发团队的上层领导经过几次讨论之后,双方达成共识,同意投入专门的资源来优化UI,而我作为主力成员参与其中。

UI规范包括很多内容,比如配色、控件的样式、线条的样式、控件之间的间距、界面布局等。

对于BS项目来说,整理界面的UI规范并不困难,因为公司的BS界面规范是现成的,项目组只需要遵循即可。但公司缺少CS的界面规范,而我们项目组恰巧基于Java Swing技术来构建C端界面,因此在整理界面规范时,美工其实没有多少现成经验可以借鉴,而我在应用Swing来构建界面方面其实是一知半解。因此在整理规范工作的前期,我们双方合作其实并不愉快,进度也很缓慢。好在美工MM非常有经验,并且非常有耐心;而我也在美工不断的鼓励之下,终于摸清楚了Java Look&Feel定制的门路,规范整理工作很快步上了正轨。

这里引用下那位美工MM的名讳,周翠兰,在写本文的时候她早已从公司离职了,希望MM天天快乐。

界面基础组件和使用样例的开发

规范输出了,但没有样例的话,是无法落地实施的,所以在规范制订的后期,我把主要精力放在了基础组件和使用样例的开发上。主要工作包括色彩、字体、UI属性、边框对象的加载和配置,主要应用了js和jython脚本来实现前述资源的配置。

UI界面整改

事后计算,我独自一人完成了70%的界面的整改,并且指导项目组成员完成其余30%的界面的优化。老实说,非常有成就感,但确实把我累的够呛,中间踩了不少基础平台和烂代码的坑。当然积累了很多界面布局的经验,比如界面的实现方案是否合理,界面的样式对不对,间距合不合理,我瞄一眼就晓得有没有问题以及问题在哪里。

C端性能优化

优化的背景,一线使用人员投诉客户端存在两个影响体验的问题:

  1. 低网速场景下,比如运维人员在家里使用客户端,客户端刷新数据非常慢,执行操作需要等很长时间,而且经常会失败;
  2. 在笔记本上运行时,响应不及时,经常假死。

经过实验室重现,以及代码走读,很快找到了问题所在。


对于问题1,经分析有如下原因:

  • 客户端与服务器交互数据过程中,向服务端传递了很多无意义、不必要的信息,导致占用了过多的上行带宽,有时还会导致交互超时。这里要科普一点小常识,运营商提供给个人用户使用的宽带套餐有个特点,上行带宽要远小于下行带宽。这样的设置是有道理的,原因是运营商的用户在使用家庭宽带时,一般以浏览网页、聊天、看视频为主,因而下行流量要远大于上行的流量。
  • 服务端在向客户端返回了非常多的数据,但只有很少的一部分会在界面上默认呈现,因此大部分数据默认情况操作人员是看不到的。据此现象与业务SE沟通后了解到,当前界面上默认呈现的字段已经可以解决80%的问题,其余非呈现的字段对于20%的问题来说意义不大;退一步讲,假如在界面呈现那些字段,对于操作人员来反而会造成不必要的困扰。原因是那些未在界面上默认呈现的字段的含义和关系非常复杂,非专业人士理解起来很困难。
  • 服务端侧未缓存客户端需要的数据。客户端下发获取数据的请求给服务端后,服务端直接从数据库加载数据、并返回客户端;此外,客户端实现了定时加载数据的行为,操作员只要打开客户端,就会有源源不断的数据获取的请求下发到服务端。从实际测试看,单个客户端发起的数据获取请求并不会影响到服务端和数据库正常运行,但是当足够多的操作员登录到系统后,数据库的压力就会越来越大,直接导致部分查询请求的响应不及时,影响用户的体验。

解决策略:

  • 对于原因一,我们调整了底层的通信实现,消除了冗余数据的传递。
  • 对于原因二,动作相对要大一些,调整了数据通信传递的对象,删除了不必要的字段,而界面也做了大规模的优化,将不必要的字段从界面上清理掉;这带来了额外的好处,客户端的内存占用有了一定的下降,对运行效率有一定作用。
  • 对于原因三,在服务端设计、实现了缓存特性,将一些常用的数据缓存起来供客户端访问,避免获取数据的请求直接透传给数据库。好消息是数据库压力下降,稳定性提升;坏消息是服务器端占用的内存上了,在部署时需要申请更大的内存。

对于问题2,经分析有如下原因:

  • C端代码在UI线程里执行了过多的复杂或者耗时的操作。比较典型的有:
    • 在两个ArrayList对象中查找,求出相同的部分。开发人员在实现功能时使用了两层for循环来分析遍历列表,依据算法分析理论其实现复杂度为O(n^2)。由于两个列表内有约1000个对象,导致最终的循环次数接近百万,无端占用了大量的CPU时间。
    • 在循环中反复与服务端发起交互。比如在某张报表页面呈现数据时,由于需要依据服务端的某个开关做差异化处理,开发人员在遍历数据的循环中插入了与服务端交互的代码;在平时的测试过程中由于数据量比较小,少量调用引入的延迟不明显;但在部署到局点之后,数据量要远大于实验室测试,因此问题就暴露出来了。
  • C端运行时输出了大量的调试日志。

解决策略:

  • 对于原因一,解决的方法很简单:

    1. 通过走读代码,寻找UI线程中与服务端发生交互的代码,重构实现,将相关操作从UI线程中全部抽取到SwingWorker后台线程的回调方法内;
    2. 使用JProfile工具监控客户端的运行情况,寻找漏网之鱼;对于那些耗时的方法,经分析后如确认是实现问题,则安排优化。
  • 对于原因二,调整客户端的日志配置文件,在发布版本中关闭调试日志的输出。


优化整改的工作量很大,但合作团队很配合,所以一线反馈的问题很快得到了解决,而年轻的合作团队从中得到了快速的成长。

而我则有如下收获:

  • 输出了C端性能开发和分析的规范,指导团队进行后续的开发;
  • 总结了SwingWorker的使用场景和使用方法,避免误用;
  • 积累了JProfile的使用经验;

告警模块的设计和开发

这个模块功能比较独立,时间和进度非常紧张,我认领了服务端的全部设计和开发任务。

当时考虑到要支持动态查询,为降低C端实现的复杂度,同时降低对后端DB的查询压力,因此应用了内存数据库H2来缓存数据,既避免了对后端DB的查询压力,又提供了动态查询的特性。当然应用新技术是有代价的,为了定位一个概率重现的问题,我在办公室里守了通宵,终于在天快亮的时候找到了问题所在,赶在版本转集成测试前消除了Bug。

值得骄傲的是,当时设计的代码框架表现非常稳定,性能表现良好,虽然扩展性稍有欠缺,但直至今日,这套设计和代码实现仍然在发挥余热。

JVM内存参数优化

版本在全球第一大局点上线之后,用户数量快速上升,系统启动脚本中默认的内存参数无法胜任现场的要求,应用频繁出现启动失败、内存溢出或者GC导致的卡死现象。

为解决这类问题,我参照网上重多资源,恶补了一把JVM内存参数的知识,同时结合实验室内的测试情况,输出了第一版的JVM内存参数。在这个版本上线后,应用在一线运行的表现就稳定多了。以现在的眼光看来,当时的JVM参数存在很多问题,还需要大量的分析的调整。

12年,危机初起

经过两年的辛苦开发,SQM项目进入了平稳运转的阶段,需求数目变少,试点项目变少,外部对SQM开发团队的关注度下降,双方的领导各自有了新的想法,对联合开发项目的投入逐渐下降。

一来二去,导致合作团队的员工大量流失,损失了很多优秀的开发人员;到年中,项目经理干脆只保留了测试人员,释放掉了全部的合作开发人员。

但变动并未停止,且愈演愈烈,项目组的自有人力也在不停的流失开发人员:

  • 郭靖为了媳妇去了苏州;
  • 姜山寻求更大的发展去合资公司做交付项目管理;
  • 唐丹丹离职去了新公司。

好消息是,我结婚了,并于年底迎来了宝宝,在人生的新起点重新启航。

本年度发布了C27、C28、C29、C30版本。

重要的工作客户端拓扑数据加载方案的优化

一举解决了客户端加载拓扑数据之后,内存占用过高、CPU占用过高的问题,同时消除了历史代码中的Bug,极大的改善了用户体验。

客户端原来的实现方案中,要把全部拓扑数据加载至内存,并全部转换为适合界面控件使用的对象,在这个过程中需要耗费大量的内存。根据测算和实地验证,可以确认拓扑数据在内存里占用的内存并不大,占用内存的大户是转换成控件对象的数据。因此改进思路很明确,客户端加载到拓扑数据之后,按需将界面呈现需要的数据转换为控件需要的对象。按照这个思路进行优化,客户端的内存优化瞬间有了明显下降,界面的操作重新恢复了轻快感。

服务端拓扑数据同步方案的优化

解决数据传递过程冗余、代码实现复杂、可靠性低的问题。

另外使用jstack和top,配合解决了几个在一线和实验室测试时发现的服务端运行卡顿的问题。

JVM内存参数的继续优化

随着理解的加深,配合测试情况,逐步优化JVM的参数,改善应用的表现。

过程相对乏味,老实说,真心不如写代码开心。

Oracle优化

主要工作是两件事情,一是表分析参数的调整,二是索引的分析和优化。在这个过程中,从SE陈凯那边偷学到了AWR的使用方法。

13年,危机爆发

转眼间IPTV SQM的联合研发进入了第四个年头,联合开发团队的矛盾终于爆发。

  • 双方的领导在人力投入、合作模式、费用结算上出现了更大的分歧。
  • IPTV SQM在一线应用情况出现了问题,新开发的部件无法在一线上线使用,多个发布版本无法在局点上线,SQM的应用效果大打折扣。

领导对SQM的关注在下降,资源投入随之下降,而作为项目组却毫无办法。
本年度发布了C40、C50、C60、C70版本。
施健离职,参与创业团队,项目组损失了一员大将。

重要工作代码静态检查整改

公司的要求是,Findbugs、CheckStyle、PMD三类检查问题清零,圈复杂度低于15,代码重复率低于10%。这几项指标已经放在CI上监控,由于推行了很多年,团队成员已经养成了习惯,基本上很少出现违规。

但这年中突然多了一项,公司推行Infusion工具来检查代码的质量,要求工具发现的三类问题,数据泥团、Message Chain、Data Class必须清零,而工具定义的代码质量指标QDI,则要求按季度下降,不得上升,并且向上级部门备案。

此外,为了提升CI上单元测试覆盖率指标,我和另外一个兄弟写了很多的测试代码,显著提升了相关指标,但,使用当前的新词汇来形容,然并卵,对于项目组并无好处。对于我个人而言,则积累了很多PowerMock的使用经验,算是意外收获吧。

14年,回光返照

项目组接到了新部件的开发任务,分别基于Silverlight、安卓、HTTP、Flash、iOS提供客户端监控部件和服务端部件。当然,限于项目组的实际交付能力,我们最后其实只发布了Silverlight、安卓两个平台的监控部件和服务端部件。

由于安卓平台在国内的快速应用,安卓平台的监控部件在公司内外获得了很多关注,项目组熬过了夏天。时间到了秋天,基于SQM在安卓平台的成功,项目组申请到了iOS的人力资源来发展iOS平台的监控能力,但可惜的是,最终只发展出了雏形就不得不把人力和监控部件整体返回给公司的iOS团队。

本年度发布了C80、C90、C91、C92版本。

重要工作监控插件的交付

  • 作为主力,主导设计并完成大部分Silverlight平台监控部件的开发工作。
  • 作为主力,主导设计并独立完成安卓平台监控部件的开发工作。

在完成Silverlight和安卓平台的监控部件之后,项目组的骨干测试MM邵金亚离开了项目组。

编译脚本优化

借鉴安卓应用的编译框架的思路,对项目组已有部件的编译脚本进行整理,将公共特性及定制部分分离,极大的降低了编译脚本开发及维护的成本。

15年,离开

时间太快,转眼5年过去了。

1月份,我奉调加入了部门新成立的工具开发项目,离开了SQM开发团队。

随后没过多久,SQM团队被整体切换至IPTV部门,与我所在的部门彻底解除了关联,联合开发项目团队随之解散。

总结与回顾技术上的收获

  • JVM内存参数调优
  • Java应用问题定位
  • Java Swing开发
  • Swing UI LookAndFeel定制
  • JVM上运行脚本,JS、Jython的使用
  • Ant脚本开发
  • 基于Wireshark的协议解析
  • 安卓应用开发
  • C#开发
  • Oracle的使用,如执行计划的分析、表索引的分析、分区的使用及分区在数据备份方面的应用、表分析参数调整及表分析数据的应用、AWR报告的使用等。
  • mina的使用。

教训

  • 对团队的危机视而不见,姜山、唐丹丹、施健的离去都没有触动我,现在想来,自己真是麻木,完全看不出来项目组的危机。
  • 加班太多,没有时间思考。
  • 忽略了学习,自我提升有限。
  • 在舒适区待的太久,没有及时改变。
  • 忽视了身体。

现在看来,我自己引以为豪的技术和改进在领导眼里其实价值不大,虽然我本人投入巨大,也很辛苦,但站在领导角度一想,结论确实明显。

本文来自博客园,作者:jackieathome,转载请注明原文链接:https://www.cnblogs.com/jackieathome/p/17936103.html