目录

server学习路线

server学习路线

总结如下:

1、

程序设计是组装代码,系统设计是组装服务。

程序设计的组件是变量、函数、类等,系统设计的组件是服务器、数据库、缓存、队列、事件总线、代理等。

2、

如果一个系统很长时间不出错,它的设计就是良好的。

如果你进一步看了代码,脱口而出:“哈,这比我想的要简单”,或者“这个部分不用我操心,即使出问题也容易解决”,它的设计就是优秀的。

3、

良好的系统设计,总是从一个有效的简单系统发展而来。千万不要从零开始设计一个复杂的系统。

4、

系统设计的难点在于状态。尽量采用无状态组件,最小化“有状态组件”的数量。

状态的复杂性在于,你无法简单地重启服务。一旦出错,往往需要手动修复状态。

5、

状态需要保存在数据库。数据库是最重要的系统组件,用来管理状态。

数据库的设计目标是每张表易于理解:打开看一下表结构,就能大致了解存储的数据内容及其原因。

千万不要采用复杂的表结构(也就是数据结构),会给代码带来极大的复杂性和性能约束。

6、

数据库往往是系统瓶颈,因为每个页面请求可能要调用数十次、数百次数据库,而且是按顺序调用。

为了避免瓶颈,数据库可以做成一个写入节点和多个只读副本。数据查询都发往只读副本,数据写入发往写入节点。

写入节点与只读副本之间,存在数据复制延迟。如果更新一条记录后,你需要立即读取它,那么可以将数据放入内存,写入数据库成功后从内存读取。

7、

耗时的操作要拆分出来,放在后台作业(即系统外部的单独服务),排队完成。

后台作业主要分成两个组件:一个队列服务,一个作业运行器(从队列中获取任务并执行)。

队列任务的软件,可以用 Redis(需要尽快执行的任务),也可以用数据库(不着急的任务)。

8、

如果数据的生成速度和读取速度不匹配,经典解决方案就是缓存。

缓存的最简单做法,就是把数据保存在内存,否则就使用专门的键值存储软件(比如 Redis 或 Memcached),后者的好处是多个服务器可以共享缓存。

初级工程师希望缓存所有内容,而高级工程师希望尽量少用缓存。因为缓存是状态的来源,不可避免需要校验状态和处理状态过期。

9、

除了缓存和后台作业,大型系统通常还有事件中心,一般用的是 Kafka。

事件中心也是一个队列,存放的是“某件事发生了”的消息。比如,用户注册触发了“新帐户创建”事件,该事件就放入事件中心,然后由事件中心去通知订阅该事件的多个服务:发送欢迎电子邮件、设置个人空间等等。

事件中心适用于,发送事件的代码不关心其他服务如何处理事件,或者事件量很大且对响应时间不太敏感。

不要过度使用事件,很多时候,更简单的做法是让一个服务请求另一个服务的 API。

为了便于除错,所有日志最好都放在一起,你可以立即看到另一个服务的响应。

10、推拉

如果数据需要传送到多处,有拉取(pull)和推送(push)两种选择。

一般来说,拉取比较简单(比如大多数网站采用的轮询),推送更节省资源,不需要用户主动请求数据,一旦后端数据发生变化,服务器主动将数据推送给每个客户端。

如果你确实需要向100万个客户端提供最新数据(就像 GMail 那样),应该采用推送还是拉取?这要视情况而定。如果采用推送,就要把每次推送放入一个事件队列,并让一大群事件处理器从队列中拉取数据并推送。如果采用拉取,就要部署一堆(比如100台)快速的只读缓存服务器,处理所有读取流量。

单台服务器的并发承载能力总是有限的,当单台服务器处理能力达到性能瓶颈的时,将多台服务器组合起来提供服务,这种组合方式称之为集群,集群中每台服务器就叫做这个集群的一个“节点”,每个节点都能提供相同的服务,从而成倍的提升整个系统的并发处理能力。

有些时候,我们需要一台全局的服务器做一些全局数据的存储和全局状态的控制,为了保证全局数据和状态的一致性,可以采用主从部署方式,主从热备是主从部署的一种最常见的方式,主从热备是对于单点服务器做的一种容灾手段,以防止单点服务器故障后系统无法提供服务。主从热备的实现方式有双写机制,主从同步,动态选举等。

分布式系统就是将一个完整的系统按照业务功能拆分成很多独立的子系统,每个子系统就被称为“服务”,分布式系统将请求分拣和分发到不同的子系统,让不同的服务来处理不同的请求。在分布式系统中,子系统独立运行,它们之间通过网络通信连接起来实现数据互通和组合服务。

分布式集群是指将不同的业务子系统用集群化的方式部署到不同的机器上去,对于每一个业务子系统都具备大规请求的并发处理能力,从而提升整个系统的性能。

集群服务器中的节点均为平行对等节点,当需要扩容时,可以通过添加更多节点以提高集群的服务能力。一般来说服务器中关键路径(如游戏服务器中的登录,支付,战斗等核心体验)都需要支持运行时动态平行扩容。

在分布式集群系统中,平行扩容的节点加入集群后,需要注册到请求分发节点,以保证请求分发节点能发现新的扩容节点,从而将一部分请求分派到该节点,这种机制就是服务发现机制。

在集群部署环境中,负载均衡就是集群服务中的各节点以什么样的方式来尽可能均衡的分摊请求。常见的负载均衡方式有:轮询、随机、哈希映射,负载加权算法等。

缓存是一种很常见的技术,缓存能极大的提升了用户体验和系统稳定性,但缓存的引入同时会给提高系统的复杂性。缓存中数据变更应该要有持久化落地机制,不然服务器重启或者故障后可能导致数据回档。缓存的策略一般有全缓存,多级缓存,LRU缓存,LFU缓存,分布式缓存等。使用缓存技术主要目的有以下两点:

  • 降低访问延迟
  • 避免过多的请求直接与后端服务器或者数据库交互而造成系统瓶颈

对于分布式缓存系统,集群中不同的节点负责一定范围的缓存数据,当扩容节点或者节点故障时,可能会改变缓存数据和节点之间的映射关系,从而造成大量缓存失效,为了避免这样的问题,需要采用一致性哈希算法来计算缓存数据与节点的映射关系。一致哈希尽可能使同一个缓存数据映射到同一台节点。当增加一个节点服务器时,新的节点尽量能分摊其他节点的缓存数据。当减少一个节点服务器时,其他节点能分摊它的缓存数据,并且其他的节点本身的缓存数据不会被重新映射。

CAP理论,指的是在一个分布式系统中,Consistency(一致性)、Availability(可用性)、Partition Tolerance(分区容错性),不能同时成立(对于一个分布式系统来说。分区容错性是一个基本要求,因此只能在一致性和可用性之间做权衡。)。

  • 一致性:它要求在同一时刻点,分布式系统中的所有数据备份都处于同一状态。
  • 可用性:在系统集群的一部分节点宕机后,系统依然能够正确的响应用户的请求。
  • 分区容错性:系统能够容忍节点之间的网络通信的故障。

是对 CAP 中 AP 选择的延伸和补充。由于AP系统牺牲了强一致性,BASE理论描述了它们通常采用的设计思路:

  • B​​asically ​​A​​vailable(基本可用):系统出现故障时,允许损失部分可用性(如响应时间变长、功能降级)。
  • ​S​​oft state(软状态):允许系统中的数据存在中间状态,并且这个状态不会直接影响系统整体可用性。
  • E​​ventually consistent(最终一致性):经过一段时间后,系统内所有数据副本最终会达到一致的状态。

对同一个系统,使用同样的条件,一次请求和重复的多次请求对系统资源的影响是一致的。

模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。模块间耦合高低取决于模块间接口的复杂性、调用的方式及传递的信息。一个完整的系统,模块与模块之间,尽可能的使其独立存在。也就是说,让每个模块,尽可能的独立完成某个特定的子功能。

模块内所有组成部分职责单一,全部都为完成同一个功能而存在,模块已是最小可拆分单元。即模块仅包括为完成某个功能所必须的所有成分,这些成分紧密联系、缺一不可。

高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。依赖倒置可以降低层与层之间的耦合。

将非关键路径的流程从主流程抽离出来异步执行,防止非关键路径阻塞住关键路径。将重要的模块抽离,单独部署,防止不重要的模块不可用而影响重要模块的可用性。

将系统按照功能划分为独立的子模块,子模块之间互不依赖,任一子模块故障不影响其他模块继续提供服务,不同系统必须相对独立设计和运行,能够独立处理自己的故障,而不至于影响全局。

为了不过度占用资源,将一个连贯的动作过程不是一次性,集中式的完成,而是分为多次,每次执行一小段直至完成的设计成为渐进式设计,渐进式设计在高性能服务设计中很常用,如Lua的gc过程,redis的字典rehash过程等都采用渐进式的设计。

过度设计就是进行了过多的面向未来的设计,过度的进行了不必要的抽象封装,为系统增加了不必要的复杂度,降低了可维护性。设计过程中我们应该有适当的分层,抽象,从而将代码的可扩展性增强,但不是将所有未来可能的细节都过度实现,造成代码累赘,框架臃肿,可读性差。

破窗效应原意指环境中的不良现象如果被放任存在,就会诱使人们仿效,甚至变本加厉。在软件开发设计中,如果代码不够简洁和优雅,后来人就很难看懂,难以改进,再次编写有可能会加重代码的繁杂和紊乱程度,造成代码重复率高,最终走向腐化。

重构就是通过调整程序代码改善软件的质量、性能,使其程序的设计模式和架构更趋合理,提高软件的扩展性和维护性。随着时间的发展、需求的变化,不可避免的要违反最初的设计。重构就是不改变系统的外部功能,只对内部的结构进行重新的整理。通过重构,不断的调整系统的结构,使系统对于新需求的变更始终具有更强的适应能力,保持足够的生命力。

程序要做到可靠,就应该对外部所有的数据和机制保持不信任原则,对服务本身的不信任,对依赖系统的不信任,对请求输入的不信任,对机器的不信任,对网络的不信任。从而做到任何异常都能有正确的处理逻辑。

协程是用户态由程序所控制,用于完成协作式多任务的一类程序组件,它允许执行被挂起与被恢复。协程的能大大提高异步逻辑编码的可读性和开发效率。

在产品开发过程中,由于时间和资源受限的情况下,没有进行合理的设计,没有选择更加合理的架构,只是完成功能设计,牺牲了代码和架构设计的质量,随着功能迭代和时间推移,使得系统爆发出难以扩展,可用性差、扩展性差,开发效率低下,性能瓶颈等难以解决的技术问题。

脑裂是指在集群系统中,部分节点之间网络不可达而引起的系统分裂,不同分裂的小集群会按照各自的状态提供服务,原本的集群会同时存在不一致的反应,造成节点之间互相争抢资源,系统混乱,数据损坏。

当请求访问的数据在缓存中不存在,需要继续向后端服务器或者数据库查询时的情况,称为缓存穿透。大量的缓存穿透相当于缓存的作用失效,将可能导致后端服务器或者数据库层的压力超出预期,引起系统瘫痪。

对于集群系统,一般缓存是分布式的,即不同节点负责一定范围的缓存数据。我们把缓存数据分散度不够,导致大量的缓存数据集中到了一台或者几台服务节点上,称为数据倾斜。一般来说数据倾斜是由于负载均衡实施的效果不好引起的。

分布式系统中某个基础服务不可用造成整个系统不可用的情况, 这种现象被称为服务雪崩效应。

比如由于部分节点故障不可用,导致请求转移到其他节点,导致其他节点过载,拖垮整个系统。又如由于网络波动或下游节点短暂不可用导致上游节点不断重试,导致最终下游节点请求量过大整个服务不可用。

防止雪崩的方式一般有熔断,隔离,动态拒绝等。

在短暂的某一刻,服务器性能指标(CPU使用率等)远大于该时刻前后时间段。毛刺的出现代表这服务器资源利用不均匀,不充分,容易诱发其他更严重的问题。

攻击者发送一个目的主机已接收过的包,来达到欺骗系统的目的,主要用于身份认证过程,破坏认证的正确性。它是一种攻击类型,这种攻击会不断恶意或欺诈性地重复一个有效的数据传输,重放攻击可以由发起者,也可以由拦截并重发该数据的敌方进行。攻击者利用网络监听或者其他方式盗取认证凭据,之后再把它重新发给认证服务器。

网络孤岛指集群环境中,部分机器与整个集群失去网络连接,分裂为一个小集群。

过载是指当前负载已经超过了系统的最大处理能力,过载的出现,会导致部分服务不可用,如果处置不当,极有可能引起服务完全不可用,乃至雪崩。过载保护正是针对这种异常情况做的措施,防止出现服务完全不可用的现象。

把核心功能进行分拆和简化,通过轻量化的服务实现,确保最短关键路径的可行。

选择性的牺牲掉一部分数据的一致性和完整性,从而保证核心应用大部分功能的稳定运行。

将故障机器从集群剔除,以保证新的请求不会分发到故障机器。

消除毛刺,使服务器资源利用更加均衡和充分。常见的削峰策略有队列,限频,分层过滤,多级缓存等。

在升级版本的过程中,需要考虑升级版本后,新的数据结构是否能够理解和解析旧数据,新修改的协议是否能够理解旧的协议以及做出预期内合适的处理。这就需要在服务设计过程中做好版本兼容。

由于网络波动造成用户间歇性的断开与服务器的连接,待网络恢复之后服务器尝试将用户连接到上次断开时的状态和数据。

会话保持是指在集群服务中保证同一用户相关连的访问请求会被分配到同一台服务器上。

服务端只转发消息,不做任何逻辑处理,各客户端每秒帧数一致,在每一帧都处理同样的输入数据。帧同步需要保证系统在相同的输入下,要有相同的输出。帧同步开发效率高,流量消耗低而且稳定,对服务器的压力非常小。但是网络要求高,断线重连时间长,客户端计算压力大。

状态同步是指服务器负责计算全部的游戏逻辑,并且广播这些计算的结果,客户端仅仅负责发送玩家的操作,以及表现收到的游戏结果。状态同步安全性高,逻辑更新方便,断线重连快,但是开发效率较低,网络流量随游戏复杂度增加,服务器需要承载更大压力。

消息队列是一种进程间或同一进程的不同线程间的通信方式,消息队列就是把进程间的交互,抽象成对一个个消息的处理,通过消息管道来对这些消息进行存储。而消息本身的路由,由存放的队列决定的,这样就把复杂的路由问题,变成了如何管理静态的队列的问题。由于有一个缓存的管道,所以进程启停状态的变化不会导致丢失消息。

远程过程调用RPC就是本地动态代理隐藏通信细节,序列化请求,通过网络到服务端,执行真正的服务代码,然后将结果返回给客户端,反序列化数据给调用方法的过程。

协议栈是协议的具体的实现形式,是网络中各层协议的总和,其形象的反映了一个网络中文件传输过程,由上层协议到底层协议,再由底层协议到上层协议。

惊群效应指的是当许多进程等待一个事件,事件发生后这些进程被唤醒,但只有一个进程能获得CPU执行权,其他进程又得被阻塞,造成了严重的系统上下文切换代价。

拥塞是指当网络负荷增加到某一值后,到达某个节点的分组将会遇到无缓冲区可用的情况,从而使这些分组不得不由前一节点重传,或者需要由源节点或源端系统重传。当拥塞比较严重时,通信子网中相当多的传输能力和节点缓冲器都用于这种无谓的重传,从而使通信子网的有效吞吐量下降。由此引起恶性循环,使通信子网的局部甚至全部处于死锁状态,最终导致网络有效吞吐量接近为零。拥塞控制就是要控制网络的负荷避免造成拥塞现象。

灰度发布是指在升级版本过程中,通过分区控制,白名单控制等方式对一部分用户先升级产品特性,而其余用户则保持不变,当一段时间后升级产品特性的用户没有反馈问题,就逐步扩大范围,最终向所有用户开放新版本特性,灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、修改问题,以保证其影响度。

指的是程序或数据处理错误时,将程序或数据恢复到上一次正确状态的行为。

服务监控主要目的在服务出现问题时能够准确快速的发现以减小影响范围。

服务监控一般有多种手段,按层次划分为系统层(CPU,网络状态,IO),应用层(进程状态,错误日志),业务层(道具流出,攻击数值),用户层(用户体验)等多方位的监控。

系统运行过程中间某一时刻的内存,堆栈,状态等数据的备份,用于对系统运行状况的分析。

系统运行过程中间的关键路径上的数据记录。日志分析对于产品经营状况,问题定位,用户行为追踪等具有很关键的作用。

相关内容