【转】分布式、高并发、多线程Multithreading

蓝咒 提交于 2019-12-06 16:24:02

一、分布式系统

在计算机领域,当单机性能达到瓶颈时,一般有两种方式解决性能问题,

  • 一是堆硬件,进一步提升配置;
  • 二是分布式,水平扩展、垂直拆分。

分布式系统有很多种:分布式文件系统、分布式数据库、分布式WebService、分布式计算等等,

面向的情景不同,但分布式的思路大致相同,万法归一吧!

以下内容主要来自:分布式系统架构思想

 

1.1、分布式系统实现的两种方式【水平扩展、垂直拆分】

1.1.1、简单的例子

假设我们有一台服务器,它可以承担1百万/秒的请求,这个请求可以的是:通过http访问网页、通过tcp下载文件、jdbc执行sql、RPC调用接口等等方式,现在我们有一条数据的请求是2百万/秒,很显然服务器很难hold住,会各种拒绝访问,甚至宕机,怎么办呢?

一台机器解决不了的问题,那就两台。所以我们加一台机器,每台承担1百万。如果请求继续增加呢,两台解决不了的问题,那就三台呗。这种方式我们称之为水平扩展,如果实现请求的平均分配便是负载均衡了。

另一个例子,我们现在有两个数据请求,数据190万,数据280万,上面那台机器也hold不住,我们加一台机器来负载均衡一下,每台机器处理45万数据1和40万数据2,但是平分太麻烦,不如一台处理数据1,一台处理数据2,同样能解决问题,这种方式我们称之为垂直拆分。

水平扩展和垂直拆分是分布式架构的两种思路,但并不是一个二选一的问题,更多的是兼并合用。下面介绍一个实际的场景。这也是许多互联网的公司架构思路。

1.1.2、实际的例子

某些公司的计算机系统很是庞大,自然是一个整的分布式系统,为了方便组织管理,公司将整个技术部按业务和平台拆分为部门:订单的、会员的、商家的等等,而每个部门有自己的web服务器集群、数据库服务器集群,

通过同一个网站访问的链接可能来自于不同的服务器和数据库,对网站及底层对数据库的访问被分配到了不同的服务器集群,这个便是典型的按业务做的垂直拆分,每个部门的服务器在hold不住时,会有弹性的扩展,这便是水平扩展。

在数据库层,有些表非常大,数据量在亿级,如果只是纯粹的水平的扩展并不一定最好,

如果对表进行拆分,比如可以按用户id进行水平拆表,通过对id取模的方式,将用户划分到多张表中,同时这些表也可以处在不同的服务器。

按业务的垂直拆库 和 按用户水平拆表 是分布式数据库中通用的解决方案。

1.2、负载均衡

前面我们谈到了分布式来解决性能问题,但其附带的问题是怎么分布,即如何负载均衡。这里要解决的问题是当客户端请求时,应该让它请求分布式系统中哪一台服务器,通常的做法是通过一台中间服务器来给客服端分配目标服务器。

这里同样拿两个不同的分布式系统做说明,

下图左边 是分布式文件系统FastDFS,

下图右边 是一个用于分布式的RPC中间件。

  • FastDFS的一次文件下载请求过程是这样的

    1. client询问tracker可以下载指定文件的storage;

    2. tracker返回一台可用的storage;

    3. client直接和storage通信完成文件下载。

其中tracker便是负载均衡服务器,storage是存储文件和处理上传下载请求的服务器。

 

  • 而另一个RPC中间件Hedwig也是类似的

    1. client询问zookeeper哪台server可以执行请求;

    2. zookeeper返回一台可用server;

    3. client直接与service完成一次RPC。

zookeeper是分布式系统中一个负载均衡框架,google的chubby的一个开源实现,是Hadoop和Hbase的重要组件。

同样的在http中,常听说的nginx也是一个负载均衡服务器,它面向的是分布式web服务器。

1.3、同步问题

分布式系统中,解决了负载均衡的问题后,另外一个问题就是数据的一致性了,这个就需要通过同步来保障。根据不同的场景和需求,同步的方式也是有选择的。

在分布式文件系统中,比如商品页面的图片,如果进行了修改,同步要求并不高,就算有数秒甚至数分钟的延迟都是可以接受的,因为一般不会产生损失性的影响,因此可以简单的通过文件修改的时间戳,隔一定时间扫描同步一次,可以牺牲一致性来提高效率。

但银行中的分布式数据库就不一样了,一丁点不同步就是无法接受的,甚至可以通过加锁等牺牲性能的方式来保障完全的一致。

在一致性算法中paxos算法是公认的最好的算法,chubby、zookeeper中paxos是它保证一致性的核心。

 

二、高并发

高并发,简言之:短时间,大量请求。

以下内容主要来源于:java系统高并发解决方案(转载)

----------------------------------------------------------------------------

2.1、并发与分布

并发反映的是同时有多少量,比如互联网上的在线直播,可能有几万人需要同时访问服务器,这就是并发。

分布是将任务分发到不同的点上去,一般分布式最多的就是分布式计算。通过某种分布式编程方式,在不同的系统上利用各自的CPU,内存等进行计算,将结果汇集至控制中心,进行处理。

  • 高并发也可以通过分布式方式解决,比如云的概念,云存储就需要通过分布式的系统,可以实现高并发的存储。这需要取决于需求和容忍度。
  • 对于互联网这个具体领域,高并发的解决不一定需要通过分布式系统,可以通过DNS轮询,实现服务器负载的分担。所有的服务器都是一样的配置,访问同样的内容。
  • 对于一些数据库处理系统,需要快速返回结果,也可以通过分布式系统,将计算任务分摊到不同的系统上去,加快计算的速度。

2.2、解决高并发的常见经验

大型网站,比如门户网站。在面对大量用户访问、高并发请求方面,基本的解决方案集中在这样几个环节:

  • 使用高性能的服务器
  • 高性能的数据库
  • 高效率的编程语言
  • 还有高性能的Web容器

以上的几个方面在一定程度上意味着更大的投入,会经常遇到瓶颈,没有很好的扩展性,所以还没法根本解决大型网站面临的高负载和高并发问题。

下面我从低成本、高性能和高扩张性的角度的一些经验:

  • HTML静态化
  • 图片服务器分离
  • 数据库集群和库表散列
  • 缓存
  • 镜像
  • 负载均衡
  • ......

2.2.1、高并发高负载类网站关注点之数据库

    首先是数据库,这是大多数应用所面临的首个SPOF【single point of failure 单一故障点】。
常用的优化措施是M-S(主-从)方式进行同步复制,将查询和操作和分别在不同的服务器上进行操作。

    推荐的是M-M-Slaves方式,2个主Mysql,多个Slaves,需要注意的是,虽然有2个Master,但是同时只有1个是Active,我们可以在一定时候切换。之所以用2个M,是保证M不会又成为系统的SPOF。
Slaves可以进一步负载均衡,可以结合LVS,从而将select操作适当的平衡到不同的slaves上。
    以上架构可以抗衡到一定量的负载,但是随着用户进一步增加,你的用户表数据超过1千万,这时那个M变成了SPOF。你不能任意扩充Slaves,否则复制同步的开销将直线上升,怎么办?我的方法是表分区,从业务层面上进行分区。最简单的,以用户数据为例。根据一定的切分方式,比如id,切分到不同的数据库集群去。

    全局数据库用于meta数据的查询。缺点是每次查询,会增加一次,比如你要查一个用户nightsailer,你首先要到全局数据库群找到nightsailer对应的cluster id,然后再到指定的cluster找到nightsailer的实际数据。每个cluster可以用m-m方式,或者m-m-slaves方式。这是一个可以扩展的结构,随着负载的增加,你可以简单的增加新的cluster进去。

2.2.2、高并发高负载网站的系统架构之HTML静态化

    其实大家都知道,效率最高、消耗最小的就是纯静态页面,所以我们尽可能使我们的网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法。但是对于大量内容并且频繁更新的网站,我们无法全部手动去挨个实现,于是出现了我们常见的信息发布系统CMS,像我们常访问的各个门户站点 的新闻频道,甚至他们的其他频道,都是通过信息发布系统来管理和实现的,信息发布系统可以实现最简单的信息录入自动生成静态页面,还能具备频道管理、权限 管理、自动抓取等功能,对于一个大型网站来说,拥有一套高效、可管理的CMS是必不可少的。
   同时,html静态化也是某些缓存策略使用的手段,对于系统中频繁使用数据库查询但是内容更新很小的应用,可以考虑使用html静态化来实现,比如论坛 中论坛的公用设置信息,这些信息目前的主流论坛都可以进行后台管理并且存储再数据库中,这些信息其实大量被前台程序调用,但是更新频率很小,可以考虑将这 部分内容进行后台更新的时候进行静态化,这样避免了大量的数据库访问请求高并发。

网站HTML静态化解决方案 
当一个Servlet资源请求到达WEB服务器之后我们会填充指定的JSP页面来响应请求:

    HTTP请求---Web服务器---Servlet--业务逻辑处理--访问数据--填充JSP--响应请求

HTML静态化之后:

    HTTP请求---Web服务器---Servlet--HTML--响应请求

2.2.3、高并发高负载类网站关注点之缓存、负载均衡、存储

2.2.4、高并发高负载网站的系统架构之图片服务器分离 
    大家知道,对于Web 服务器来说,不管是Apache、IIS还是其他容器,图片是最消耗资源的,于是我们有必要将图片与页面进行分离,这是基本上大型网站都会采用的策略,他们都有独立的图片服务器,甚至很多台图片服务器。这样的架构可以降低提供页面访问请求的服务器系统压力,并且可以保证系统不会因为图片问题而崩溃。

2.2.5、高并发高负载网站的系统架构之数据库集群和库表散列

    大型网站都有复杂的应用,这些应用必须使用数据库,那么在面对大量访问的时候,数据库的瓶颈很快就能显现出来,这时一台数据库将很快无法满足应用,于是我们需要使用数据库集群或者库表散列。
  
  在数据库集群方面,很多数据库都有自己的解决方案,Oracle、Sybase等都有很好的方案,常用的MySQL提供的Master/Slave也是类似的方案,您使用了什么样的DB,就参考相应的解决方案来实施即可。
  
   上面提到的数据库集群由于在架构、成本、扩张性方面都会受到所采用DB类型的限制,于是我们需要从应用程序的角度来考虑改善系统架构,库表散列是常用并且最有效的解决方案。我们在应用程序中安装业务和应用或者功能模块将数据库进行分离,不同的模块对应不同的数据库或者表,再按照一定的策略对某个页面或者 功能进行更小的数据库散列,比如用户表,按照用户ID进行表散列,这样就能够低成本的提升系统的性能并且有很好的扩展性。

------------------------------------------------------------------------------

三、多线程 Multithreading

3.1、Thread 基本概念与特点

多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。

具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。

  • 多线程:指的是这个程序(一个进程)运行时产生了不止一个线程
  • 并行与并发:
    • 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
    • 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。

3.2、Thread 生命周期

关于Java中线程的生命周期,首先看一下下面这张较为经典的图:

上图中基本上囊括了Java中多线程各重要知识点。掌握了上图中的各知识点,Java中的多线程也就基本上掌握了。

3.3、Thread五种基本状态

  • 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
  • 就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
  • 运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就     绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
  • 阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
    • 1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
    • 2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
    • 3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  • 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!