Web Base (一) Architecture Evolution


一、网站架构及其演变过程

1、软件三大类型

软件三大类型:单机、C/S、B/S

2、基础架构

B/S 架构是最基础的结构,但是想做好它也并不容易,因为互联网是一个错综复杂的网络,数据在传输过程中有很多问题,而所有问题都有它对应的处理方法。

对于复杂问题,我们可以将其分解成多个简单的问题,通过解决每个简单问题,最终解决复杂问题。

BS 结构网络传输的分解方式有两种:

  • 标准的 OSI 参考模型
  • TCP/IP 参考模型

OSI 参考模型分为七层,但是它主要用于教学,实际使用多的还是 TCP/IP 的 4 层模型。

对于 TCP/IP 4 层模型可以简单理解为:(也可以看作一种协议)

  • 网络接入层:将需要相互连接的节点接入网络中,从而为数据传输提供条件 (没有协议
  • 网际互连层:找到要传输数据的目标节点 (IP协议)
  • 传输层:实际传输数据 (TCP协议
  • 应用层:使用接收到的数据 (HTTP协议

BS 架构中还使用到了 DNS 协议,并且在 HTTP 上层还有相关的规范,比如 Java Web 开发中的 Servlet 标准

补充:对于硬件是各种总线协议、对于网络传输来说就是网络协议

BS 架构虽然简单、基础,但是想要做好并不容易:

  • 用户交互
  • 海量数据处理
  • 高并发

前者是另一回事,后两者导致了现在网站越来越复杂的架构

3、架构演变的起点

基础架构中服务器就一台主机,部署了应用程序和数据库。

当数据和流量变得越来越大时,就需要将应用程序和数据库分开存放到不同主机

二、海量数据的解决方案

1、缓存和页面静态化

(1)缓存使用方式:

  • 通过程序保存到内存中
    • Map:ConcurrentHashMap
  • 使用缓存框架
    • 常用:EhcacheMemcacheRedis 等等
  • 最重要的问题:什么时候创建缓存和缓存的失效机制
    • 什么时候创建:
      • 第一次获取的时候创建
      • 程序启动
      • 缓存失效之后立即创建
    • 缓存失效机制:
      • 定期失效
      • 数据变化时失效
        • 粗粒度失效
        • 细粒度失效

mark:缓存中空数据管理

(2)页面静态化

原理和缓存类似:缓存是将从数据库(也可以是从其他地方序列化而来)中取到的数据保存起来,而页面静态化是将程序最后生成的页面保存起来,

  • 使用模板技术生成:
    • 常用的 FreemarkerVelocity,可以根据模板生成静态页面
    • 使用缓存服务器在应用服务器的上一层缓存生成的页面:比如 Squid
    • Nginx 也提供了相关功能

2、数据库优化

常用:

  • 表结构优化

  • SQL 语句优化

    • 语法层面的优化、处理逻辑的优化(和索引缓存配合)
    • 通用SQL优化方法:记录目标 SQL 语句的执行时间、仔细分析日志,找出要优化的语句和其中的问题
  • 分区和分表

    • 分区:将一张表的数据按照一定的规则分到不同的区来保存,这样在查询数据时如果数据的范围在同一区内那么可以只对一个区的数据进行操作,这样操作的数据量更少、速度更快
    • 分表:如果一张表的数据可以分为几种固定不变的类型,而且如果同时对多种类型共同操作的情况不多,那么都可以通过分表来处理,这也需要具体情况具体对待
    • 另一种分表方法:将一个表中不同类型的字段分到不同的表中保存,这么做最直接的好处就是增删改数据的时候锁定的范围减小了,没被锁定的表中的数据不受影响。但是查询的时候需要多表联查
  • 索引优化

    • 索引的大致原理:数据发生变化(增删改)的时候就预先指定字段的顺序排列后保存到一个类似表的结构中,这样在查找索引字段为条件的记录时就可以很快从索引中找到对应记录的指针并从表中获取到记录
    • 索引是一把双刃剑:提高查询速度的同时降低了增删改的速度,每次数据变化都需要更新索引
    • 使用方法:合理使用索引、对哪些字段使用索引、使用什么类型的索引、做一些测试
  • 使用存储过程代替直接操作

    • 操作过程中复杂而且调用频率高的业务中,可以通过使用存储过程代替直接操作来提高效率,因为存储过程只需要编译一次,而且可以在一个存储过程中做一些复杂操作
  • 合理使用冗余

3、分离活跃数据

有些数据总数据量非常大,但是活跃数据并不多,这种情况可以将活跃数据单独保存起来从而提高处理效率。

例子:对网站来说,用户数据很重要

  • 可以按照指定规则:比如上一次登录时间、指定时间段的登录次数等等规则
  • 写一个定时任务,按照上述规则将不活跃的用户转移到另一张表
  • 用户登录时:先从活跃表中查数据、查不到再去不活跃表、还找不到就是未注册用户

4、批量读取和延迟修改

批量读取和延迟修改的原理是通过减少操作次数来提高效率。

  • 批量读取:将多次查询合并到一次中进行
  • 延迟修改:主要针对高并发而且频繁修改(包括新增)的数据,如一些统计数据。这种情况可以先将需要修改的数据暂时保存到缓存中,然后定时将缓存中的数据保存到数据库中,程序在读取的时候可以同时读取数据库中和缓存中的数据。这里的缓存和前面将的缓存有本质的区别,前面的缓存在使用过程中,数据库中的数据一直是完整的,但是现在数据库中数据有一段时间是不完整的。所以这种情况如果保存缓存的机器出了问题将可能丢失数据。

5、读写分离

读写分离的本质是对数据库进行集群,这样可以在高并发情况下将对数据库的操作分配到多个数据库服务器去处理从而降低单台服务器的压力。

但是:由于数据库的特殊性 —— 每台服务器需要保存的数据都需要一致,所以数据同步就成了数据库集群最核心的问题。

专门负责写的服务器叫做主服务器。主服务器写入(增删改)数据后从底层同步到其他从服务器,读数据时从从服务器中读取。

处理策略

简单的数据同步方式可以采用数据库的热备份功能,不过读取到的数据可能会存在一定的滞后性,高级的方式需要使用专门的软硬件配合。(比如 MySQL + canal)

另外既然是集群就涉及到负载均衡问题,负载均衡和读写分离的操作一般采用专门程序处理,而且对应用系统来说是透明的。

6、分布式数据库

分布式数据库是将不同的表存放到不同的数据库后然后再放到不同的服务器。这样在处理请求时,如果需要调用多个表,则可以让多台服务器同时处理,从而提高效率。

注意:读写分离和分布式数据库的使用场景

  • 数据库集群(读写分离)的作用是将多个请求分配到不同的服务器处理,从而减轻单台服务器的压力
  • 分布式数据库是解决单个请求本身就非常复杂的问题,它可以将单个请求分配到多个服务器处理,使用分布式后的每个节点还可以同时使用读写分离,从而组成多个节点群

真正使用分布式数据库还有很多问题,比如事务处理、多表查询等等

重要是思路

7、NoSQL 和 Hadoop

  • NoSQL:非关系型数据库
  • Hadoop:处理大数据的框架

两者结合处理海量大数据

三、高并发的解决方案

1、应用和静态资源分离

  • 早期应用程序和静态资源放在一起,当并发量达到一定程度就需要将静态资源保存到专门的服务器

2、页面缓存

页面缓存是将应用生成的页面缓存起来,这样就不需要每次都重新生成页面。

如果使用了 Nginx 服务器可以使用自带的缓存功能,当然也可以使用专门的 Squid 服务器。

页面缓存的失效机制一般按照缓存时间处理,当然也可以在修改数据之后手动让缓存失效。

mark:某些页面中有部分数据经常变化,该如何使用页面缓存?

  • 页面缓存主要使用在数据很少发生变化的页面
  • 但是有部分页面中只有一小部分数据经常变化(比如视频网站中顶和踩)
  • 这个问题可以这样干:先生成静态页面,然后使用 Ajax 来读取并修改相应的数据

3、集群和分布式

概览

集群和分布式都是使用多台服务器进行处理的。

  • 集群是每台服务器都具备相同的功能,处理请求时调用哪台服务器都可以,主要起到分流的作用
  • 分布式是将不同的业务放到不同的服务器中,处理一个请求可能会用到多台服务器,这样可以提高一个请求的处理速度
  • 集群和分布式可以同时使用

集群

集群有两种方式:

  • 静态资源集群
  • 应用程序集群(比较复杂)
    • 应用程序在处理时可能会用到缓存,如果集群需要同步这些数据,其中最重要的一个点就是 Session,Session 同步也是应用程序集群中非常核心的一个问题
    • Session 不同两种处理方式:
      • 一:Session 变化后自动同步到其他服务器
      • 二:用一个程序统一管理 Session
    • 所有集群的服务器都使用同一个 Session
      • Tomcat 默认使用第一种方式
      • 第二种方式可以使用专门的服务器安装 Memcached 等高效的缓存程序来统一管理 Session,然后在应用程序中通过重写 Request 并覆盖 getSession 方法来获取指定服务器中的 Session
  • 对于集群来说有一个重要的问题就是负载均衡

现在如何处理这些问题?

4、反向代理

反向代理指客户端直接访问的服务器并不真正提供服务,它从别的服务器获取资源然后将结果返回给客户。

反向代理服务器和代理服务器

  • 反向代理服务器:我们正常访问一台服务器时,服务器自己调用了其他服务器的资源将结果返回给我们,我们并不知道
  • 代理服务器:代我们想要获取的资源然后将结果返回给我们,所要获取的资源是我们主动告诉服务器的(比如 VPN)
  • 代理服务器是我们主动使用的,是为我们服务的,它不需要有自己的域名;反向代理服务器是服务器自己使用的,我们并不知道,它有自己的域名,我们访问它和访问正常的网址没有任何区别

反向代理服务器的三个作用:

  • 可以作为前端服务器跟实际处理请求的服务器(如 Tomcat)集成
  • 可以用作负载均衡
  • 转发请求,比如可以将不同类型的资源请求转发到不同的服务器去处理,可以将动态资源转发到 Tomcat、Php 等动态程序,将静态资源如图片的请求转发到静态资源服务器,另外也可以在 url 地址结构发生变化后将新地址转发到原有的旧地址上

5、CDN

CDN 其实就是一种特殊的集群页面缓存服务器,它和普通集群的多台页面缓存服务器比主要是它存放的位置和分配请求的方式有点特殊。

CDN 的服务器是分布在全国各地的,当接收到用户请求后会将请求分配到最合适的 CDN 服务器节点数据获取数据,比如,联通用户会分配到联通节点,电信用户会分配到电信节点;另外还会按照地理位置进行分配,比如上海用户分配到上海节点。

CDN 的每一个节点其实就是一个页面缓存服务器,如果没有找到请求资源的缓存就会到主服务器上获取,否则直接返回缓存页面。

CDN 分配请求的方式比较特殊,它并不是使用普通的负载均衡服务器来分配,而是用专门的 CDN 域名解析服务器在解析域名的时候就分配好的。一般做法是在 ISP 那里使用 CNAME 将域名解析到一个特定的域名,然后再将解析到的那个域名用专门的 CDN 服务器解析到相应的 CDN 节点。

我们知道 DNS 服务器是域名解析服务器,正常而言通过 DNS 服务器会将域名解析成 IP 地址,然后直接返回。

但是 CDN 不一样,当我们访问 CDN 域名是,先去找 DNS 服务器,而 DNS 服务器使用 CNAME 记录的目标域名使用 NS 记录指向了 CDN 的 DNS 服务器。

CDN 的每个节点可能也是集群了多台服务器。

6、底层的优化

所有的架构都是建立在前面介绍的基础架构之上的,而且很多地方都需要网络传输数据,如果可以加快网络传输的速度,那会让整个系统从根本上得到改善。

网络传输数据都是按照各种协议进行的,不过协议并非不可改变。

四、总结

  • 网站架构演进主要围绕两个方面:海量数据、高并发
  • 解决方案主要分为:使用缓存、使用多资源 两种类型
    • 多资源主要指多存储(包括多内存)、多CPU和多网络
    • 多资源又可以分:单个资源处理一个完整请求和多个资源合作处理一个请求
      • 多存储和多CPU中的集群和分布式
      • 多网络中的 CDN 和静态资源分离

一个网站使用什么样的架构需要根据实际做出选择,只要可以满足需要、可以解决问题就可以了。

想要设计出合理的架构首先需要理解每种架构所针对的问题和它背后的本质。

另外在使用复杂架构之前一定要先将业务优化好,这是基础中的基础。


Author: NaiveKyo
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source NaiveKyo !
  TOC