分布式系统的概念都搞懂了吗?(上)

–     进程与线程     –

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源,如程序计数器、一组寄存器和栈,但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

 

–     并发     –

当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间段分配给各个线程执行,在一个时间段的线程代码运行时,其他线程处于挂起状态。这种方式我们称之为并发(Concurrent)

应用层的并发概念可以推广之,定义为单位时间内对于共享资源的访问,比如在数据库单条记录更新时,一条在更新,一条并发请求则处于等待状态。

 

–     锁     –

锁(lock)作为用于保护临界区(critical section)的一种机制,被广泛应用在多线程程序中,比如Java(synchronized , ReentrantLock…)。

减少或规避锁争用的几种策略:

(1)分拆锁;

(2)分离锁;

(3)避免共享变量缓存;

(4)使用并发容器如Amino;

 

使用Immutable数据ThreadLocal中数据

特别介绍一下分拆锁(lock splitting)和分离锁(lock striping)。如果一个锁守护多个相互独立的状态变量,你可能能够通过分拆锁,使每一个锁守护不同的变量,从而改进可伸缩性。通过这样的改变,使每一个锁被请求的频率都变小了。分拆锁对于中等竞争强度的锁,能够有效地把它们大部分转化为非竞争的锁,使性能和可伸缩性都得到提高。分拆锁有时候可以被扩展,分成若干加锁块的集合,并且它们归属于相互独立的对象,这样的情况就是分离锁。例如:

ConcurrentHashMap的实现使用了一个包含16个锁的数组,每一个锁都守护HashMap的1/16。假设Hash值均匀分布,这将会把对于锁的请求减少到约为原来的1/16。这项技术使得ConcurrentHashMap能够支持16个并发Writer。当多处理器系统的大负荷访问需要更好的并发性时,锁的数量还可以增加。

 

–     并行     –

当系统有一个以上的CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。

和并发的区别:并发和并行是即相似又有区别的两个概念,并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔内发生。

 

–     集群     –

集群是一组相互独立的、通过高速网络互联的计算机,它们构成了一个组,并以单一系统的模式加以管理。一个客户与集群相互作用时,集群像是一个独立的服务器。集群配置是用于提高可用性和可伸缩性。其实,分布式系统可以表达为很多机器组成的集群,靠彼此之间的网络通信,担当的角色可能不同,共同完成同一件事情的系统。可以划分为以下几种类型:

(1)节点:系统中按照协议完成计算工作的一个逻辑实体,可能是执行某些工作的进程或机器。

(2)网络:系统的数据传输通道,用来彼此通信。通信是具有方向性的。

(3)存储:系统中持久化数据的数据库或者文件存储。

 

根据典型的集群体系结构,集群中涉及的关键技术可以归属于四个层次:

(1)网络层:网络互联结构、通信协议、信号技术等。

(2)节点机及操作系统层高性能客户机、分层或基于微内核的操作系统等。

(3)集群系统管理层:资源管理、资源调度、负载平衡、并行IPO、安全等。

(4)应用层:并行程序开发环境、串行应用、并行应用等。

–     状态特性     –

在大部分应用中都提倡服务无状态,分布式环境中的任何节点(Node)也是无状态的。无状态是指不保存存储状态,则可以随意重启和替代,便于做扩展。比如负载均衡服务器Nginx是无状态的,应用服务绝大部分也是无状态的,在高压力访问下,撑不住了就加一些机器,扩展很容易。

 

如图2-2所示,当Nginx、Jetty服务出现故障,客户快速更换,但MySQL、Memcached出现故障,快速更换就未必是预案的全部了。

 

以Cache Server(memcached)宕掉为例,一定范围的key查询不到就会访问DB(database),在极端情况下会导致DB穿透,甚至让DB服务器不可用。在业界对于缓存失效/缓存服务器不可用带来的雪崩效应未有完美的解决方案,一个可选的方案是:如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。

图2-2 Web集群

 

–     系统重发与幂等性     –

什么叫网络重发?在我的知识体系和百度并未找到原生定义。笔者讲一下现实的情况吧,我们模拟一下最简单的调用场景。如图2-3所示,用户访问一个应用,该应用需要调用一个远程服务,如果app1访问service B的链路出现网络异常,用户得到操作失败的反馈。为了减少失败率,httpClient的设计一般增加重发(retry)的机制。

图2-3 网络调用序列图

 

我们可以看看DefaultMethodRetryHandler(commons-httpclient-3.0)的代码,默认retry次数为3。

发展,相应类设计已经被改写,但retry的机制仍然存在。

 

因此,我们要考虑幂等性设计。所谓幂等性就是调用1次和调用N次要返回一样的结果。比如一次转账动作,A账户转账1000到B账户,由于网络调用超时,客户端client基于上述保障成功率的原因发起了retry,那么最终应该转账1000还是2000呢,客户的意愿是1000。只需要在设计上加上调用订单号就可以规避这个问题,多次重发,调用的订单号一样,则在服务提供方内部只做一次真实转账动作就行了。

 

–     硬件异常     –

大家都知道一套提供给客户的运行系统包括硬件和软件,而硬件则涉及机房、网络、服务器、磁盘及其他存储设备等等。硬件异常就是硬件出现了问题,而导致运行程序部分不可用或者全部不可用。

 

1.服务器宕机

引发服务器宕机的原因可能是服务器停电、内存错误等等故障,换言之,服务器故障是大概率事件。在分布式环境下,采用低廉的PC Server代替高大上的服务器已是常态。我们把宕机时不能提供服务的节点,称为不可用。服务器宕机时,节点将丢失所有内部信息,因此设计时需要考虑存储系统的持久化,在重启系统后,可以进行相关存储内容的恢复。

2.网络异常

网络异常的原因可能是消息丢失、网络包数据错误。比如笔者见过一个校园网的案例。故障引发原因为校园网内部分问题主机不定时发起大量异常对互联网的连接数据包,导致校园网出口设备会话连接数急剧增加,从而无法接受用户正常的网络连接请求数据包。而经过排查,确认为校园网内大量主机存在安全漏洞,有相当数量的主机被植入木马和恶意软件。这些主机频繁发送大量数据包,严重影响校园网性能。

设计容错系统的一个方案是,任何消息只有收到对方回复才可以认为发送成功。即使通讯软件钉钉进一步延伸为通过确认机制来了解接收者是否已读,已读状态则无法抵赖,属于确认机制的一种延伸应用。

 

3.磁盘故障

磁盘故障是高概率事件。我们一般区分故障为软件故障和硬件故障,而硬件故障又可以分为系统引起的,例如主板的IDE接口松动、与其他硬件设备不兼容、电源不稳定等等,而另一个就是硬盘本身的故障了,如出现坏道、分区表损坏、病毒等。磁盘损坏时,数据将丢失,当然还有一些专业的恢复策略,但是可靠性无法保障。因此,在分布式环境中,需要把数据存储在多台服务器,一旦一台出现故障,也能从其他服务器恢复。

 

4.房级异常

俗话说不要把鸡蛋放到一个篮子里,对容灾而言也有同城灾备和异地机房的做法。当发生机房级异常比如光纤出了问题,异地机房可以继续提供服务。

图2-4所示为一个示意性的机房容灾方案。机房H的备库放在机房K,通过数据库同步机制做信息复制。

图2-4 机房容灾示意图

未经允许不得转载:大自然的搬运工 » 分布式系统的概念都搞懂了吗?(上)

赞 (0)

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址