关于复杂度来源,前面已经讲了高性能、高可用和可扩展性,今天我来聊聊复杂度另外三个来源低成本、安全和规模。
低成本
在设计架构方案时,成本通常只有在涉及数百、数千乃至数万台服务器时才成为重点考虑的目标。举例来说,方案A需要1万台机器,方案B只需要8千台机器,尽管从比例上看,B方案仅比A方案节省了20%的成本,但由于B方案需要的机器数量更少,因此可以节省约4000万元的成本,每人可以分得40万元奖金。因此,通过巧妙的架构设计,可以轻松地节省数千万元的成本,不仅展示了技术的实力,而且带来了可观的收益,这对技术人员来说是最有成就感的事情之一。
当我们致力于设计“高性能”和“高可用”的架构时,通常的做法是增加更多的服务器以满足需求。但在设计低成本的架构时,我们需要相反的策略:减少服务器的数量。因此,低成本与高性能和高可用往往是相互冲突的,因此低成本通常不是架构设计的首要目标,而是作为附加约束。这意味着,我们需要首先设定一个成本目标,然后在设计满足高性能和高可用的方案时,考虑方案是否符合成本要求。如果无法设计出满足成本要求的方案,就需要重新设计架构;如果无论如何都无法满足成本目标,那么就需要与老板商量调整成本目标。
低成本带来的主要挑战在于,往往只有通过“创新”才能实现低成本目标。这里的“创新”包括开创全新的技术领域(对大多数公司来说要求过高),也包括引入新技术。如果没有找到解决问题的新技术,那么就需要自己开发新技术。这是低成本架构设计的主要复杂性所在。
有很多类似的新技术出现,我来举几个例子。
- NoSQL(如Memcache和Redis)的出现是为了解决关系型数据库无法应对高并发访问带来的压力。
- 全文搜索引擎(如Sphinx、Elasticsearch和Solr)的出现是为了解决关系型数据库like搜索的效率问题。
- Hadoop的出现是为了解决传统文件系统无法应对海量数据存储和计算的问题。
以下是一些业界类似的例子:
- Facebook为了解决PHP低效的问题,首先采用了HipHop PHP,将PHP翻译成C++并执行。之后,Facebook转向HHVM,将PHP翻译成字节码并使用虚拟机执行,类似于Java的JVM。
- 新浪微博将传统的Redis/MC + MySQL架构扩展为Redis/MC + SSD Cache + MySQL架构,其中SSD Cache作为L2缓存使用,解决了MC/Redis成本高和容量小的问题,同时也解决了穿透数据库带来的访问压力问题(来源:http://www.infoq.com/cn/articles/weibo-platform-archieture)。
- LinkedIn为了处理每天5千亿事件,开发了高效的Kafka消息系统。
- 还有许多类似的例子,如将Ruby on Rails改为Java,将Lua + Redis改为Go语言实现等。
引入新技术和自己创造新技术都是复杂的任务。引入新技术的主要挑战在于需要熟悉新技术,并将其与现有技术结合起来。而自己创造新技术的主要挑战在于需要创造新的理念和技术,并且新技术需要与旧技术相比具有质的飞跃。
总的来说,创造新技术的难度更大,因此中小型公司通常借助引入新技术来达成低成本目标。大公司则更有可能自己创造新技术,因为只有大公司才有足够的资源、技术和时间去创造新技术。
安全
安全是一个庞大而又复杂的技术领域,一旦出现问题,会对业务和企业形象产生巨大的影响。例如:
- 2016年,雅虎曝出了史上最大规模的信息泄露事件,超过5亿用户的资料在2014年被窃取。
- 2016年10月,美国遭受了史上最大规模的DDoS攻击,导致东海岸的网站集体瘫痪。
- 2013年10月,浙江慧达驿站网络有限公司为全国4500多家酒店提供网络服务,因安全漏洞而导致2千万条入住酒店的客户信息泄露,引发了许多敲诈和家庭破裂等后续事件。
正是由于经常发生各种安全事件,大多数技术人员和架构师对安全问题有了更多的了解和考虑。
从技术的角度来看,安全问题可以分为两类:功能上的安全和架构上的安全。
1.功能安全
常见的XSS攻击、CSRF攻击、SQL注入、Windows漏洞、密码破解等安全问题,本质上是由于系统实现存在漏洞,黑客可以利用这些漏洞入侵系统。这种行为与小偷利用家庭不完善的地方潜入进行破坏或盗窃的方式类似。因此, 功能安全的目的是“防小偷”。
从实现的角度来看,功能安全与具体的编码相关,与架构关系不大。现在很多开发框架都内置了常见的安全功能,减少了安全相关功能的重复开发,但框架只能预防常见的安全漏洞和风险(例如XSS攻击、CSRF攻击、SQL注入等),无法预知新的安全问题。此外,框架本身也存在漏洞(例如,流行的Apache Struts2就多次爆出了调用远程代码执行的高危漏洞),给整个互联网造成了一定的恐慌。因此,功能安全是一个逐步完善的过程,需要有针对性地提出解决方案来应对新出现的安全问题。我们无法预测系统下一个漏洞在哪里,也不敢说自己的系统肯定没有任何问题。换句话说,功能安全是一个“攻”与“防”的矛盾,需要在攻防大战中逐步完善,而不能在系统架构设计的时候一劳永逸地解决。
2.架构安全
如果说功能安全是“防小偷”,那么 架构安全就是“防强盗”。强盗可以采用暴力手段入侵系统,例如用大锤将门砸开,或者用炸药将围墙炸倒。相比之下,小偷所做的只是偷东西,而强盗则可能故意搞破坏,对系统的影响也更大。因此,在架构设计时需要特别关注架构安全,尤其是在互联网时代,理论上来说系统部署在互联网上时,全球任何地方都可以发起攻击。
传统的架构安全主要依靠防火墙,防火墙最基本的功能就是隔离网络,通过将网络划分成不同的区域,制定出不同区域之间的 访问控制策略 来控制不同信任程度区域间传送的数据流。例如,下图是一个典型的银行系统的安全架构。
从图中你可以看到,整个系统根据不同的分区部署了多个防火墙来保证系统的安全。
除了依靠运营商和云服务商,还有一些技术手段可以应对互联网系统的架构安全问题,例如:
- CDN(内容分发网络):CDN可以缓存网站的静态资源,减轻源站的压力,同时也能起到一定的防御作用,抵御轻量级的攻击。CDN提供商也一般会提供一些基本的防护服务,例如对常见的DDoS攻击进行清洗。
- 反向代理:反向代理可以通过限制用户访问频率、请求流量、IP地址等,对恶意攻击进行一定程度的拦截。
- 分布式架构:采用分布式架构可以将系统部署在多台服务器上,通过负载均衡等手段来处理高并发请求。这样可以避免单点故障,同时也能在一定程度上提高系统的抗攻击能力。
- 漏洞扫描和风险评估:针对互联网系统的架构安全问题,可以使用漏洞扫描工具对系统进行扫描,发现安全漏洞,及时进行修复。同时也可以进行风险评估,分析系统存在的风险和安全隐患,有针对性地进行安全规划和布局。
总之,在互联网领域,架构安全是一个非常复杂的问题,需要综合考虑多个因素。除了技术手段,还需要从管理、人员和流程等多个方面进行规划和管理,才能确保系统的安全和稳定。
规模
确实,这种情况在企业级系统中很常见。在系统开发的过程中,为了应对不断变化的需求,往往会添加各种功能和逻辑,但是缺乏对系统整体架构的规划和管理,导致系统变得越来越复杂、难以理解和维护。
此外,企业级系统往往面向复杂的业务场景和业务流程,其中涉及到的各种规则、约束和限制非常多,这些规则可能存在互相矛盾的情况,导致系统逻辑变得更加复杂。同时,为了保证系统的正确性和可靠性,往往需要进行大量的异常处理、日志记录等操作,这些操作也会增加系统的复杂度。
最后,随着系统的发展,很多早期版本的代码可能会被保留下来,而这些代码可能已经过时、冗余或者存在漏洞,但是由于缺乏维护和更新,这些代码仍然在系统中存在,进一步增加了系统的复杂度。
因此,在开发企业级系统时,需要注意对系统的整体架构进行规划和管理,避免过多的功能堆砌和逻辑分支,同时保证代码的可读性、可维护性和可扩展性,这样才能确保系统的长期健康发展。
规模带来复杂度的主要原因就是“量变引起质变”,当数量超过一定的阈值后,复杂度会发生质的变化。常见的规模带来的复杂度有:
1.功能越来越多,导致系统复杂度指数级上升
例如,某个系统开始只有3大功能,后来不断增加到8大功能,虽然还是同一个系统,但复杂度已经相差很大了,具体相差多大呢?
我以一个简单的抽象模型来计算一下,假设系统间的功能都是两两相关的,系统的复杂度=功能数量+功能之间的连接数量,通过计算我们可以看出:
- 3个功能的系统复杂度= 3 + 3 = 6
- 8个功能的系统复杂度= 8 + 28 = 36
可以看出,具备8个功能的系统的复杂度不是比具备3个功能的系统的复杂度多5,而是多了30,基本是指数级增长的,主要原因在于随着系统功能数量增多,功能之间的连接呈指数级增长。下图形象地展示了功能数量的增多带来了复杂度。
通过肉眼就可以很直观地看出,具备8个功能的系统复杂度要高得多。
2.数据越来越多,系统复杂度发生质变
随着数据规模的增长,传统的数据处理技术已经无法胜任,导致系统的复杂度增加。这也是“大数据”技术领域的兴起,其理论基础是Google发表的三篇大数据相关论文,包括Google File System、Google Bigtable和Google MapReduce,它们开创了一个新的技术领域。大数据技术的应用能够更有效地处理海量数据,提高数据处理效率和准确性。但是,大数据技术的引入也会给系统架构设计带来新的复杂度,例如如何选择合适的大数据存储系统、如何设计分布式计算模型等问题。因此,系统设计师需要具备深入的技术知识和实践经验,才能在设计中平衡各种因素,以实现系统高效、可靠、可扩展等要求。
即使我们的数据没有达到大数据规模,数据的增长也可能给系统带来复杂性。最典型的例子莫过于使用关系数据库存储数据,我以MySQL为例,MySQL单表的数据因不同的业务和应用场景会有不同的最优值,但不管怎样都肯定是有一定的限度的,一般推荐在5000万行左右。如果因为业务的发展,单表数据达到了10亿行,就会产生很多问题,例如:
- 添加索引会很慢,可能需要几个小时,这几个小时内数据库表是无法插入数据的,相当于业务停机了。
- 修改表结构和添加索引存在类似的问题,耗时可能会很长。
- 即使有索引,索引的性能也可能会很低,因为数据量太大。
- 数据库备份耗时很长。
- ……
因此,当MySQL单表数据量太大时,我们必须考虑将单表拆分为多表,这个拆分过程也会引入更多复杂性,例如:
- 拆表的规则是什么?
以用户表为例:是按照用户id拆分表,还是按照用户注册时间拆表?
- 拆完表后查询如何处理?
以用户表为例:假设按照用户id拆表,当业务需要查询学历为“本科”以上的用户时,要去很多表查询才能得到最终结果,怎么保证性能?
小结
今天我分析了低成本给架构设计带来的主要复杂度体现在引入新技术或创造新技术,讨论了从功能安全和架构安全引入的复杂度,以及规模带来复杂度的主要原因是“量变引起质变”
本文由mdnice多平台发布
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net