互联网架构的我的主观见解

如下内容仅做为我的主观见解,不表明业界,仅供参考php

架构是一个系统的总体骨架的简称。理论上能够说全部运行的系统都有本身的架构,不一样的是数据处理方式、工具和目的。一个理想的架构须要表现出最大的扩展性、最好的安全性、最佳的运行性能、最简的维护工做、最快的升级特色、最合适的支撑团队、最低的运营成本和最优的发展目标。为了实现这些要求无数团队与我的在无私贡献丰厚的成果,但还远远不够,由于业务要求与市场不断在升级变化,与之要求的系统也须要不变的升级与变化。不少时候系统在随着变化而面临重构,更甚的会在不一样的阶段重构一次或几回。但有些并不是架构全责,好比:团队重组、语言变动、业务转向、硬件调整、成本管控等。java

不能否认大公司颇有钱能够拥有你不敢相像的团队,能够买你可能永远都接触不到的硬件或系统,去完成他们定义的高端架构标准,但他们在处理架构时经历了什么、成功到什么节点、能适应到什么节点、还有多少优化空间你能断言否?这不该该是架构的标杆,这只是有钱的标杆。我认为架构的初衷不该该有绑架的动机,它须要咱们拿出本身擅长的能力不断去学别人所长补本身所短,权衡的思考如今的要求与状况、未来的要求与状况,再尽量的去选择一套合适的方案,一步一步迭代与完善。node

目前尚未一个绝对的权威的架构标准,不过业界都有同一个目标:把数据库、业务逻辑的处理量与并发量减小到可承受的范围内,并预留必定的扩展和伸缩空间。选择合适的方案是决策人能力的体现,不少人喜欢跟风选择去填补本身的眼界或尝试欲望,在使用先后没有充分的了解与分析,致使面临问题时手忙脚乱,甚至有些问题一直没法解决。跟风是顺应潮流是扩大生存空间,但也须要充分的准备学习才能更好的生存下去。python

一个以数据库为核心的互联网系统中,架构的首要重点天然是数据库的规划;而后业务逻辑规划;最后对外服务规划。除非服务器长期的压力小到只须要要单台服务器就知足了,那架构就不须要专门去思考与研究,甚至都不须要专门考虑数据的原始性。若是服务器压力在上升架构的重要性就必定会摆在面前,而架构的重点就是合理安排各环节之间的通讯法则。mysql

数据库规划

数据库是整个系统的数据仓库,是提供数据保障的数据管理独立系统,但它在多节点的状况下处理方式有很大的变化。最主要的缘由是数据库依赖索引来查询数据(而索引只能对单表,多表索引会影响拆数据的目的),数据拆分后索引也一同拆分(只有这样才能保证索引树更小,查询更快)。为尽量少的对系统提供服务的影响须要在业务层增长一层数据库节点索引(或中间件)关联到不一样的数据库节点上快速选择完成数据操做。linux

目前作法有nginx

  1. 使用强大的中间件(好比mycat、ShardingSphere等),它们会自动处理分表,分片等工做,让你的架构不须要再考虑太多数据库的问题。但会受中间件的功能限制,某些更定制化的特殊需求可能须要在业务上进行复杂处理(好比熟悉的数据库不支持,更灵活的查询和复杂的查询不支持或性能不佳,不过中间件通常有团队在维护,只要市场有较大刚需算法上可行很快会增长对应的功能),固然也能够外加其它数据库系统来辅助完成。
  2. 对必用搜索字段作HASH业务索引分片到不一样的节点表。当只有一个必用字段时问题不大,若是出现多个必用字段时会复杂的多,要么遍历主要必用字段节点群(业务上处理复杂性能稍差,如:分页须要额外计算拼装);要么给次要的必用搜索字段建立各自的节点群,这个节点群的数据列包含主要必用字段,和辅助搜索字段(须要额外占用部分空间,业务处理相对简单性能稍好,如分页只须要获取主分片ID集再查询主要必用字段节点群的数据再合并即为分页数据体),也能够包含全部数据(额外空间占用量大,直接返回分页数据体),但更新时都须要同时更新全部对应的节点群。这种作法更自由,业务适应能力强,对数据二次拆分或合并难度大,也能够借助其它非关系型数据库来辅助搜索数据。
  3. 使用商业收费数据库集群系统,就如同使用中间件同样,但须要在不一样的量级下额外支付不一样的费用。
  4. 按业务某些不怎么互通的区域拆分经过大量主从复制来分压,好比按地区拆分,按业务线拆分,这种作法会限制较多的查询功能,系统的支撑量有限也不能无限扩展。
  5. 依赖大量的主从复制,最原始的方式,简单粗暴,系统的支撑量很是有限而且也不能无限扩展,须要足够强的硬件支撑,当到极限时必需调整。

不一样的作法适应不一样的环境、背景、条件。相同的是集群服务器必需知足一些基本要求,好比:redis

  1. 各节点的数据能够互通且及时性高
    若是数据互通性很差,及时性不高就会出现数据延时读脏,严重影响系统正常功能。高效的互通性与及时性须要保证各节点的压力一直在可承受范围内。好比主从复制分流,若是复制过于依赖某些写入量大的节点时会影响这些节点的写速度的效率发挥,让一些从节点作提供复制功能给其它节点,减小主节点的复制压力(固然这样会形成相对的复制延时,须要控制好复制的层次,视读写量级而定)算法

  2. 各节点的数据处理量要相对均匀
    若是各节点数据处理量极度不均匀压力就可能会失衡,容易形成部分节点压力过大而罢工。数据处理量要均匀就须要在分表分片时分散数据集中点,系统查询时分散到各只读节点上。在节点的数据量上通常须要选择一个惟一或索引层够高的字段来分片,好比:手机号取前缀或其它段、主键ID能够取模、取整、取尾数等,尽量能让各节点的数据量相对均匀便可;对于系统查询量须要业务代码尽量能雨露均沾的访问各节点,而不是集中在某些节点,通常可使用权值计算、随机碰撞、访问顺序、时序,询压等。

3.支持数据锁最好支持一致性事务
数据锁能够保证数据的一致性,在并发环境中尤为重要,只有锁定数据才能保证各进程上下文中处理的数据不会被破坏。值得庆幸的是大部分数据库都提供了数据锁,但在集群中上锁可能会出如今不一样的节点上,若是上锁的顺序混乱那么就可能形成死锁。
事务处理能够快速让一批数据的修改生效(提交)或失效(回滚),同时事务提供事务隔离与事务锁保证了数据的一致性,简化程序处理流程,避免程序回滚数据与数据加锁等操做。关系型数据大部分都支持标准事务,非关系型数据库基本没有或很简单的事务,但都提供了锁。在集群中同一个业务事务处理可能会出如今多个节点上,而在事务提交时可能会出现某些节点提交失败,而其它节点提交成功的状况,这会形成已经提交的数据没法回滚,而未提交成功的数据回滚的问题。多个节点事务没法保证事务的绝对一致性,有不少种特殊状况会致使事务只在部分节点上生效,好比:网络异常、数据库挂了、业务进程挂了、死锁等。
要想在多节点上保证事务的可靠性就须要额外增长一个独立一致性事务,以这个事务来决定各节点的事务成败。独立事务必需在其它各节点事务提交前提交而且记录各节点的事务处理数据,独立事务提交成功后,而后成功提交一个节点事务就删除一个独立事务对应的数据,当出现某个节点的事务没法正常提交时可再经过其它的守护进程取出独立事务内的数据写到异常节点中,保证事务一致性。若是在尚未来的及删除独立事务内的节点数据时就挂了则须要守护进程自行判断数据是否已经修改为功(插入或删除的数据经过惟一特征来判断,修改经过修改前惟一特征数据源增长限制条件)。这个独立事务可以使用消息队列,先进先出,当某个节点事务提交失败时再去填补下;固然也可使用数据库事务。准备一个提交一致性事务(记录各节点事务修改数据体,提交后就表示事务完成,而后逐个提交各节点事务,成功一个删除一个提交一致性事务对应的节点数据体或者所有提交完后统一删除),一个确认一致性事务(这个事务可使用最后提交的节点事务来担任,这个节点的事务最早开启前加锁,最后提交解锁,若是提交中异常则交给其它守护进程处理)。另外守护进程须要堵塞其它业务进程事务处理,防止业务事务内处理待守护进程修改的数据,守护进程使用不当可能会影响系统的性能。守护进程可使用定时队列服务、写到业务进程中或者二者均有,这彻底取决于架构的选用。
理论上只要担任的一致性事务或锁能正常提供服务就能够保证各节点的数据的一致性。sql

  1. 各节点迭代、更新、升级、伸缩可以快速同步进行
    业务发展会影响各阶段的人力与财力投入,也不可能一开始就使用很是大的集群来应对很小的业务,系统初期会预估1~5年的数据量,而后根据当前的财力来选择合适的集群,再做对应的分表分片处理。随着业务的变化颇有可能须要再次升级或降级,若是集群升降级很是复杂并伴有不确认性那将会给系统的升降级来带不可估计的影响。一个好的架构须要具有快速的升降级处理条件,以应对业务的变化。而升降级中最困难的莫过于分表分片的二次拆分与合并,业务代码的调整。这也是为何如今不少项目使用了数据库中间件的缘由,中间件把这些操做封装好对外的就如同操做一个数据库,使得架构升降级时不须要调整业务代码,惟一的遗憾是中间件并不能像操做一个数据库那么的任性,由于他就是一个数据库节点路由器,操做不当会给系统带来隐患。固然若是在业务代码中来完成中间件的功能也是能够的,不过须要额外增长很是多的算法逻辑,好处是你的系统你做主,只要能力达到就以完成中间件的全部工做而且还能够更好的定制调整。
    若是单从升降级处理上讲,分表与分片须要准备一个处理工具把这些数据进行复制转移,当数据复制转移完成后再切换到业务处理,若是切换失败则退回切换。中间须要存在一点切换停服时间,一来保证数据在切换中不会再变化,二来保证数据切换失败时退回前数据也不会变化。业务代码上的切换须要同数据切换同步,最好各业务节点里有两套代码,一套是原来的分表分片处理业务,一套是如今的分表分片处理业务,若是数据切换失败能够快速退回。

  2. 节点群须要高可用容许少许服务器异常时依然能够正常提供服务
    高可用是如今比较热门的话题,当用户体量足够多时系统异常机率会多起来,异常时间越长损失就越大,因此让系统在最短的时间内恢复正常止损是高可用的价值所在。高可用涉及到系统的出入口(负载均衡器)、业务服务器、数据服务器等各节点和环节。一般业务服务器会更容易点,由于业务代码相同且部署多个,部分异常时负载均衡器能够直接剔除,正常后再自动加入。系统的出入口与数据服务器通常是增长备用节点来替换,经过守护进程定时去核实主节点可用性,当主节点不可用时自动切换到备用节点上。系统的出入口能够经过修改域名解析IP,或修改机房网络等方式。数据服务器只须要修改链接地址或地址解析便可。但它们在切换以前最好保证异常的节点死透了或强制关闭,假死容易带来数据的混乱。

  3. 合理查询不受限制
    集群原本的目的是解决数据量的问题,但数据被切分后查询会变得更麻烦,若是一条查询涉及到多个节点则须要遍历这些节点,节点越多这条查询越慢,即便增长缓存也会由于第一次查询超时堵塞整个业务线。不一样类型的数据库单表数据量不同对查询的限制或要求也不同,目前主要有关系与非关系型数据库,还有部分数据库在这二者之间(不过大部分能够定义为非关系型数据库)。关系型数据库可使用关联查询减小数据的冗余量简化查询流程,会牺牲数据的容纳量与查询速度;非关系型数据库提高数据查询速度拆分查询流程,不能使用关系查询须要增长冗余数据来减小查询次数与复杂性。能够说数据拆分后会把数据非关系化,为了完成更多的查询要求就须要增长更多辅助冗余数据完成,固然这些冗余数据不必定要存放在相同的数据库中,能够是其它的数据库或缓存。

业务逻辑规划

业务逻辑是须要定制开发,基本没有太多的第二选择,即便使用了开源代码也须要二次开发。但在集群数据库系统中业务的处理须要格外当心,稍有不慎就会形成巨大的隐患甚至影响系统正常运行。

业务拆分
不少架构或决策人员愿意把直接操做数据的逻辑单独拆分出来组成微服务或低层服务提供给更外层的业务逻辑处理,让更专业的人员处理低层数据操做,其余人员处理外层业务逻辑操做,尽量避免数据操做不当的灾难。这种作法好处比较明显,好比:系统更稳定可靠、外层处理人员不须要再考虑数据一致性等相关问题开发更快、独立服务提供更多应用场景、各层级更专注容易升级与维护等,缺点是:低层服务处理复杂、须要额外占用空间、增长系统总体负载与成本等。当业务很大时仍是建议这种布局,由于开发人员的能力责任不同,天然结果也会不同,数据处理不当带来的灾难每每影响很是大,越是核心容易出错的地方越应该交给有能力的人去完成。拆分合理也须要综合评估,拆分不合理会把逻辑处理量偏向一边影响周期和扩展性。

开发语言
开发语言只是一个实际系统业务功能实现的工具,没有太大的贵贱之分,适应团队才是王道。合理的架构不仅是节省成本,有的时候还决定了项目的成败。而不少人却把架构的失败归结到开发语言自己及框架和使用的各类服务工具;好比:像php、nodejs、python等弱类型语言安全性差、功能少、速度慢不能开发大型系统,而应该使用Java、go等高级别强类型语言,系统框架也应该使用流行强大的;数据库系统应该使用mongodb、postgresql、oracle、非关系数据库而不是使用mysql等等。但我认为架构的失败是决策人的全责与能力的体现,好的工具用的好才能发挥好,软件的世界里没有绝对好的东西,只有用的好的东西。强类型语言也有漏洞、多线程并发等特定高级功能并无多少系统大量运用、运行速度也不必定绝对性的快;还有全部的数据库单表支撑都是有限的,数据库受硬件限制没法作到无限量,若是能够今天也不须要讨论分表分片搞集群。但有一点能够说的是强类型语言学习成本高难度稍大,天然能生成下来的开发人员能力与素质相对偏高;而弱类型语言学习成本低简单,不少低能力与低素质的人混杂在内拉低了总体的能力水平,致使弱类型语言成了弱鸡的代名词。

每一个语言有本身的定位与特色,但目前弱类型语言都是由C或C++之类的更低级的强类型语言开发的出来的,为保证弱类型的特色会牺牲一些空间与性能来避免强类型语言的开发复杂性。但不表明性能就必定比高级别强类型语言差,一个系统运行的速度彻底取决于实际CPU执行的指令时长和IO等待时长,只有最优的代码才能保证速度最优,惋惜的是在业务代码中最优每每只是表象,系统中通常会使用框架及组件而真正使用到的功能可能还不能20%大部的功能是无用的损耗,无形中增长了系统的负载。在很是简单的功能对比弱类型语言基本不具有性能等优点,但面对庞大的功能时弱类型语言开发速度快,代码体量小,谁优谁劣还真很差说。当系统处理量足够大时,性能的体现才会很是明显,不过目前尚未哪一个系统会用多种语言开发多套进行性能对比。目前全部的对比都是在必定的基础上对比,并非成熟的大型系统上对比,语法与底层的差别使得对比自己不具有不公平性,每一个语言都有本身的性能突出点和薄弱点,在性能突出点使用多的系统中天然性能更佳,相反性能更差。

至于业务代码的安全性与开发语言自己是没有直接关系的,没有哪一个语言敢承诺开发出来的程序是绝对不会出现安全问题的。弱类型与强类型的语言在各自生存环境中有本身的的处理方式来避免安全问题,但不免会有疏忽,彻底在于开发人员自己的意识与看法。

我的认为只要能力到了弱类型语言并不弱而强类型语言并无强到哪里去,大部分复杂的功能与算法已经被写到各服务与工具、语言解析器和框架中,即便有更高级的算法要求也会是另外的算法团队来完成,而大家只须要去使用它(除非你能力足够强能够写出任何其它语言能作的事)。全部开发语言都有本身的优势与缺点,所以语言没有最好只有最合适。若是你评估确认某种语言及框架是团队最拿手的就不要再去冒然尝试团队的短板,除非你有万全的把握应对。

对外服务规划

对外服务有两种,一种是系统内部各服务节点之间的对外服务(不对公网开放),好比数据库、微服务等;一种是对公网和内网开放的服务,好比对外API、网站展现、数据输出等。不官哪一种形式都须要保证服务的正常有序。
高可用性
若是服务出现异常应该如何保证对外服务还能正常呢?高可用性是全部系统都会面对的问题,软件与硬件存在许多的不肯定性致使系统异常,在出现异常时若是去及时发现并处理便是高可用的主要目标。通常能够增长监控系统,发现系统异常后及时报警和自动处理,减小导演带来不可服务的损失。
安全
对外服务最怕的就是数据泄露、篡改、甚至形成系统不可服务。从理论上说,没有绝对的安全,但须要有对应的监控和预防机制尽量止损。主要安全区域有:操做系统、组件服务、业务逻辑、业务组件框架、开发语言低层等,通常可以掌控的是业务逻辑安全,其它的安全问题基本上只能在配置、升级、补丁上来弥补。

业务逻辑安全。业务逻辑安全有不少,好比SQL注入、SHELL注入、跨站篡改、业务漏洞等。除了业务漏洞以外其它全部安全问题都是由业务逻辑不够严谨形成的。若是须要很好的避免漏洞就得须要知道漏洞的特色,而且还要有更好的洞察能力去避免。对于业务漏洞核心的思想是不要相信全部用户提供的数据,这些数据都须要通过验证或加工处理安全后才可使用;全部会接收用户数据的进程尽量不要给过高的操做权限,好比在linux系统下不要在root帐号下启动这些服务进程。业务漏洞通常是需求考虑不周形成的,好比:作活动只能每人抽奖一次,但在其它业务中又能够赠送抽奖次数,致使抽奖数据不可控。

业务组件框架、开发语言低层安全。这部分安全问题不多,一旦出现影响会比较大,基本上只能升级对应的组件框架或开发语言,对于比较大的集群来讲是一个不小的工做(固然若是集群管理工具强大另论),有的时候可能还须要修改比较多的业务代码来弥补。做为决策人应该须要考虑下这块的安全问题,尽早安排部署对就的工具,不一样的开发语言工具不尽相同这里就很少说明,不过也能够自行开发简单的处理脚本进行远程批量操做。

组件服务安全。服务组件只要不对外网开放,就能够抵挡一大半安全问题,若是有对外开放的服务则须要注意相关配置,好比:端口号调整、使用加密协议通讯、限制链接的地址或其它标识、使用专用帐号启动服务、复杂的受权密码等。其次就是业务代码或管理工具漏洞也可能会致使组件服务被暴露出来,甚至能够任意控制,通常建议管理工具只在内网或专网使用,业务代码提供的操做帐号必需限制权限,全部的受权密码或帐号必定要尽量复杂防止暴力破解。

操做系统安全。操做系统安全大部分是系统组件与系统辅助管理工具带来的,遇到了只能及时升级或打补丁。操做系统都会提供一块儿辅助管理工具和基本的IO操做管理进程,这些是操做系统不可缺乏的。由于操做系统的复杂性,因此漏洞也难以免。但也不是全部的漏洞是系统带来的,好比ssh若是配置使用不当会被利用甚至提权。通常建议集群节点只能经过内网或专网(***或其它固定IP)通道管理,减小其它外网访问的可能性,固然各节点依然须要增长二道防守,增长帐号与密码强度与保密性,而且对外提供的链接帐号不使用最高权限帐号,只能经过这个帐号进入后再提权。

监控管理
集群系统必定要有个监控管理系统,不然管理太多的服务器将是一个耗时易错的工做。监控系统主要负责服务可用与安全预警并及时给出报警与修复;管理系统主要负责集群升级、更新、调整、伸缩、安装等工做。不管是集群监控或管理都有不少成熟工具,按业务需求来选择,若是你有足够的能力或财力也能够自行研发,毕竟本身作的东西能够任意调整与定制。

实施

架构不是神秘黑盒子,非常一个有严格条理的各环节解决方案。当系统数据量足够大时各类状况都有可能发生,只有提早预知更多、考虑更多、准备更多才能保证系统更稳定,一样也不是每种构架方案都适合任何业务场景。
通常架构时须要画出架构图,同时给出各环节流程图以及问题与解决方案。没有哪一个架构能一次性完美的解决全部当前问题和未来问题,业务在变化架构也须要不断的调整或升级,见招拆招是一条走不完的路,不然架构一次后面就没有技术团队啥事了。

选择

选择数据库。表层数据使用非关系型数据库是缓解系统压力的有效途径,通常建议一种以上,好比redis和es,在高速环境下好比秒杀,队列、分页缓存可使用redis集群,在全文搜索上使用es集群。上层数据对事务要求很少,主要是在速度上要求更高,而非关系型数据库就是为速度而生的。落地底层数据库可使用mysql、mongodb、postgresql、oracle等集群,也可使用可持久化的非关系型数据库集群(固然非关系型数据在事务处理上会稍微复杂些)。若是业务有很是多复杂的关系网建议使用关系型数据库(好比:分销系统,电商平台系统),若是业务关系网比较简单建议使用mongodb或非关系型数据库(好比:秒杀系统)。固然若是团队能力OK只要能持久保存数据哪一种数据库均可以。

开发语言。建议使用团队拿手的语言,最比如较流行的好比:java、php等由于被使用的越多问题修改的就越多也越完善。尝试新语言会付出不少的代价,除非你足够牛。

数据库集群操做。若是业务要求并不苛刻,仍是建议使用开源的中间件,毕竟集群操做复杂、管理也复杂,什么都依靠团队来完成会严重影响开发周期,并且容易踩坑。

表层非关系型数据同步。落地底层数据库须要同步数据到表层非关系型数据库上,才能让表层数据库提供最新数据,通常对内存型的非关系型数据可直接写,好比写redis集群;不是内存型的非关系型数据库使用队列同步或三方工具,好比同步数据到es可使用列队或阿里的canal同步工具等。

对外服务。对外服务相对比较固定,主要是负载均衡器、系统服务器、CDN,微服务等。负载均衡器建议使用云负载均衡器,它们已经帮你完成负载均衡及高可用等功能。也能够本身搭建,通常能够选用varnish(HTTP加速器)、nginx(反向代理器)等。系统服务器通常须要配套开发语言的,好比java须要使用tomcat,php或python使用nginx或apache等。CDN目前都在使用商业的,本身部署成本大,并且须要按地区部署点节省跨区域的网络拥堵。微服务与系统服务相似。

相关文章
相关标签/搜索