上篇文章我们说了分布系统存在的意义,基础的线程进程运行模式,进程之间内存是相互独立的,多线程是在进程内部,共享同一个进程里的内存,进程之间也可以共享对象,但是就有了序列化和反序列化的开销。网络通信知识有BIO/NIO/AIO、java通常用的NIO非阻塞,把出现的事件交给event handler处理,不需要一个socket分配一个线程,一个线程可以处理多个socket套接字工作。
分布式系统的介绍(1)--分布式系统&中间件从入门到精通(一)
前面提到了计算机由五个部分组成,输入设备,CPU(运算、控制器),外存/内存,输出设备,那么大型分布式是不是也可以从这个维度来分析呢。
输入设备的变化
分布式系统由多个单节点组成,那么输出设备可以看做两种,一种是互相连接的多个节点,一个节点向另一个节点发送数据,那么这个发送数据的节点就是输出设备,另一种就是传统意义上的人机交互,输入设备。
输出设备的变化
和输入设备变化类似,一种就是多个节点相互连接的情况下,一个节点接收另一个节点发送的数据,那么这个接收数据的节点就是输入设备,另一种就是传统意义上的人机交互,输出设备。
控制器的变化
在单个机器中,控制器和运算器都在cpu中。在分布式系统中,则控制器指的是分布式系统中如何由多个节点通过网络连接在一起并通过消息的传递进行协调的系统,控制器主要作用就是协调或者控制节点之间接收或者传输信息的动作。
第一种:可以使用硬件负载均衡器来完成,请求发起方和请求处理方中有一个硬件负载均衡器设备,所有的请求和接收都会通过这个负载均衡器来控制,这是一种控制方式。
第二种:如果换成软件负载均衡也是可以的,比如换成LVS,这种方式的特点是代价低,可控制性强,即你可以想对自由的按照自己的需求去增加负载均衡策略。
上面这两种方式称为透明代理。在集群中,这种对于请求方和发起方都是透
的,他们只需要在负载均衡设备/负载均衡软件把消息发送/接收,发起消息方不用关系有多少台服务器提供服务,也不需要提供服务的地址。但这种方式有两点不足,一方面会增加服务器的开销,开销指流量的开销,还有延迟的开销(实际使用的时候延迟影响很小)。另一不足就是这个透明代理是处于必经之路,当代理出现宕机的时候,则会出现所有请求不能发送的场景,这种时候我们则需要考虑代理服务器热备份。不过在切换的时候请求还是会受到影响。
第三种:名称服务。名称服务跟透明服务最大的区别就是,请求发起和请求处理方中间没有代理服务,而是通过名称服务来获取需要发送的ip服务名称,或者通过名称服务爱获取需要接受的ip服务名称。这样当服务名称机器宕机的时候,可以给他一个默认的ip来直接连接请求处理的服务。所以这个优点就是当名称服务宕机的时候,我们有很多办法可以保证请求处理正常。缺点就是代码升级比较复杂,需要处理当名称服务宕机的时候业务逻辑。
第四种:规则服务。这个和名称服务类似,不需要通过负载均衡,直接请求者与发送者直接连接,那么请求发起如何获取请求处理的ip呢,则是通过规则服务的机器来负载均衡获取的。这种情况下,请求发起方和规则服务来进行交互就好,来实现负载,请求处理服务不需要与规则服务交互。
第五种:Master+Worker。这种方式是存在一个master节点来管理任务,由master把任务分配给不同的worker去进行处理。这种方式和前面场景不太一样,主要是任务分配和管理。
运算器的变化
在单机系统中,运算器具体的电子元件,而在分布式系统中,运算器由多个节点来组成的,计算机的单机能力又上线,而分布式系统中运算器运用多个节点的计算能力来完成任务。
首先我们如果有10个用户,10个用户全部访问单个服务器,压力太大,所以这时候就增加多个网站服务来增加运算,那么如何保证他们能负载均衡访问呢,通过DNS服务器进行调度和控制。
在日志的处理有一个经典的场景,当一个日志服务需要处理太多其他服务的日志,这时候就需要增加日志的服务器,这时候可以用前面说的master+worker解决,或者用规则服务器来解决。
存储器变化
传统的单机模式会吧存储器分为内存和外存,内存在系统宕机后就会消失,外存的数据则会持久化,当然也不会是绝对就吃华可靠的,在分布式系统中,我们需要把承担存储的多个节点组织起来,最基础的是key-value场景存储。
如果需要负载均衡则需要采用名称服务或者规则服务来使用,当然也可以用master-worker来分配使用。
分布式的难点
在单机系统中,程序就以自己机器上的时钟为准,那么分布式的情况下,怎么控制呢,每个节点都有字节的时钟,在消息相互发送进行协调时候,如果依赖时钟,则相对难处理。这个问题首先想到的解决办法是保证每个节点的时间一致,当然如果能保证是最好的,但是这个方法本身没有办法实现,因为同步的时候本身就存在时间差,但有的时候,我们需要区分两个动作的先后顺序,而不是一定要知道准确的时间,这种情况,我们可以把工作交给单独的集群来解决。
面对故障独立性,分布式系统由多个节点组成,整个分布式完全出问题的概率是存在的,但多数情况都是出现某个节点不可用,但是其他节点还可以用,在单机的情况下,如果我们不使用多进程的方式,基本不会遇到独立障碍,只要出现机器问题或者OS问题或者程序bug,就会直接整体不可用,但是分布式会出现单个节点不可用而不影响整体使用,这时候就要找出相对应的哪个节点故障。
那发生了单点故障之后,也就是SPoF(Single Point of Failure)。我们需要在分布式系统中尽量避免出现单点故障,避免单点的关键就是把单点编程集群,当然这种比较困难,如果不能把单点部署成集群有另外两种办法。1、给这个单点做个容灾备份,手动恢复,尽量做成自动恢复,减少恢复时间。2、降低故障影响范围。可以把数据库拆分成多份,这样其中一个数据库出现故障,另一个数据库还能访问其他的数据,这样影响范围降低。但是一台数据库拆分成多台之后,会增加出故障的次数和时间,本质上这种方式更多是转移和交换故障。
分布式事务挑战,单机的分布式很好解决,但是不同节点之间的事务回滚就比较难实现,大家或许都听过2pc两阶段提交的缺陷,最终一致性,cap理论等,这些在后面会做详细介绍。