高并发的解决方案
除了数据量大, 另一个常见的问题就是并发量高, 很多架构就是针对这个问题设计出来的, 下面分别介绍。
1.应用和静态资源分离
刚开始 的 时候 应用 和静 态 资源 是 保存 在一起 的, 当 并发 量 达到 一定程度 时 就 需要 将 静态 资源 保存 到 专门 的 服务器 中, 静态 资源 主要 包括 图片、 视频、 js、 css 和 一些 资源 文件 等, 这些 文件 因为 没有 状态, 所以 分离 比较 简单, 直接 存放 到 相应 的 服务器 就可以 了, 一般 会使 用 专门 的 域名 去 访问, 比如, 新 浪的 图片 保存 在 sinaimg. cn 域名 对应 的 服务器 中, 而 百度 的 图片 则是 通过 imgsrc. baidu. com 二级 域名 访问 的, 通过 不同 的 域名 可以 让 浏览器 直接 访问 资源 服务器 而 不需要 再访 问 应用 服务器 了, 这时 的 架构 如图 1- 8 所示。
2.页面缓存
页面缓存是将应用生成的页面缓存起来, 这样 就不 需要 每次 都 重新 生成 页面 了, 从而 可以 节省 大量 CPU 资源, 如果 将 缓存 的 页面 放到 内存 中 速度 就 更快 了。 如果 使用 了 Nginx 服务器 就可以 使用 它 自带 的 缓存 功能, 当然 也可以 使用 专门 的 Squid 服务器。 页面 缓存 的 默认 失效 机制 一般 是按 缓存 时间 处理 的, 当然 也可 以在 修改 数据 之后 手动 让 相应 缓存 失效。
有部分经常变化的数据的页面怎么使用页面缓存
页面缓存主要是使用在数据很少发生变化的页面中, 但是 有很 多 页面 是 大部分 数据 都很 少发 生 变化, 而 其中 有 很少 一部分 数据 变化 的 频率 却 非常 高, 比如, 一个 显示 文章 的 页面 正常 来说 是 完全可以 静态 化 的, 但是 如果 在 文章 后面 有“ 顶” 和“踩” 的 功能 而且 显示 的 有 相应 的 数量, 这个 数据 的 变化 频率 就比 较高 了, 这就 会 影响 静态 化, 在 电 商 系统 中 显示 商品 详情 的 页面 中的 销售 数量 也是 这种 情况, 对于 这个 问题 可以 先生 成 静态 页面 然后 使用 Ajax 来 读取 并修 改 相应 的 数据, 这样 就可以 一举两得 了, 既可以 使用 页面 缓存 也可以 实时 显示 一些 变化 频率 高的 数据 了。
3.集群与分布式
集群和分布式处理都是使用多台服务器进行处理的, 集群 是 每 台 服务器 都 具有 相同 的 功能, 处理 请求 时 调用 哪 台 服务器 都可以, 主要 起 分流 的 作用, 分布式 是将 不同 的 业务 放到 不同 的 服务器 中, 处理 一个 请求 可能 需要 用到 多台 服务器, 这样 就可以就可以 提高 一个 请求 的 处理 速度, 而且 集群 和 分布式 也可以 同时 使用, 结构图 如图 1- 9 所示。
集群 有两 个 方式: 一种 是 静态 资源 集群。 另一种 是 应用 程序 集群。 静态 资源 集群 比较 简单, 而 应用 程序 集群 就有 点 复杂 了。 因为 应用 程序 在 处理 过程中 可能 会使 用到 一些 缓存 的 数据, 如果 集群 就 需要 同步 这些 数据, 其中 最重要的 就是 Session, Session 同步 也是 应用 程序 集群 中非 常 核心 的 一个 问题。 Session 同步 有两 种 处理 方式: 一种 是在 Session 发生 变化 后 自动 同步 到 其他 服务器, 另外 一种 方式 是 用 一个 程序 统一 管理 Session。 所有 集群 的 服务器 都 使用 同一个 Session, Tomcat 默认 使用 的 就是 第一 种 方式, 通过 简单 的 配置 就可以 实现, 第二 种 方式 可以 使用 专门 的 服务器 安装 Memcached 等 高效 的 缓存 程序来 统一 管理 Session, 然后 在 应用 程序 中 通过 重写 Request 并 覆盖 getSession 方法 来 获取 指定 服务器 中的 Session。 对于 集群 来说 还有 一个 核心 的 问题 就是 负载 均衡, 也就是 接收 到 一个 请求 后 具体 分配 到 哪个 服务器 去 处理 的 问题, 这个 问题 可以 通过 软件 处理 也可以 使用 专门 的 硬件( 如 F5) 解决。
另外还想到了 一种 思路 可以 简单 地 解决 Session 同步 的 问题, Session 需要 同步 的 本质 原因 就是 要使 用 不同 的 服务器给 同一个 用户 提供 服务, 如果 负载 均衡 在 分配 请求 时 可以 将同 一个 用户( 如按 IP) 分配 到 同 一台 服务器 进行 处理 也就 不需要 Session 同步 了, 而且 这种 方法 一般 也不 会对 负载 均衡 带来 太大 的 问题, 如果 考虑到 稳定性, 为了 防止 有 机器 宕 机 后 丢失 数据 还可以 将 集群 的 服务器 分成 多个 组, 然后 在 小 范围 的 组( 如 2、 3 台 服务器) 内 同步 Session。
架设 分布式 应用 程序 是一 件 非常 复杂 的 事情, Session 同步 肯定 是 需要 的, 分布式 事务处理 和 各个 节点 之间 复杂 的 依赖 关系 也是 分布式 中非 常 复杂 的 问题, 如果 要 使用 分布式 一定 要做 好 足够 的 准备。
4.反向代理
反向代理指的是客户端直接访问的服务器并不 真正 提供 服务, 它 从 别的 服务器 获取 资源 然后 将 结果 返回 给用户 的, 如图 1- 10 所示。
反向代理服务器和代理服务器的区别
代理 服务器 的 作用 是 代我 们 获取 想要 的 资源 然后 将 结果 返回 给我 们, 所要 获取 的 资源 是我 们 主动 告诉 代理 服务器 的, 比如,我们 想 访问 Facebook, 但是 直接 访问 不了, 这时 就可以 让 代理 服务器 访问, 然后 将 结果 返回 给我 们。
反向 代理 服务器 是我 们 正常 访问 一台 服务器 的 时候, 服务器 自己 调用 了 别的 服务器 的 资源 并将 结果 返回 给我 们, 我们自己 并不 知道。
代理 服务器 是我 们 主动 使用 的, 是 为我 们 服务 的, 它不 需要 有 自己的 域名; 反向 代理 服务器 是 服务器 自己 使用 的, 我们 并不 知道, 它有 自己的 域名, 我们 访问 它 跟 访问 正常 的 网址 没有 任何 区别。
反向 代理 服务器 可以 和 实际 处理 请求 的 服务器 在 同一 台 主机 上, 而且 一台 反向 代理 服务器 也可以 访问 多台 实际 处理 请求的 服务器。 反向 代理 服务器 主要 有 三个 作用:
① 可以 作为 前端 服务器 跟 实际 处理 请求 的 服务器( 如 Tomcat) 集成;
② 可 以用 做 负载 均衡;
③ 转发 请求, 比如, 可以 将不 同类型 的 资源 请求 转发 到 不同 的 服务器 去 处理, 可以 将 动态 资源 转发 到 Tomcat、 Php 等 动态 程序 而将 图片 等 静态 资源 的 请求 转发 到 静态 资源 的 服务器, 另外 也可 以在 url 地址 结构 发生 变化 后 将 新地 址 转发 到 原来 的 旧 地址 上。
5.CDN
CDN 其实 是一 种 特殊 的 集群 页面 缓存 服务器, 它 和 普通 集群 的 多台 页面 缓存 服务器 比 主要 是它 存放 的 位置 和 分配 请求 的 方式 有点 特殊。 CDN 的 服务器 是 分布 在 全国各地 的, 当 接收 到 用户 的 请求 后 会 将 请求 分配 到 最 合适 的 CDN 服务器 节点 获取 数据, 比如, 联 通 的 用户 会 分配 到 联 通 的 节点, 电信 的 用户 会 分配 到 电信 的 节点; 另外 还会 按照 地理 位置 进行 分配, 北京 的 用户 会 分配 到 北京 的 节点, 上海 的 用户 会 分配 到 上海 的 节点。 CDN 的 每个 节点 其实 就是 一个 页面 缓存 服务器, 如果 没有 请求 资源 的 缓存 就会 从 主 服务器 获取, 否则 直接 返回 缓存 的 页面。CDN 分配 请求 的 方式 比较 特殊, 它 并不是 使用 普通 的 负载 均衡 服务器 来 分配 的, 而是 用 专门 的 CDN 域名 解析 服务器 在 解析 域名 的 时候 就 分配 好的, 一般 的 做法 是在 ISP 那里 使用 CNAME 将 域名 解析 到 一个 特定 的 域名, 然后 再将 解析 到 的 那个 域名 用 专门 的 CDN 服务器 解析 到 相应 的 CDN 节点, 结构图 如图 1- 11 所示。
第二 步 访问 CDN 的 DNS 服务器 是因为 CNAME 记录 的 目标 域名 使用 NS 记录 指向 了 CDN 的 DNS 服务器。 CDN 的 每个 节点 可能 也是集群 了 多台 服务器。 CDN 的 原理 并不 复杂, 不过 如果 要 自己 去 架设 则需 要 投入 大量 的 资金, 现在 有 专门 的 CDN 服 务商, 可以 直接 购买 它们 的 服务。
来自:韩路彪 著. 看透Spring MVC:源代码分析与实践 (Web开发技术丛书)