您现在的位置:首页
--> 四火的唠叨
曾经写过一点关于代码评审(code review)的文章,比如这篇和这篇,现在觉得关于它的认识又有了不少更新。软件工程的技术和实践分成两部分,一部分是和书本知识一致的,大约占一半,这部分基本上在大学里就可以学,自学只要方法得当、刻苦努力也可是途径;但是第二部分来自于实际团队、经验,内容通常无法从书本当中获得,而且难说对错,不同的人和不同的经历造就了不同的认识。代码评审就是第二部分颇具槽点,可以大加讨论的典型。
其实老早就像写一点这个话题。几乎我见过的所有大型系统中,都需要一个唯一ID的生成逻辑。别看小小的ID,需求和场景还挺多:
这个ID多数为数字,但有时候是数字字母的组合;
可能随机,也可能要求随时间严格递增;
有时ID的长度和组成并不重要,有时候却要求它严格遵循规则,或者考虑可读性而要求长度越短越好;
某些系统要求ID可以预期,某些系统却要求ID随机性强,无法猜测(例如避免爬虫等等原因)。
独立的生成服务
比如数据库。最常见的一种,也是应用最多的一种,就是利用数据库的自增长序列。比如Oracle中的sequence的nextVal。有多台application的host,但是只有一个数据库。本质上这是耍了个小赖皮,把某分布式系统唯一ID的生成逻辑寄托到一个特定的数据库上,于是分布式系统存在中心节点了。
Spark的性能优化有一些特殊的地方,比如实时性一般不在考虑范围之内,通常我们用Spark来处理的数据,都是要求异步得到结果的数据;再比如数据量一般都很大,要不然也没有必要在集群上操纵这么一个大家伙,等等。事实上,我们都知道没有银弹,但是每一种性能优化场景都有一些特定的“大boss”,通常抓住和解决大boss以后,能解决其中一大部分问题。比如对于portal来说,是页面静态化,对于web service来说,是高并发(当然,这两种可以说并不确切,这只是针对我参与的项目总结的经验而已),而对于Spark来说,这个大boss就是shuffle。
最近工作中一直和SWF(Amazon的Simple Work Flow)打交道,在一个基于SWF的工作流框架上面开发和修bug。SWF的activity超时时间是5分钟,在activity task开始执行以后,activity worker需要主动发送心跳请求告知service端:“我还活着,我还在干活”,如果出现超过5分钟(可以配置)没有心跳,SWF的service端就认为,你已经挂了,我需要把这个activity安排到别的activity worker上来执行了。借用AWS官网的一张图:
关于编程语言的类型系统其实很复杂,我已经写得很费劲了,但是毕竟火候不行,还有一些重要或者深入的东西没有提到。另外,这也不是教程,只是按照特性的比较和整理,如果要系统学习Groovy或者Haskell,还是需要寻找相应的教程,通常在官网上的资料就很不错。
我记得刚接触计算机的时候,我就受到了两个非常巨大的错误观念的影响,这个观念最初是来自于老师的传授还是学长的教诲已经记不清了,但是直到我工作几年以后,才慢慢有了实际的体会:
1、学习和使用什么编程语言不重要,重要的是算法和设计;
2、程序员学习的精髓是面向对象的设计模式,掌握以后,一通百通。
公司搞淘汰Oracle数据库的事情已经搞了好久了,这个事情其实和国内淘宝系搞的去IOE(IBM、Oracle和EMC)是类似的,基本上也是迫不得已,Oracle的维护成本太高,而公司内部基于Oracle数据库的数据仓库,也是问题频出;另一个原因则是scalability。我相信这两个原因许多人都非常清楚。而这个淘汰,也不是简简单单换一个关系数据库,比如把Oracle换成MySQL,或者换到云上(RDS)。而是有明确阶段性地演进,比如替换到DynamoDB这样的NoSQL数据库上面去;或者更彻底地,像我们接触到的某个产品,数据本身换到更廉价的存储S3上去,元数据才存在DynamoDB里,而原本SQL执行的运算的部分用Hadoop或者Spark来完成,这件数据源统一和演进的事情由一个做infrastructure的团队来完成。
Oracle数据库要淘汰,而且还看到了NoSQL数据库作为其中的一个替代方案,那是不是说SQL要慢慢淡出历史舞台了?
有这样一道算法题:
给定一个能够生成均匀1~5随机枚举数的函数,请设计一个能够生成均匀1~7随机枚举数的函数。
就是说,有一个生成随机数的函数rand5,可能返回1、2、3、4、5这5个枚举值,其中每个值被返回的概率都是严格的1/5,现在需要设计一个类似的随机数函数rand7,可能返回1、2、3、4、5、6、7这几个枚举值,每个值被返回的概率都是严格的1/7。
系统设计方面的问题问题是非常考验经验和思维过程的,而且和常见的算法问题、语言基础问题不同,涉及的面很广,还没有比较一致的判别标准。但无论如何,还是可以归纳一些常见的思路和典型问题的线索。
本篇文章的话题是元编程。首先来认识元编程,我在第一篇《引子》里面已经介绍:元编程,指的是在运行时改变“类”的定义,例如访问、增加或修改等等。一言以蔽之,就是“用程序来写程序”。在第二篇的《类型系统》里面已经借由继承和接口的实现,介绍了一些利用元编程特性来增加或改变子类行为的方法。回顾语言发展的长河,其实是经历了一个从“对象 -> 类 -> 元类”到“对象 -> 原型”的发展过程的。所以,无论是类,还是元类,这样的概念其实都不是非有不可的,只是因为我们思考的习惯,特别是抽象的习惯而顺其自然地产生了。
• 手滑的故事
最近看到这篇文章《小伙伴们手滑集》,觉得感慨很多,强烈推荐大家阅读。比如这样的例子:
UPDATE没有WHERE条件
而我则经历过delete没有写where条件的惨剧,这个惨剧是某些case下面代码调用触发的,不是手动执行SQL发生的。
还有臭名昭著的,我没有经历过,但是我有不止一个同事干过这样的事情:
rm -rf
都只是手稍稍地温柔地“滑了一下”而已嘛……
这些事情我觉得一下子很亲切,似乎全世界的软件工程师都是如此得同一。
出的事故多了以后,变得战战兢兢,如履薄冰,尤其是回车键这样的敲击,似乎总是带着颤抖落指。
DSL(Domain Specific Language)指的是一定应用领域内的计算机语言,它可以不强大,它可以只能在一定的领域内生效(和GPL相比,GPL是General Purpose Language),表达仅限于该领域,但是它对于特定领域简洁、清晰,包含针对特定领域的优化。 当我们面对各种各样的特定需求的时候,一个通用的语言往往不能高效地提供解决问题的路径,相应的DSL并不是并非要解决所有的问题,但是它只关注于某一个小领域,以便解决那一个小领域的问题就好了。
• 三次性能优化经历
最近在做一些性能优化工作,回想起工作这些年来,参与过的三次集中性能优化,每次都得折腾少则一个月,多则半年。这些内容既是不同视角、不同思路的比较,也是挺有趣的工作经历。
作为系统设计学习的一部分,不久前在梳理面试中典型的系统设计问题,发现大部分都可谓有套路可寻。我把思路梳理了一下,简单整理到下面这张图表里面....
以下都来自我的经历,带有主观评价,但是尽量保持平直的论述。
在我工作的第一家公司的时候,一个典型的研发团队是这样组成的。我的经验也只是到4年前,现在也许早就不一样了呢。
项目经理,这个角色是不断在换的。项目经理当然是只跟着项目走,这和团队经理(Team Leader)是不一样的。当然,Team Leader也往往在不同的项目里面兼任项目经理。基层的项目经理也可能会编码,但是不管参与不参与编码,工作压力都不小。
从毕业工作到现在,已经有七个年头,年头虽然不久,但是回过头来看看那些经历的好的坏的有趣的扯淡的事情,还是有很多东西可以总结。所有人都会或多或少走弯路,本来成长就是这样一个过程,有时候想起来会感叹,有时候会唏嘘,有时候会一笑而过。我的前一半时间是在华为,这段时间留给我很多回忆(比如这几个瞬间);后半时间在亚马逊,也给了我不少感慨的机会。下面这些故事都是我经历的真真实实的事,有的事情已经过去好久,但我不想把它永远尘封。也许你和我在某些方面,会有共同的体会。
下面这些关于Spark的性能调优项,有的是来自官方的,有的是来自别的的工程师,有的则是我自己总结的。
Data Serialization,默认使用的是Java Serialization,这个程序员最熟悉,但是性能、空间表现都比较差。还有一个选项是Kryo Serialization,更快,压缩率也更高,但是并非支持任意类的序列化。
Memory Tuning,Java对象会占用原始数据2~5倍甚至更多的空间。最好的检测对象内存消耗的办法就是创建RDD,然后放到cache里面去,然后在UI上面看storage的变化;当然也可以使用SizeEstimator来估算。使用-XX:+UseCompressedOops选项可以压缩指针(8字节变成4字节)。在调用collect等等API的时候也要小心——大块数据往内存拷贝的时候心里要清楚。
最近的工作总是在EMR上跑Spark的job,从代码完毕到测试完毕的过程是这样的:
1. 本地测试:
构建 -> 本地UT -> 观察分析结果,这一阶段可以发现逻辑问题
2. EMR上执行测试:
上传最新构建到S3 -> 准备EMR资源(包括计算资源和数据) -> 在EMR上执行Spark job -> 观察分析结果,这一阶段可以发现在数据量较大的情况下才出现的问题
3. Workflow集成测试(这个workflow是公司内部的一个管理job的工作流系统):
启动workflow -> 观察job状态 -> 等待workflow调度和资源分配 -> 等待workflow执行结束 -> 观察分析结果,这一阶段可以发现在workflow配置、参数等环境上的问题
最近开始学习Scala,相较于学习Haskell的过程来看,Scala真是直观得多,友好得多,更容易上手。以前写过关于从熟悉的Java和JavaScript来逐步学习Groovy和Haskell的文章,这以后再来学习Scala的话,就可以不断比较了。
大学里面算法课老师教导过动态规划,但是就像看书要把书看厚再看薄一样,要把动态规划彻底理解,还是需要一些时间的锻炼。解动态规划问题,每个人都有自己的习惯的套路,我的理解是最核心的过程有两部,一个是找出问题的一个一个子“状态”,再一个就是建立“状态转移方程”(就是所谓的“递推关系式”)。把这个过程搞定,基本上动态规划的题目就解了一半了,剩下那些代码层面的事情,是把思路和数学方程实现而已了。
[ 共24篇文章 ][ 第1页/共2页 ][ 1 ][ 2 ]
近3天十大热文
- [66] Go Reflect 性能
- [66] Oracle MTS模式下 进程地址与会话信
- [65] 如何拿下简短的域名
- [59] IOS安全–浅谈关于IOS加固的几种方法
- [59] android 开发入门
- [59] 图书馆的世界纪录
- [58] 【社会化设计】自我(self)部分――欢迎区
- [53] 视觉调整-设计师 vs. 逻辑
- [47] 界面设计速成
- [47] 读书笔记-壹百度:百度十年千倍的29条法则
赞助商广告