对于我们所研发的网站,若网站的访问量非常大,那么我们必须考虑相关的并发访问问题,而并发问题是绝大部分的程序员头疼的问题。带你领略一下相关概念和解决方案:
概念类:
- 什么是 QPS、PV、UV、QPS 不等于并发连接数?
- 大中小三种类型网站的 QPS 一般是多少?
- 具体解决方案:数据库层面、Web 负载层面、IP Hash 策略、Nginx 负载均衡策略......
第一章 哪些必须掌握的常用概念
1.1 什么是 QPS?
QPS:
每秒查询率(Query Per Second),每秒的响应请求数,也即是最大吞吐能力。 QPS = req / sec = 请求数 / 秒。 QPS 统计方式 (一般使用 http _ load 进行统计)。 QPS = 总请求数 / ( 进程总数 * 请求时间 )。 QPS:单个进程每秒请求服务器的成功次数。
峰值QPS:
原理:每天 80% 的访问集中在 20 % 的时间里,这 20 % 时间叫做峰值时间。
单台服务器每天 PV 计算
公式1:每天总 PV = QPS * 3600 * 6 。 公式2:每天总 PV = QPS * 3600 * 8。
集群服务器计算
服务器数量 = ceil(每天总 PV / 单台服务器每天总 PV) 峰值 QPS 和机器计算公式
-
原理:每天 80 % 的访问集中在 20 % 的时间里,这 20 % 时间叫做峰值时间 。
-
公式:( 总 PV 数 * 80 % ) / ( 每天秒数 * 20 % ) = 峰值时间每秒请求数(QPS)
-
机器:峰值时间每秒 QPS / 单台机器的 QPS = 需要的机器
举例 1: 每天 600 w PV 的在单台机器上,这台机器需要多少 QPS? ( 6000000 * 0.8 ) / (86400 * 0.2 ) = 278 (QPS)
举例 2: 如果一台服务器机器的 QPS 是 58,需要几台机器来支持? 278 / 65 = 4.3 采用进 1 算法,需要 5 台机器支持。
以上 数据仅供参考,勿要对应自己服务器,请以自己服务器的性能为准。
1.2 什么是 PV?
PV 是 page view 的缩写,即页面浏览量,或点击量;通常是衡量一个媒体频道或网站甚至一条网络文章的主要指标。
控制 PV 的网站:24 小时算一次 PV 。
普通的 PV 的网站:每访问一次 PV 增加一次。
提醒: 针对大并发和大流量的网站,一定要做好这个,否则,黑客利用 PV 漏洞,及其容易刷 PV,导致服务器崩溃。
PV:一个网站的 PV,从某种程度上已成为投资者衡量商业网站表现的最重要尺度,可以通过专业的工具查询和计算。
1.3 什么是UV ?
UV:
独立访客即 Unique Visitor,访问您网站的一台电脑客户端为一个访客。00:00 - 24:00 内相同的客户端只被计算一次,指访问某个站点或点击某条新闻的不同 IP 地址的人数。
在同一天内,uv 只记录第一次进入网站的具有独立 IP 的访问者,在同一天内再次访问该网站则无效。独立 IP 访问者提供了一定时间内不同观众数量的统计指标,而没有反应出网站的全面活动状况。
分析:PV 和 UV 各有各的用途,但是往往 UV 更为准确,但是 PV 更能查看活动值。
1.4 什么是 PR 值
PR 值,即 PageRank,网页的级别技术。取自 Google 的创始人 Larry Page,它是 * 运算法则(排名公式)的一部分,用来标识网页的等级 / 重要性。级别从 1 到 10 级,10 级为满分。PR 值越高说明该网页越受欢迎(越重要)。
一个 PR 值为 1 的网站表明这个网站不太具有流行度,而 PR 值为 7 到 10 则表明这个网站非常受欢迎。
我们可以这样说:一个网站的外部链接数越多其 PR 值就越高;外部链接站点的级别越高,网站的 PR 值就 越高。
例如:如果 https://edu.csdn.net/course/detail/8566 网站上有一个 www.ceshi.com 网站的链接,那为 CSDN 网站必须提供一些干货,搜索引擎认为来自 ceshi.com 的友情链接,从而对 CSDN 的网站增加PR值。
1.5 QPS 不等于并发连接数
通过前面的计算公式和各自概念的关系:我们得出结论 QPS 不等于并发连接数。
QPS 是每秒 HTTP 请求数量,并发连接数是系统同时处理的请求数量。
(总 PV 数 80 %)/(6小时秒数 20 %)= 峰值每秒请求数(QPS) 80 % 的访问量集中在 20 % 的时间。
这点谨防在面试中误入陷阱,面试中该部分是拔高的部分,很多人被面试官带偏。如果面试者答不上来你自己做的系统是 QPS 和并发连接数,或者误认为是一个的话,在以后的谈薪资等容易被动,甚至让你回家等消息了,因为这是实际项目经验不可或缺的一部分,要不你不上心。
那么如果被面试官问道你做的网站的 QPS 是多了?你该怎么回答?尤其是对这方面缺乏或者没有实战经验的同学,请查看下面的章节。
第二章 大中小三种类型网站的 QPS 一般是多少?
随着 QPS 的增长,每个阶段需要根据实际情况来进行优化,优化的方案也与服务器等硬件、网络带宽等现实的物理条件息息相关。
2.1网站的大小标准
一个网站的“大小”,所采用的架构不同,用到的技术也大相径庭,众多种衡量的方法 。对于并发业界的,存在争议,这里从数量级层面总结归纳一下。
网站的热度:日均 PV,同时在线人数、注册用户数,活跃用户等运营数据。
互联网的“3 秒定律”,大型网站要求 1.5 秒以内加载整页,或者至少可以达到浏览。
2.2 分类
2.2.1 平均值 < 50QPS
小型网站,一般的服务器就可以应付,可以用最简单的方法快速搭建,短期没有太多的技术瓶颈,只要服务器稳定即可,网络通畅即可。
2.2.2 50QPS < 平均值 < 100QPS
DB 数据库极限型:常用的关系型数据库的每次请求大多都能控制在 0.01 秒左右,就算你研发的 Web 网站每页面只有一次数据库请求,那么页面请求无法保证在 1 秒钟内完成 100 个请求,这个阶段要考虑做 Cache 或者多 DB 负载。
2.2.3 300QPS<平均值<800QPS
带宽极限型
服务器常用 IDC 提供的“百兆带宽”,这意味着网站出口的实际带宽是 8 M Byte左右。假定每个页面只有 10 K Byte,在这个并发条件下,百兆带宽已经快速的占用资源完毕。
这要就可能考虑优化的技术如同:CDN 加速 & 异地缓存,集群负载等技术。
2.2.4 500QPS < 平均值 < 1000QPS
内网带宽极限+缓存极限型
由于 Key/value 的特性,每个页面对缓存技术的请求远大于直接对 DB 的请求。
例:Memcache 的悲观并发数在 2w 左右,现在的实际项目,可能在大并发之前内网的带宽就已经吃光。
压力测试的时候,在 7991QPS 的时候,memcached 已经不稳定,存在各种无法预知的程序问题,这时压力迅速到到 mysql 的数据库上了,整个系统性能迅速下降,这样就会出现网站访问变慢,甚至无法访问的 404 等情况,当时做的是 wait.xxxxx.com,跳转到等待界面,这样提示更加的友好。
2.2.5 1000QPS < 平均值 < 2000QPS
FORK / SELECT,锁模式极限型
线程模型决定吞吐量。不管你系统中最常见的锁是什么锁,这个级别下,文件系统访问锁都成为了灾难。这就要求系统中不能存在中央节点,所有的数据都必须分布存储,数据需要分布处理。总之, 分布
提醒:这个是常说的是否需要做分布式的标准,如果达到了这个标准,必须做分布式。
2.2.6 2000 QPS < 平均值
C10K 极限 现在阿里的技术以及实现了 C25K,但熟悉 java 的短板理论,木桶原理很明显我们能得出, 网站整体并发的永远是最慢的那个。在阿里巴巴的双 11 的晚上 24 点的时候,肯定超过这个值。
第三章 具体的解决方案
以下内容都是在实际项目中遇到的各种瓶颈或者问题,经过了团队讨论,前辈的请教,闭关的修炼,查阅大量技术官网或者文档,最后的总结,结合市面上的各种成熟方案,以及当下硬件,宽带等多方面的局限,经过了研发团队的打磨和面试中,面试高工或者架构师的门槛,总结如下:供大家在日常业务中参考和面试中升职加薪。
3.1 数据库层面
数据库缓存层的优化:数据库集群、库表散列 自从去 IOE 之后,大批量的软件研发团队和企业都开始研究使用 Mysql,缓存等作为存储设备。本文以 mysql 的数据库层面去探索优化的意义。
下面具体给大家说一说
数据库存储引擎是数据库底层软件组织,数据库管理系统使用数据引擎进行创建、查询、更新和删除数据。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎,还可以 获得特定的功能。现在许多不同的数据库管理系统都支持多种不同的数据引擎。
-
-
3.1.1 InnoDB 存储引擎
InnoDB 是事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键,InnoDB 是默认的 MySQL 引擎。InnoDB 主要特性有:
1、InnoDB 给 MySQL 提供了具有提交、回滚和崩溃恢复能力的事物安全(ACID 兼容)存储引擎。InnoDB 锁定在行级并且也在 SELECT 语句中提供一个类似 Oracle 的非锁定读。这些功能增加了多用户部署和性能。在 SQL 查询中,可以自由地将 InnoDB 类型的表和其他 MySQL 的表类型混合起来,甚至在同一个查询中也可以混合。
2、InnoDB 是为处理巨大数据量的最大性能设计。它的 CPU 效率可能是任何其他基于磁盘的关系型数据库引擎锁不能匹敌的。
3、InnoDB 存储引擎完全与 MySQL 服务器整合,InnoDB 存储引擎为在主内存中缓存数据和索引而维持它自己的缓冲池。InnoDB 将它的表和索引在一个逻辑表空间中,表空间可以包含数个文件(或原始磁盘文件)。这与 MyISAM 表不同,比如在 MyISAM 表中每个表被存放在分离的文件中。InnoDB 表可以是任何尺寸,即使在文件尺寸被限制为 2 GB 的操作系统上。
4、InnoDB 支持外键完整性约束,存储表中的数据时,每张表的存储都按主键顺序存放,如果没有显示在表定义时指定主键,InnoDB 会为每一行生成一个 6 字节的 ROWID,并以此作为主键。
5、InnoDB 被用在众多需要高性能的大型数据库站点上。
InnoDB 不创建目录,使用 InnoDB 时,MySQL 将在 MySQL 数据目录下创建一个名为 ibdata1 的 10 MB 大小的自动扩展数据文件,以及两个名为 ib _ logfile0 和 ib _ logfile1 的 5 MB 大小的日志文件。
3.1.2 MyISAM 存储引擎
MyISAM 基于 ISAM 存储引擎,并对其进行扩展。它是在 Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM 拥有较高的插入、查询速度,但不支持事物。
MyISAM 主要特性有:
1、大文件(达到 63 位文件长度)在支持大文件的文件系统和操作系统上被支持。
2、当把删除和更新及插入操作混合使用的时候,动态尺寸的行产生更少碎片。这要通过合并相邻被删除的块,以及若下一个块被删除,就扩展到下一块自动完成。
3、每个 MyISAM 表最大索引数是 64,这可以通过重新编译来改变。每个索引最大的列数是 16。
4、最大的键长度是 1000 字节,这也可以通过编译来改变,对于键长度超过 250 字节的情况,一个超过 1024 字节的键将被用上。
5、BLOB 和 TEXT 列可以被索引。
6、NULL 被允许在索引的列中,这个值占每个键的 0 ~ 1 个字节。
7、所有数字键值以高字节优先被存储以允许一个更高的索引压缩。
8、每个 MyISAM 类型的表都有一个 AUTO _ INCREMENT 的内部列,当 INSERT 和 UPDATE 操作的时候该列被更新,同时 AUTO _ INCREMENT 列将被刷新。所以说,MyISAM 类型表的 AUTO _ INCREMENT 列更新比 InnoDB 类型的 AUTO _ INCREMENT 更快。
9、可以把数据文件和索引文件放在不同目录。
10、每个字符列可以有不同的字符集。
11、有 VARCHAR 的表可以固定或动态记录长度。
12、VARCHAR 和 CHAR 列可以多达 64KB。
使用 MyISAM 引擎创建数据库,将产生 3 个文件。文件的名字以表名字开始,扩展名之处文件类型:frm 文件存储表定义、数据文件的扩展名为 .MYD(MYData)、索引文件的扩展名时 .MYI(MYIndex)。
3.1.3 MEMORY 存储引擎(也叫 HEAP)堆内存
MEMORY 存储引擎将表中的数据存储到内存中,未查询和引用其他表数据提供快速访问。
MEMORY主要特性有:
1、MEMORY 表的每个表可以有多达 32 个索引,每个索引 16 列,以及 500 字节的最大键长度。
2、MEMORY 存储引擎执行 HASH 和 BTREE 缩影。
3、可以在一个 MEMORY 表中有非唯一键值。
4、MEMORY 表使用一个固定的记录长度格式。
5、MEMORY 不支持 BLOB 或 TEXT 列。
6、MEMORY 支持 AUTO _ INCREMENT 列和对可包含 NULL 值的列的索引。
7、MEMORY 表在所由客户端之间共享(就像其他任何非 TEMPORARY 表)。
8、MEMORY 表内存被存储在内存中,内存是 MEMORY 表和服务器在查询处理时的空闲中,创建的内部表共享。
9、当不再需要 MEMORY 表的内容时,要释放被 MEMORY 表使用的内存,应该执行 DELETE FROM或TRUNCATE TABLE,或者删除整个表(使用 DROP TABLE)。
3.1.4 EXAMPLE 存储引擎
是一个 “ 存根 ” 引擎,它不做什么。你可以用这个引擎创建表,但没有数据被存储于其中或从其中检索。这个引擎的目的是服务,在 MySQL 源代码中的一个例子,它演示说明如何开始编写新存储引擎。同样,它的主要兴趣是对开发者。
3.1.5 NDB Cluster
是被 MySQL Cluster 用来实现分割到多台计算机上的表的存储引擎。
它在 MySQL - Max 5.1 二进制分发版里提供。这个存储引擎当前只被 Linux,Solaris,和 Mac OS X 支持。在未来的 MySQL 分发版中,我们想要添加其它平台对这个引擎的支持,包括 Windows。
3.1.6 ARCHIVE 存储引擎 被用来无索引地,非常小地覆盖存储的大量数据。
3.1.7 CSV 存储引擎 把数据以逗号分隔的格式存储在文本文件中。
3.1.8 BLACKHOLE 存储引擎 接受但不存储数据,并且检索总是返回一个空集。
3.1.9 FEDERATED 存储引擎
把数据存在远程数据库中,在 MySQL 5.1 中,它只和 MySQL 一起工作,使用 MySQL C Client API。在未来的分发版中,我们想要让它使用其它驱动器或客户端连接方法连接到另外的数据源。
在实际高并发项目中:
MySQL 等一些常见的关系型数据库的数据都存储在磁盘中,在高并发场景下,业务应用对 MySQL 产生的增、删、改、查的操作造成巨大的 I/O 开销和查询压力, 数据库和服务器都是一种巨大的压力,为了解决此类问题,缓存数据的概念应运而生。
缓存数据是为了让客户端很少甚至不访问数据库服务器进行数据的查询,高并发下,能最大程度的降低对数据库服务器的访问压力极大地解决数据库服务器的压力。
提高应用数据的响应速度
用户请求 --> 数据查询 --> 连接数据库服务器并查询数据-->将数据缓存起来(HTML、内存、JSON、序列化数据)--> 显示给客户端 用户再次请求或者新用户访问 --> 数据查询 --> 直接从缓存中获取数据 --> 显示给客户端
3.2 联姻的数据库
引入缓存可以提高性能,但是数据会存在两份,一份在数据库中,一份在缓存中,如果更新其中任何一份会引起数据的不一致,数据的完整性被破坏了,因此,同步数据库和缓存的这两份数据就非常重要。本文介绍常见的缓存更新的同步策略。
1.预留缓存 Cache-aside
应用代码能够手工管理数据库和缓存中数据,应用逻辑会在访问数据库之前检查缓存,在数据库更新以后再更新缓存。
通过手工编码分别对数据库 save() 和缓存 (put(key,entity)) 做更新,将这种琐碎的缓存管理和更新夹杂在应用逻辑中并不是一种好方式,可以采取 AOP 面向方面拦截器等方式实现缓存操作,减轻缓存操作泄漏到应用代码中,同时确保数据库和缓存都能正确同步。
2.Read-through(同步读取)
如果缓存中不存在某个项目,则对 DataCache.Get 的调用将会返回 null。
在缓存端编程模型中,调用方负责随后从后端存储中加载数据,然后将该数据放置于缓存中。缓存使用 read - through(同步读取)提供程序检测丢失的项目,并调用提供程序执行数据加载。项目随后将无缝返回到缓存客户端中。
相比上面同时管理数据库和缓存,我们可以简单委托数据库同步给一个缓存提供者,所有数据交互通过这个缓存抽象层完成。确认缓存中是否有该数据,如果没有,从数据库加载,然后放入缓存,下次以后再访问就可以直接从缓存中获得。
3.Write - through
类似于 Read - through 的数据抓取策略,缓存能够在其中数据变化时自动更新底层数据库。
尽管数据库和缓存同步更新了,但是我们也可以按照我们自己的业务要求选择事务的边界,如果需要强一致性,并且缓存提供者提供了 XAResource,这样我们可以在一个全局事务中完成缓存和数据库的更新,这样数据库和缓存更新是在一个原子单元:
single atomic unit-of-work
。 如果只需要弱一致性,我们可以先后更新缓存和数据库,不必使用全局事务,这会让我们提升快速响应性与性能,通常缓存首先被更新,如果数据库更新失败,缓存可以通过补偿动作实现回滚当前事务所做的改变。4.Write - behind(事后写入)
如果强一致性不是必须的,我们可以简单将缓存的更新放在队列中,然后定期批量地去更新数据库。打破了事务保证,但是性能要远远超过 write - through,因为数据库能够快速批量更新,事务机制不再需要。在 write - behind 缓存中,数据的读取和更新通过缓存进行,与 write - through 缓存不同,更新的数据并不会立即传到数据库。相反,在缓存中一旦进行更新操作,缓存就会跟踪脏记录列表,并定期将当前的脏记录集刷新到数据库中。
作为额外的性能改善,缓存会合并这些脏记录。合并意味着如果相同的记录被更新,或者在缓冲区内被多次标记为脏数据,则只保证最后一次更新。对于那些值更新非常频繁,例如金融市场中的股票价格等场景,这种方式能够很大程度上改善性能。如果股票价格每秒钟变化 100 次,则意味着在 30 秒内会发生 30 x 100 次更新。合并将其减少至只有一次。
3.2 Web 负载层面,IP Hash 策略,Nginx 负载均衡策略三者互相关联
涉及高并发的时候,我们的 Nginx 这个是不可或缺的工具,那么我们来看看这个软件是什么,他能帮助我们实际生产中解决什么问题。
3.2.1 Web 负载层面,Nginx 负载均衡策略
HTTP基础功能:
处理静态文件,索引文件以及自动索引; 反向代理加速(无缓存),简单的负载均衡和容错; FastCGI,简单的负载均衡和容错;
模块化的结构:
过滤器包括:gzipping,byte ranges,chunked responses,以及 SSI - filter ; 在SSI过滤器中,到同一个 proxy 或者 FastCGI 的多个子请求并发处理; SSL 和 TLS SNI 支持。
IMAP/POP3 代理服务功能:
- 使用外部 HTTP 认证服务器重定向用户到 IMAP/POP3 后端;
- 使用外部 HTTP 认证服务器认证用户后连接重定向到内部的 SMTP 后端。
认证方法:
POP3:POP3 USER/PASS, APOP, AUTH LOGIN PLAIN CRAM-MD5; IMAP:IMAP LOGIN; SMTP:AUTH LOGIN PLAIN CRAM-MD5; SSL 支持; 在 IMAP 和 POP3 模式下的 STARTTLS 和 STLS 支持。
其他HTTP功能:
基于IP 和名称的虚拟主机服务; Memcached 的 GET 接口; 支持 keep-alive 和管道连接; 灵活简单的配置; 重新配置和在线升级而无须中断客户的工作进程; 可定制的访问日志,日志写入缓存,以及快捷的日志回卷; 4xx - 5xx 错误代码重定向; 基于 PCRE 的 rewrite 重写模块; 基于客户端 IP 地址和 HTTP 基本认证的访问控制; PUT,DELETE,和 MKCOL 方法; 支持 FLV (Flash 视频); 带宽限制;
3.2.2 高性能的服务器
Nginx 是一个高性能的 Web 和反向代理服务器, 它具有有很多非常优越的特性:
作为 Web 服务器:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,体现更高的效率,这点使 Nginx 尤其受到虚拟主机提供商的欢迎。能够支持高达 50000 个并发连接数的响应,感谢 Nginx 为我们选择了 epoll and kqueue 作为开发模型。
作为负载均衡服务器:Nginx 既可以在内部直接支持 Rails 和 PHP,也可以支持作为 HTTP代理服务器 对外进行服务。Nginx 用 C 编写, 不论是系统资源开销还是 CPU 使用效率都比 Perlbal 要好的多。
作为邮件代理服务器:Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器),Last.fm 描述了成功并且美妙的使用经验。
Nginx 安装非常的简单,配置文件 非常简洁(还能够支持 perl 语法),Bugs 非常少的服务器:Nginx 启动特别容易,并且几乎可以做到 7 * 24 不间断运行,即使运行数个月也不需要重新启动。你还能够在 不间断服务的情况下进行软件版本的升级。
总结:七层负载均衡的实现基于 Web 层面的 URL 等应用信息的负载均衡,Nginx 的 proxy 是它一个很强大的功能,实现了 7 层负载均衡。
3.2.3 nginx 负载均衡中 RR 和 IP Hash 策略分析
1、RR(默认)
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器 down 掉,能自动剔除。
例如:
upstream tomcats { server 172.19.1.182:8888 max_fails=3 fail_timeout=3s weight=9; server 172.19.1.152:8080 max_fails=3 fail_timeout=3s weight=9; }
2、IP Hash 策略
每个请求按访问 ip 的 hash 结果分配,这样每个访客固定访问一个后端服务器,可以解决 session 的问题。
例如:
upstream tomcats { ip_hash; server 172.19.1.182:8888; server 1172.19.1.152:8080 ; }
3、fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
4、url_hash(第三方)
按访问 url 的 hash 结果来分配请求,使每个 url 定向到同一个后端服务器,后端服务器为缓存时比较有效。
总结:Nginx 内置的另一个负载均衡的策略,流程和轮询很类似,只是七种的算法和具体的策略有些变化 IP Hash 算法是一种变相的轮询算法。
3.3 页面静态化
现在提倡前后端分离,前端界面基本都是 HTML 网页代码,通过 Angular JS 或者 NodeJS 提供的路由向后端服务器发出请求获取数据,然后在游览器对数据进行渲染,这样在很大程度上降低了后端服务器的压力。
还可以将这些静态的 HTML、CSS、JS、图片资源等放置在缓存服务器上或者 CDN 服务器上,一般使用最多的应该是 CDN 服务器或者 Nginx 服务器提供的静态资源功能。
无论是 JSP,ASP,PHP 等等效率最高、消耗最小的就是纯静态化的 html 页面,所以我们尽可能使我们的网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法。因为这样可以减少了和后台等交互的步骤,尤其大量内容并且频繁更新的网站,我们无法全部手动逐个实现。
所以就诞生了 CMS 的内容发布系统,生成 HTML,像我们常访问的各个门户站点,甚至他们的其他频道,都是通过信息发布系统来管理和实现的,信息发布系统可以实现最简单的信息录入自动生成静态页面,还能权限和爬虫自动抓取等功能,对于一个大型门户网站来说,拥有一套高效、可管理的 CMS 必须的。
哪些网站需要这些技术?
除了门户和信息发布类型的网站,对于交互性要求很高的社区类型网站来说,尽可能的静态化也是提高性能的必要手段,将社区内的帖子、文章进行实时的静态化、有更新的时候再重新静态化也是大量使用的策略,像电商类使用了这样的策略,网易社区等也是如此。
第四章 实战分享
无论是淘宝的双 11,还是京东的 618 都是高并发和大流量的王者,那么我们通过网络中的例子和电商的官方解析来看看他们如何将技术落地的。
4.1关系数据库仍然不可或缺
当前主流的关系型数据库有 Oracle、DB2、Microsoft SQL Server、Microsoft Access、MySQL 等。
非关系型数据库有 NoSql、Cloudant。
nosql和关系型数据库的比较
优点: 1)成本:nosql数据库简单易部署,基本都是开源软件,不需要像使用oracle那样花费大量成本购买使用,相比关系型数据库价格便宜。 2)查询速度:nosql数据库将数据存储于缓存之中,关系型数据库将数据存储在硬盘中,自然查询速度远不及nosql数据库。 3)存储数据的格式:nosql的存储格式是key,value形式、文档形式、图片形式等等,所以可以存储基础类型以及对象或者是集合等各种格式,而数据库则只支持基础类型。 4)扩展性:关系型数据库有类似join这样的多表查询机制的限制导致扩展很艰难。
缺点:
1)维护的工具和资料有限,因为 nosql 是属于新的技术,不能和关系型数据库 10 几年的技术同日而语。
2)不提供对 sql 的支持,如果不支持 sql 这样的工业标准,将产生一定用户的学习和使用成本。
3)不提供关系型数据库对事物的处理。
非关系型数据库的优势:
-
性能 NOSQL 是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过 SQL 层的解析,所以性能非常高。
-
可扩展性同样也是因为基于键值对,数据之间没有耦合性,所以非常容易水平扩展。
关系型数据库的优势:
-
复杂查询可以用 SQL 语句方便的在一个表以及多个表之间做非常复杂的数据查询。
-
事务支持使得对于安全性能很高的数据访问要求得以实现。对于这两类数据库,对方的优势就是自己的弱势,反之亦然。
-
保持数据的一致性(事务处理)。
-
由于以标准化为前提,数据更新的开销很小(相同的字段基本上都只有一处)。
-
可以进行 Join 等复杂查询。
其中能够保持数据的一致性是关系型数据库的最大优势。
关系型数据库的不足
不擅长的处理:
-
大量数据的写入处理。
-
为有数据更新的表做索引或表结构(schema)变更。
-
字段不固定时应用。
-
对简单查询需要快速返回结果的处理。
大量数据的写入处理
读写集中在一个数据库上让数据库不堪重负,大部分网站已使用主从复制技术实现读写分离,以提高读写性能和读库的可扩展性。
所以在进行大量数据操作时,会使用数据库主从模式。数据的写入由主数据库负责,数据的读入由从数据库负责,可以比较简单地通过增加从数据库来实现规模化,但是数据的写入却完全没有简单的方法来解决规模化问题。
4.2 非关系型数据库锦上添花
临时性键值存储(memcached、Redis)、永久性键值存储(ROMA、Redis)、面向文档的数据库(MongoDB、CouchDB)、面向列的数据库(Cassandra、HBase)
4.2.1 键值存储
它的数据是以键值的形式存储的,虽然它的速度非常快,但基本上只能通过键的完全一致查询获取数据,根据数据的保存方式可以分为临时性、永久性和两者兼具 三种。
(1)临时性
所谓临时性就是数据有可能丢失,memcached 把所有数据都保存在内存中,这样保存和读取的速度非常快,但是当 memcached 停止时,数据就不存在了。由于数据保存在内存中,所以无法操作超出内存容量的数据,旧数据会丢失。
总结来说:
- 在内存中保存数据。
- 可以进行非常快速的保存和读取处理。
- 数据有可能丢失。
(2)永久性
所谓永久性就是数据不会丢失,这里的键值存储是把数据保存在硬盘上,与临时性比起来,由于必然要发生对硬盘的 IO 操作,所以性能上还是有差距的,但数据不会丢失是它最大的优势。
总结来说:
- 在硬盘上保存数据。
- 可以进行非常快速的保存和读取处理(但无法与 memcached 相比)。
- 数据不会丢失。
(3) 两者兼备
Redis 属于这种类型。Redis 有些特殊,临时性和永久性兼具。Redis 首先把数据保存在内存中,在满足特定条件(默认是 15 分钟一次以上,5 分钟内 10 个以上,1 分钟内 10000 个以上的键发生变更)的时候将数据写入到硬盘中,这样既确保了内存中数据的处理速度,又可以通过写入硬盘来保证数据的永久性,这种类型的数据库特别适合处理数组类型的数据。
总结来说:
- 同时在内存和硬盘上保存数据。
- 可以进行非常快速的保存和读取处理。
- 保存在硬盘上的数据不会消失(可以恢复)。
- 适合于处理数组类型的数据。
4.2.2 面向文档的数据库
MongoDB、CouchDB 属于这种类型,它们属于 NoSQL 数据库,但与键值存储相异。
(1)不定义表结构
即使不定义表结构,也可以像定义了表结构一样使用,还省去了变更表结构的麻烦。
(2)可以使用复杂的查询条件
跟键值存储不同的是,面向文档的数据库可以通过复杂的查询条件来获取数据,虽然不具备事务处理和 Join 这些关系型数据库所具有的处理能力,但初次以外的其他处理基本上都能实现。
4.2.3 面向列的数据库
Cassandra、HBae、HyperTable 属于这种类型,由于近年来数据量出现爆发性增长,这种类型的 NoSQL 数据库尤其引入注目。
普通的关系型数据库都是以行为单位来存储数据的,擅长以行为单位的读入处理,比如特定条件数据的获取。因此,关系型数据库也被成为面向行的数据库。相反,面向列的数据库是以列为单位来存储数据的,擅长以列为单位读入数据。
面向列的数据库具有高扩展性,即使数据增加也不会降低相应的处理速度(特别是写入速度),所以它主要应用于需要处理大量数据的情况。另外,把它作为批处理程序的存储器来对大量数据进行更新也是非常有用的。
但由于面向列的数据库跟现行数据库存储的思维方式有很大不同,故应用起来十分困难。
总结:关系型数据库与NoSQL数据库并非对立而是互补的关系,即通常情况下使用关系型数据库,在适合使用NoSQL的时候使用NoSQL数据库,让NoSQL数据库对关系型数据库的不足进行弥补。
后记
还有同步的解决策略,图片服务器分离,CDN 加速技术等技术。
更多优秀的方案,伴随着时代的高速步伐,在后厂村的道路上让我们共同见证......