架构演变之海量数据及高并发问题的解决方案笔记

来源:互联网 发布:复杂网络的度 编辑:程序博客网 时间:2024/06/14 01:12

一、海量数据的解决方案
1、缓存
数据量很大最直接的解决方案就是使用缓存,缓存就是将数据库中获取的结果暂时保存起来,在下次使用时无需重新到数据库中获取,这样可以大大降低数据库的压力。
缓存的使用方式有两种:

  1. 通过程序直接保存到内存中
  2. 使用缓存框架
    程序直接操作主要是使用Map,尤其是ConcurrentHashMap, 常用的缓存框架主要有Ehcache、Memcache和Redis等。
    缓存使用过程中最重要的问题是: 什么时候创建缓存和缓存的失效机制
    缓存中空数据的管理方法:如果缓存是在第一次获取的时候创建的,那么在使用缓存的时候,最好将没有数据的缓存使用特定值来保存,这样如果缓存中获取不到数据就不会再从数据库中获取。否则,因为数据库中没有查出来数据,那么我们就没有放在缓存中, 当再次请求时,因为先看缓存里没有,那么又会去查一遍数据库,那么数据库里当然还是没有数据的。
    2、页面静态化
    跟缓存类似,只不过缓存是把从数据库中读出来的数据或着其他可以序列化的东西保存起来,而页面静态化是将程序生成的页面保存起来,使用页面静态化既不需要调用程序去生成页面也不需要查询数据库了,所有对处理高并发和海量数据都有好处。常见模版技术有freemarker、velocity,可以使用squid或着Nginx来在应用服务器的上一层缓存生成的页面。
    3、数据库优化
    3.1 表结构优化
    主要是数据库设计的三范式。

    第一范式
    1、每一列属性都是不可再分的属性值,确保每一列的原子性
    2、两列的属性相近或相似或一样,尽量合并属性一样的列,确保不产生冗余数据。
    第二范式
    所谓完全依赖是指不能存在仅依赖主关键字一部分的属性
    假定选课关系表为SelectCourse(学号, 姓名, 年龄, 课程名称, 成绩, 学分),关键字为组合关键字(学号, 课程名称),因为存在如下决定关系:
    (学号, 课程名称) → (姓名, 年龄, 成绩, 学分)
    这个数据库表不满足第二范式,因为存在如下决定关系:
    (课程名称) → (学分)
    (学号) → (姓名, 年龄)
    即存在组合关键字中的字段决定非关键字的情况。
    由于不符合2NF,这个选课关系表会存在如下问题:
    (1) 数据冗余:
    同一门课程由n个学生选修,”学分”就重复n-1次;同一个学生选修了m门课程,姓名和年龄就重复了m-1次。
    (2) 更新异常:
    若调整了某门课程的学分,数据表中所有行的”学分”值都要更新,否则会出现同一门课程学分不同的情况。
    (3) 插入异常:
    假设要开设一门新的课程,暂时还没有人选修。这样,由于还没有”学号”关键字,课程名称和学分也无法记录入数据库。
    (4) 删除异常:
    假设一批学生已经完成课程的选修,这些选修记录就应该从数据库表中删除。但是,与此同时,课程名称和学分信息也被删除了。很显然,这也会导致插入异常。
    第三范式
    数据不能存在传递关系,即每个属性都跟主键有直接关系而不是间接关系
    假定学生关系表为Student(学号, 姓名, 年龄, 所在学院, 学院地点, 学院电话),关键字为单一关键字”学号”,因为存在如下决定关系:
    (学号) → (姓名, 年龄, 所在学院, 学院地点, 学院电话)
    这个数据库是符合2NF的,但是不符合3NF,因为存在如下决定关系:
    (学号) → (所在学院) → (学院地点, 学院电话)
    即存在非关键字段”学院地点”、”学院电话”对关键字段”学号”的传递函数依赖。
    它也会存在数据冗余、更新异常、插入异常和删除异常的情况
    3.2、SQL语句优化
    通过把涉及大数据业务的SQL语句的执行时间详细记录下来,然后找出需要优化的语句和其中的问题。
    3.3、分区
    分区就是将一张表中的数据按照一定的规则分到不同的区来保存, 这样在查询数据时如果数据的范围在同一个区内那么可以只对一个区的数据进行操作,这样的操作量更少,速度更快,对程序透明,程序不需要做任何改动。
    3.4、分表
    适用于如果一张表中的数据可以分为几种固定不变的类型,而且如果同时对多种类型共同操作的情况不多,那么都可以通过分表来处理
    另一种分表的方法是将一个表中不同类型的字段分到不同的表中保存, 这样最直接的好处就是增删改数据的时候锁定的范围减小了。不同类型的字段可以这样分,经常增删改的和经常被用来查的。
    3.5、索引优化
    有待填充
    3.6、使用存储过程
    在操作过程复杂且调用频率较高的业务中,可以使用存储过程代替直接操作来提高效率,因为存储过程只需要编译一次。
    3.7、分离活跃数据
    虽然有些数据总数据量非常大,但是活跃数据并不多,这种情况就可以将活跃数据单独保存起来从而提高处理效率,比如一个网站有大量用户, 但是只有少数用户是活跃的,那么可以有个定时任务定期将不活跃的用户转移到别的数据表中,在主要操作的数据表中只保存活跃用户,查询时先查它,查不到再到不活跃的用户表中咯。
    3.8、批量读取和延迟修改
    原理是通过减少操作的次数来提高效率。
    批量读取是将多次查询合并到一次中进行。比如要插入一万条数据,并且要求每条数据都要从数据库中查一下是否有对应记录,以及值是否正确,还不如直接一次性全都查出来,只查一次。拿到结果在程序中判断。
    延迟修改主要针对高并发而且频繁修改的数据,这时可以将需要修改的数据暂时保存到缓存中,然后定时将缓存中的数据保存到数据库中, 这样有可能导致缓存和数据库里数据不一样的现象
    4、读写分离
    读写分离的本质是对数据库进行集群,这样就可以在高并发的情况下将数据库的操作分配到多个数据库服务器去处理从而降低单台服务器的压力, 这样就要求每台服务器所保存的数据具有一致性,所以数据库集群中数据同步就成了数据库集群中最是核心的问题。一般将有一台专门服务器作为一个写库,也就是主库,当主服务器写入数据后,就从底层同步到别的服务器,读数据的时候到从服务器读取,将读请求分配到多个服务器去处理。主服务器向从服务器同步数据时, 如果从服务器数量多,那么可以让主服务器先向其中一部分从服务器同步数据, 第一部分从 服务器接收到数据后再向另外一部分同步。
    这里写图片描述
    这就是读写分离结构图
    5、分布式数据库
    分布式数据库是将不同的表存放到不同的数据库中然后再放到不同的服务器。数据库集群的作用是将多个请求分配到不同的处理器处理,从而减轻单台服务器的压力,而分布式数据库是解决单个请求本身就非常复杂的问题,它可以将单个请求分配到多个处理器处理, 使用分布式后的每个结点还可以同时使用读写分离,从而可以组成多个结点群。这里写图片描述
    分布式数据库有很多复杂的问题需要解决,如事务处理、多表查询等。
    抽象哲学: 技术和架构只是一个工具,真正重要的是思路,也就是工具的使用方法
    6、NoSQL和Hadoop
    NoSQL 多用来做缓存,redis、Memcache等
    这里写图片描述
    Hadoop对数据的处理是对每一块的数据找到对应的节点并进行处理,然后再对每一个处理的结果进行处理,最后生成最终的结果。比如要查找符合条件的记录, Hadoop的处理方式是先找到每一块中的符合条件的记录, 然后再将所有获取到的结果合并到一起, 这样就可以将一个查询分到多个服务器去处理, 处理的速度也就快了。
    二、高并发的解决方案
    首先想说的是基本上都是出现了问题才有了演化的架构, 那么高并发的问题下,孵化出了什么呢? 
    1、应用和静态资源分离
    一开始应用和静态资源是保存在一起的,但是特么一些静态资源,比如图片、视频、js、css和一些资源文件等,这些文件因为没有状态,所以分离比较简单,直接放到响应的服务器就可以了,一般会使用专门的域名去访问。就不需要浪费应用服务器的性能了~
    这里写图片描述
    2、页面缓存
    不要忘了我们还要加入页面缓存,不需要调用应用程序重复生成页面,节省大量CPU资源。
    这里写图片描述
    3、集群与分布式
    集群与分布式再解释:集群和分布式处理都是使用多台服务器进行处理的, 集群是每台服务器都具有相同的功能,处理请求时多由代理服务器Nginx负载均衡哪一台服务器都可以,主要起分流的作用,分布式是将不同的业务放到不同的服务器中,处理一个请求可能需要用到多台服务器,这样就可以提高一个请求的处理速度,而且集群和分布式也可以同时使用。
    集群有两种方式:一种是静态资源集群, 另一种是应用程序集群。应用程序集群比较复杂, 因为应用程序在处理过程中可能会使用到一些缓存的数据,如果集群就需要同步这些数据, 比如Session,Session同步有两种方式,一种是在Session发生变化后自动同步到其它服务器, 另外一种方式是用一个程序统一管理Session, 所有的集群服务器都使用同一个Session, Tomcat默认是第一种方式。第二种方式通常都有专门的服务器安装redis等高效缓存程序来统一管理Session, 然后在应用程序中通过重写Request并覆盖getSession方法来获取指定服务器中的Session。
    这里写图片描述
    Session需要同步的本质原因是使用不同的服务器给同一个用户提供服务。
    4、反向代理
    反向代理主要的三个作用:

    1. 可以作为前端服务器跟实际处理请求的服务器(如Tomcat)集成2. 可以做负载均衡 3. 转发请求

这里写图片描述
5、CDN
CDN其实是一中特殊的集群页面缓存服务器,它和普通集群的多台页面缓存服务器比那就是它存放的位置和分配请求的方式有点特殊。CDN是分布在全国各地的,就像阿里巴巴全球都有分布。并且当接收到用户请求后会讲请求分配到最合适的CDN服务器节点获取数据。CDN每个节点的实质就是一 个页面缓存服务器,如果没有请求资源的缓存就从主服务器获取并加入缓存,否则直接返回页面。CDN请求分配到方式特殊在不是有专门的负载均衡器来分配, 而是由专门的CDN域名解析服务器在解析域名的时候分配好的,一般做法是在ISP那里使用CNAME将域名解析到一个特定的域名,然后再将解析到的那个域名用专门的CDN服务器解析到响应的CDN结点。
这里写图片描述
第二部访问CDN服务器是因为CNAME记录的目标域名使用NS记录指向了CDN的服务器。CDN每个节点也可能是多台服务器集群。
6、底层的优化
从网络底层协议上使用http/2
三、总结
网站架构的演变过程主要是围绕大数据和高并发这两个问题展开的。解决方案主要分为使用缓存和使用多资源两种类型

1 0
原创粉丝点击