架构师需要考虑的问题有很多,考虑的广度和深度,决定了架构师的高度,和系统架构的高度。
单单实现一个功能,实现一个系统,其实都是再简单不过的事情。很多体力活,拷贝,粘贴,输入,编译,调试,打包,部署,测试,无非就是这些。
但,维持一个大的在线的系统,更重要的不是这些,而是出各种异常情况的时候,系统的表现如何。
比如,数据库主库挂了,系统是完全不可用,还是能够优雅的降级为只读?还有一种情况比完全不可用更差,那就是:开发者也不知道会发生什么,系统的行为是未定义的,取决于机器,网络,报错的error code,运维人员昨天下班回家的顺序。。。
再比如,数据库辅库挂了,系统会自动切换辅库,甚至切回主库,还是拒绝服务?如果要实现连接池自动切换,怎么做?DNS 不是一个好的办法,但好歹“基本可用”。
类似的,memcache 挂了?redis 挂了?在大公司,做大系统,几乎每个结点都有 HA ,所以代码中做好处理就行了。万一系统中某个模块因为种种原因没有 HA,挂了以后会如何?是简单的单个模块不可用,还是会拖累到整个系统崩溃?
系统大了以后,开发团队也会膨胀,紧接着,更多的问题来了:
很多人修改代码,肯定会使用版本管理工具,svn?git?自己会用什么,想用什么并不重要,重要的是整个团队的共识。需要追踪问题,jira 还是 redmine ?文档怎么管理?需要一个 wiki 么?还是写 blog ?不管怎样,word 文档是应该被抵制的。有的团队甚至要求成员们的本机的开发环境统一,比如 eclipse 统一设置4个空格替代 tab ,比如本地的代码所在的目录。如果大家都用 windows ,也许问题会少一些,但是,如果有人用 mac,又有人用 ubuntu 甚至 FreeBSD 呢?
修改完代码是需要先测试才能上线的。同一时间多个需求并行的情况也不少见,那么就需要多个测试环境。如果系统比较单纯,这个问题也许就不那么严重。 如果运气不好,一个系统由超过3个独立模块组成,有各种的队列异步处理,远程过程调用,多 IDC 部署,那就悲剧了,意味着部署一个测试环境需要一个新人付出以天计算的时间才能完成。而且,容易出错。
多个人修改一份代码,每个人都尽量只加不改,更不要说减了,到后来,代码已经完全丧失了它原本的模样,更糟糕的是,谁也不敢大刀阔斧的改,因为没有 人对系统有足够清晰的,足够全局的了解。每一行代码都是一个坑,总有一天会有人掉进去的。还有,大家各自负责一块,互相之间以约定的接口进行调用,这样, 很容易就会产生理解不一致,以及接口的滥用。
修改完代码,合并到 trunk 或者 master ,该上线了。如果系统只部署在小于 10 台机器上,那一般不会被认为是大的系统。如果一次上线就需要改动超过 100 台机器,单纯的上线也是一个非常大的工作量,更不要说上线完成之后的验证,可能的意外情况处理,回滚。修改了代码或者配置文件,也就意味着可能的bug风 险。要不要引入 code review ?上线流程?签字审批之类的,经常会被写代码的人抵触。但是不这么做,总有一天受伤的会是自己。
大的系统,线上的“灵异”问题是一个很头疼的事情。一方面,它无法稳定重现,另一方面,数据量太大,log 不可能记的那么全,而且,系统太大,模块之间各自为政,处理过程经常串不起来,没法“重演”。机器设备一多,各种与设备相关的问题也就多了,网络波动?路 由不通?ulimit ?硬盘满了?为了避免这样的问题,流程化,自动化,标准化就很有必要了。上线新代码,上线新设备,上线新资源都必须要有章可循。
为了避免某一个资源,某一个模块的故障导致整个系统的瘫痪,模块隔离,服务化就势在必行。将模块抽象成服务,资源与资源之间做到物理隔离,做好容灾和降级方案,以备不时之需。
运维,监控,就不再多说了,看起来简单,真的做起来,就一个字:难!
在公司里面做事,资源总是有限的,需求总是无穷的。如何用有限的资源,多快好省的完成紧急而又重要的任务,如何尽快搞定紧急但不重要的扑火,如何将 重要但不紧急的事情按部就班的安排下去,如何拒绝又不重要又不紧急的打扰,这也是一种能力。各个相关的部门,自己有事需要他人帮忙的时候,他们总是会很忙 的,他们有事需要自己帮忙的时候,他们的事情总是又紧急又重要的。一方面尽量避免公司政治,另一方面,又避不开种种麻烦的事。