精华内容
下载资源
问答
  • 木质人造是一种广泛应用的工程材料。它本身具有一定的吸声特性,不同种类的...人造的厚度及容重对其吸声效率有明显的影响,软质纤维的容重在0.230—0.260克/立方厘米范围内;水泥刨花的容重在0.55—0.65克/立方厘
  • 针对废线路资源化处理,采用结合拆卸元器件的回收方式,以空气作为熔焊加热介质,采用数值模拟的方式,以流体分析软件FLUENT为工具,研究了熔焊时热风温度、速度和喷嘴(即热风出口)的结构尺寸对加热效率和焊点附近...
  • 环境因素(例如环境温度,风速和太阳辐照度)对家用光伏面板的效率有重大影响。 本文在冬季在甘肃省民勤县的一栋建筑物中进行了实验研究。 实验测量用于量化家用光伏电池的性能和操作特性。 根据实验结果,家用...
  • 我国省域电子信息制造业效率测算及影响因素分析——基于DEA和面Tobit模型.pdf
  • 影响我国商业银行效率的环境因素分析,冯立红,,根据面板数据分析,建立逐步回归模型,对影响商业银行效率的环境因素进行定量分析。研究结果表明:GDP增长率、通货膨胀率、股票市
  • 长杆弹垂直侵彻半无限靶影响因素及其影响规律分析,高光发,,针对长杆弹垂直侵彻半无限厚靶的问题,理论上分析了影响弹体侵彻效率的主要因素,并就其对长杆弹归一化侵彻深度的影响规律及机
  • 论文研究-中国区域全要素能源效率及其影响因素分析——基于2003-2010年的省际面板数据.pdf, 如何做好节能减排, 提高用能效率进而提升经济增长的质量逐渐成为中国经济...
  • 本文基于2000年至2015年中国各省的面板数据,探讨了DEA-Tobit两阶段分析框架下地方政府公共文化服务支出的效率及其影响因素。 首先,通过数据包络分析法(DEA)测算地方政府公共文化支出的综合效率,纯技术效率和...
  • ...个人关于目前影响开发效率的几大因素总结以及解决方案 Published on 2012 年 11 月 26 日, by Hengstar in C/C++, JS相关, Web相关, 个人相关, 服务器技术.

    http://blog.chukong-inc.com/index.php/2012/11/26/个人关于目前影响开发效率的几大因素总结以及解/




    formats

    个人关于目前影响开发效率的几大因素总结以及解决方案

    论坛帖子
    本人根据这两个月在项目中的实际开发对目前的开发过程中的效率问题做了一个小结(纯属个人观点),希望大家能共同出力改善下,即使是方案也可以有参考价值的:
    1.最大的效率影响点恐怕要属调试功能了。这个大家都深有体会的。引擎刚刚推出了基于console的调试方案。不过功能还比较少,使用上相对不是很便捷,对于开发的效率提升不是很高。不过html5版本出来后,调试就会方便很多了。另外V8的可视化调试也是一个比较好的选择,服务器端易用。目前客户端需要用还需要花时间做兼容;
    2.原生JS很难找到成熟好用的库。熟悉了其它语言(如C++,Java,C#之类的语言)的童鞋都会习惯性的使用语言标准化的一些基础库。如各种容器map等数据结构,一些系统的操作,如文件流操作,如C++的fstream。需要在JS端使用还需要逐个导入,且不支持模板。客户端使用html5会弥补这很多的不足,服务器端Node.js是一个很好的选择;
    3.引擎工具问题较多,功能不完善,使用上不是很方便;
    4.引擎文档化程度较低,想要的功能有没有无处可查。导出的接口不够完善,导出新接口到发布的时间比较长。希望能尽快完善文档和接口;
    5.对JS语言本身的特性不熟悉,导致使用过程中经常出岔子。(另外有一些是由于类似与大小写不敏感导致写错一个字母很难查错),这个需要靠自己多补补JS的知识了,如果有高手愿意花时间给大家培训下把一些经常容易出问题的地方提点下也会改善一些吧;
    6.对代码版本控制工具(如git)不熟悉,使用过程中出现莫名其妙的问题。经常一时半会解决不了,然后会采取比较极端的方式,重装,或者强制更新,合并等,最后导致别人工作丢失。然后又一堆人研究半天找不到问题。接着重写吧。这个也需要花时间研究下相关工具了。相对来说git是比较复杂的东东,需要花点时间才能理解透彻。通过统一的培训可以达到事半功倍的效果;
    7.没有使用便捷的IDE,例如可以自动检测JS语法错误和自动补全功能会减少很多错误。VS和Eclipse的JSDT插件都具备这些功能的。

    目前就想到这些。希望有想法的童鞋们继续补充啦~


    formats

    个人关于目前影响开发效率的几大因素总结以及解决方案

    论坛帖子
    本人根据这两个月在项目中的实际开发对目前的开发过程中的效率问题做了一个小结(纯属个人观点),希望大家能共同出力改善下,即使是方案也可以有参考价值的:
    1.最大的效率影响点恐怕要属调试功能了。这个大家都深有体会的。引擎刚刚推出了基于console的调试方案。不过功能还比较少,使用上相对不是很便捷,对于开发的效率提升不是很高。不过html5版本出来后,调试就会方便很多了。另外V8的可视化调试也是一个比较好的选择,服务器端易用。目前客户端需要用还需要花时间做兼容;
    2.原生JS很难找到成熟好用的库。熟悉了其它语言(如C++,Java,C#之类的语言)的童鞋都会习惯性的使用语言标准化的一些基础库。如各种容器map等数据结构,一些系统的操作,如文件流操作,如C++的fstream。需要在JS端使用还需要逐个导入,且不支持模板。客户端使用html5会弥补这很多的不足,服务器端Node.js是一个很好的选择;
    3.引擎工具问题较多,功能不完善,使用上不是很方便;
    4.引擎文档化程度较低,想要的功能有没有无处可查。导出的接口不够完善,导出新接口到发布的时间比较长。希望能尽快完善文档和接口;
    5.对JS语言本身的特性不熟悉,导致使用过程中经常出岔子。(另外有一些是由于类似与大小写不敏感导致写错一个字母很难查错),这个需要靠自己多补补JS的知识了,如果有高手愿意花时间给大家培训下把一些经常容易出问题的地方提点下也会改善一些吧;
    6.对代码版本控制工具(如git)不熟悉,使用过程中出现莫名其妙的问题。经常一时半会解决不了,然后会采取比较极端的方式,重装,或者强制更新,合并等,最后导致别人工作丢失。然后又一堆人研究半天找不到问题。接着重写吧。这个也需要花时间研究下相关工具了。相对来说git是比较复杂的东东,需要花点时间才能理解透彻。通过统一的培训可以达到事半功倍的效果;
    7.没有使用便捷的IDE,例如可以自动检测JS语法错误和自动补全功能会减少很多错误。VS和Eclipse的JSDT插件都具备这些功能的。

    目前就想到这些。希望有想法的童鞋们继续补充啦~

    展开全文
  • 针对拟在中国创业上市企业,从提升企业价值、实现股东财富最大化及完善企业治理结构的角度,对影响激励效率的主要因素进行归纳与分析,旨在为我国创业企业如何提高经理股票期权激励效率提供分析思路。
  • 本文选择有代表性的33个资源...以及这些因素对决定生态效率的两个重要方面――资源效率、环境效率影响,实证分析资源型城市可持续发展影响因素。实证结果显示,除科技进步外,上述因素对资源型城市可持续发展都有显著
  • 本文旨在分析中国工业化进程中影响能源消耗及其效率的主要因素。通过理论研究,我们认为经济结构、技术进步以及能源市场化改革是中国工业化进程中的主要影响因素。从这些影响因素的作用机理来看,经济结构与工业化阶段...
  • 文章目录影响性能的几个因素 影响性能的几个因素 硬件资源(CPU 、内存、磁盘等) 操作系统的区别 MySQL的存储引擎的选择 MyISAM: 不支持事务,表级锁 InnoDB: 事务级存储引擎,完美支持行级锁,事务ACID...


    在这里插入图片描述

    生猛干货

    带你搞定MySQL实战,轻松对应海量业务处理及高并发需求,从容应对大场面试


    官方文档

    https://dev.mysql.com/doc/

    在这里插入图片描述

    如果英文不好的话,可以参考 searchdoc 翻译的中文版本

    http://www.searchdoc.cn/rdbms/mysql/dev.mysql.com/doc/refman/5.7/en/index.com.coder114.cn.html
    在这里插入图片描述


    影响性能的几个因素

    • 硬件资源(CPU 、内存、磁盘等)

    • 操作系统的区别

    • MySQL的存储引擎的选择

      MyISAM: 不支持事务,表级锁
      InnoDB: 事务级存储引擎,完美支持行级锁,事务ACID特性。

      但 比不是说 MyISAM比InnoDB差,看使用场景

    • 数据库参数设置

    • 数据库结构设计和SQL语句 ,毫无疑问 这个是最最重要的因素 —> mysql 可以开启慢查询监控耗时长的SQL


    CPU

    更多的CPU or 更快的CPU ?

    主要从以下几个方面考虑:

    • (1)CPU密集型的应用?

    分析下我们的应用的类型,是的话,要提高SQL的运行效率,那就需要更快的CPU。

    还有一点需要注意 MySQL不支持多CPU对同一SQL的并发处理,也就是说一个SQL只能运行在一个CPU的核上。


    • (2) 系统的并发量如何 ?

    一个SQL只能跑在一个CPU上,如果有32个CPU呢 ,是不是同时可以跑32个SQL呢? 就是我们前面说的QPS 。 一般web应用,CPU的核心数量比CPU的主频更重要。


    • (3) MySQL的版本 ?

    5.6、 5.7以上的版本,对多核CPU的支持更好。


    • (4) 64位操作系统 OR 32位操作系统

    32的操作系统,进程所能寻址的最大内存也就4G。

    总结

    • 对于并发较高的场景,CPU的数量比频率重要
    • 对CPU密集型场景和复杂的SQL 频率越高越好

    内存

    MyISAM : 索引 缓存在内存 ,数据通过OS来缓存

    InnoDB : 索引和数据都是通过内存来缓存

    举个例子, 100G的数据量, 内存64G,这个时候增加内存对性能有提高。 如果内存是256G,还是慢,那就是其他问题了。

    当然了,内存多了,对于数据的读和写都是好处的,都可以利用缓存来提高读写性能。

    如何选择内存呢? ----> 建议选择主板支持的最大内存频率, 跟CPU一个道理。

    内存的型号,保持一致, 单个内存尽可能的大,都是比较好的选择。

    配置的时候,要考虑数据的增长,比如100G的数据, 128G内存可能已经满足了要求,但数据可能增长较快,这个时候256的更佳。

    总结

    • 选择主板所能使用的最高频率的内存
    • 内存尽可能的多

    磁盘的配置和选择

    主流的4种

    • 使用传统的机械硬盘
    • 使用RAID增强传统硬盘的性能
    • 使用固态存储SSD和PCIe卡
    • 使用网络存储NAS和SAN

    传统的机械硬盘

    传统的机械硬盘的读取数据的过程

    1. 移动磁头到磁盘表面上正确的位置
    2. 等待磁盘旋转,使所需的数据在磁头之下 ----> 访问时间
    3. 等磁盘旋转过去,所需的数据被磁头读出 ------> 传输速度

    考虑的话 1. 存储容量 2.传输速度 3 访问时间 4 主轴的转速(常见的7200转、1万5千转等等) 5. 物理尺寸


    RAID

    RAID : 磁盘冗余队列 (Redundant Arrays of Independent Disks )

    RAID是一种将多个容量较小的磁盘组成一组容量更大的磁盘,并提供数据冗余来保证数据完整性的技术 。

    Linux-Raid0、Raid1、Raid5、Raid10初探


    SSD 或者 PCIe卡

    SSD

    • 比普通的机械盘有更好的随机读写性能
    • 支持更好的并发, I/O 性能好
    • 缺点: 长时间密集的写,容易造成损坏

    特点:

    • 可以使用SATA接口,可以替换传统的磁盘而不需要任何的改动。
    • SATA接口的SSD同样支持RAID
    • SATA的SSD 3.0 接口如果放到了 2.0接口上,受2.0接口的性能影响,性能会下降

    举个例子 SATA3.0接口 6Gbps , 放到SATA2.0接口上 最多只能用到2.0的 3Gbps


    PCIe 卡(Fushion IO)

    • 无法使用SATA接口,需要独特的驱动和配置
    • 比SSD性能好,但价格也比SSD贵
    • PCIe 也会吃服务器的内存
    • 支持PCIe的Raid控制器比较少,而且成本相当高

    固态存储使用的场景

    • 大量随机I/O的场景
    • 解决单线程负载的I/O 瓶颈

    举个例子

    主从节点的MYSQL, 有一个SSD, 给哪个节点用呢 ?

    ----> 从节点 上用。 主节点上写 ,是多线程, 从节点的复制,单线程,为了减少延迟,建议放到从服务器上。


    网络存储SAN (光纤传输)和 NAS (带宽传输)

    SAN: Storage Area Network

    NAS: Network Attached Storage

    是两种外部文件存储设备加载到服务器上的方法。

    SAN设备通过光纤连接服务器,设备通过块接口访问,服务器可以将其当做硬盘使用。 可以承受大量的顺序读写,但随即读有的时候不如RAID

    NAS 使用 宽带来传输,有延迟。

    使用场景的话: 数据备份等 。

    总结

    • PCIe > SSD > Raid10 > 本地磁盘 > NAS

    网络

    网络带宽 —> 低延时 、吞吐量达

    网络质量—> 少抖动

    建议

    • 采用高性能和高带宽的网络接口设备和交换机
    • 对多个网卡进行绑定,增强可用性和带宽
    • 尽可能的进行网络隔离

    操作系统

    windows 和 linux , 大小写的区别,可以通过修改MySQL的配置来调整。

    以CentoOS为例来了解下系统的参数优化

    内核相关参数 /etc/sysctl.conf

    在这里插入图片描述
    如需增加 可以直接追加到该文件的末尾

    net.core.somaxconn=65535  # Linux kernel参数,表示socket监听的backlog(监听队列)上限
    net.core.netdev_max_bakclog=65535 # 允许发送到队列中的数据包数目
    net.ipv4.tcp_max_syn_backlog=65535 # #表示SYN队列长度,默认1024,改成65535,可以容纳更多等待连接的网络连接数。
    
    net.ipv4.tcp_fin_timeout = 10 #表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间
    net.ipv4.tcp_tw_reuse = 1 #表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
    net.ipv4.tcp_tw_recycle = 1 #表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
    

    TCP/IP及内核参数优化调优

    net.core.wmen_default = 87380 # 表示内核套接字发送缓存区默认的大小。
    net.core.wmen_max = 16777216 # 表示内核套接字发送缓存区最大大小。
    net.core.rmem_default = 87380 # 默认的TCP数据接收缓冲
    net.core.rmem_max=16777216 # 最大的TCP数据接收缓冲
    
    #单位是秒   可适当调整 
    net.ipv4.tcp_keepalive_time = 120 # 有效时长
    net.ipv4.tcp_keepalive_intvl = 30  # 探测失败时,重发的间隔
    net.ipv4.tcp_keepalive_probes = 3  # 最多发送多少次探测消息
    
    kernel.shmmax = 4294967295  # (4G)单个共享内存段的最大值,应该设置的足够大,以便能在一个共享段下容纳整个Innodb缓冲池的大小 。 可以取物理内存-1 byte 
    
    vm.swappiness = 0 #  除非虚拟内存满了,否则不会使用交换分区
    

    其实就是swap交换分区的设置, 当操作系统没有足够的内存时,就会将一些虚拟内存写到磁盘的交换区中,这样就会发生内存交换。

    然后执行sysctl -p命令,使上述修改生效


    资源限制的配置文件 /etc/security/limits.conf

    # 文件句柄数量 
    
    * soft nofile 65535
    * hard nofile 65535
    
    
    *  对所有用户生效
    soft 当前系统生效的设置
    hard 系统所能设置的最大值
    nofile 表示所限制的资源是打开文件的最大数目
    65535 限制的数目
    
    

    这俩参数,重启系统才生效。


    磁盘调度策略

    I/O 调度算法再各个进程竞争磁盘I/O的时候担当了裁判的角色,以求得尽可能最好的整体I/O性能。

    在linux下面列出4种调度算法

    • CFQ (Completely Fair Queuing 完全公平的排队)(elevator=cfq) 默认策略
    • Deadline (elevator=deadline): 试图把每次请求的延迟降至最低
    • NOOP (elevator=noop):FIFO队列形式处理
    • Anticipatory (elevator=as):对读操作优化服务时间,在提供一个I/O的时候进行短时间等待,使进程能够提交到另外的I/O。
    #查看当前IO
    
    [root@artisan ~]#  cat /sys/block/sd*/queue/scheduler
    noop [deadline] cfq 
    [root@artisan ~]# 
    
    

    文件系统

    windows -----> FAT 和 NTFS

    WinServer 只有 NTFS 这种可以选择

    Linux —> EXT3 EXT4 XFS

    EXT3 EXT4系统的挂载参数 /etc/fstab

    # data的可配置选项
    
    data=writeback | ordered |journal 
    
    
    noatime 
    nodiratime 
    
    
    
    /dev/sda1/ext4 noatime,nodiratime,data-writeback 1 1
    
    
    

    在这里插入图片描述


    搞定MySQL

    在这里插入图片描述

    展开全文
  • 详解NVMe SSD存储性能影响因素

    千次阅读 2018-11-03 07:21:50
    导读: NVMe SSD的性能时常捉摸不定,为此我们需要打开SSD的神秘盒子,从各个视角分析SSD性能影响因素,并思考从存储软件的角度如何最优化使用NVMe SSD,推进...

    640?wx_fmt=jpeg

    640?wx_fmt=gif&wxfrom=5&wx_lazy=1

    导读: NVMe SSD的性能时常捉摸不定,为此我们需要打开SSD的神秘盒子,从各个视角分析SSD性能影响因素,并思考从存储软件的角度如何最优化使用NVMe SSD,推进数据中心闪存化进程。本文从NVMe SSD的性能影响因素进行分析,并给出存储系统设计方面的一些思考。


    目录


    1 存储介质的变革    
    2 NVME SSD成为主流    
    2.1 NAND FLASH介质发展    
    2.2 软件层面看SSD——多队列技术    
    2.3 深入理解SSD硬件    
    3 影响NVME SSD的性能因素    
    3.1 GC对性能的影响    
    3.2 IO PATTERN对性能的影响    
    3.2.1 顺序写入Pattern对SSD性能优化的奥秘    
    3.2.2 读写冲突Pattern对性能的影响    
    4 SSD写性能分析模型    
    5 小结


    NVMe SSD的性能时常捉摸不定,为此我们需要打开SSD的神秘盒子,从各个视角分析SSD性能影响因素,并思考从存储软件的角度如何最优化使用NVMe SSD,推进数据中心闪存化进程。本文从NVMe SSD的性能影响因素进行分析,并给出存储系统设计方面的一些思考。


    1 存储介质的变革 


    近几年存储行业发生了翻天覆地的变化,半导体存储登上了历史的舞台。和传统磁盘存储介质相比,半导体存储介质具有天然的优势。无论在可靠性、性能、功耗等方面都远远超越传统磁盘。目前常用的半导体存储介质是NVMe SSD,采用PCIe接口方式与主机进行交互,大大提升了性能,释放了存储介质本身的性能。通常NVMe SSD内部采用NAND Flash存储介质进行数据存储,该介质本身具有读写不对称性,使用寿命等问题。为此在SSD内部通过FTL(Flash Translation Layer)解决NAND Flash存在的问题,为上层应用软件呈现和普通磁盘相同的应用接口和使用方式。

    640?wx_fmt=png


    如上图所示,随着半导体存储介质的发展,计算机系统的IO性能得到了飞速发展。基于磁介质进行数据存储的磁盘和处理器CPU之间一直存在着棘手的剪刀差性能鸿沟。随着存储介质的演进与革新,这种性能剪刀差将不复存在。从整个系统的角度来看,IO性能瓶颈正从后端磁盘往处理器和网络方向转移。如下图性能数据所示,在4KB访问粒度下,NVMe SSD和15K转速磁盘相比,每秒随机读IO处理能力提升了将近5000倍;每秒随机写IO处理能力提升了1000多倍。随着非易失性存储介质的进一步发展,半导体存储介质的性能将进一步提升,并且会具有更好的IO QoS能力。


    640?wx_fmt=png


    存储介质的革命一方面给存储系统性能提升带来了福音;另一方面对存储系统的设计带来了诸多挑战。原有面向磁盘设计的存储系统不再适用于新型存储介质,面向新型存储介质需要重新设计更加合理的存储软件堆栈,发挥存储介质的性能,并且可以规避新介质带来的新问题。面向新型存储介质重构存储软件栈、重构存储系统是最近几年存储领域的热门技术话题。


    在面向NVMe SSD进行存储系统设计时,首先需要对NVMe SSD本身的特性要非常熟悉,需要了解SSD性能的影响因素。在设计过程中需要针对SSD的特性通过软件的方式进行优化。本文对SSD进行简要介绍,并从性能影响因素角度出发,对NVMe SSD进行深入剖析,在此基础上给出闪存存储设计方面的一些思考。


    2 NVMe SSD成为主流


    2.1 NAND Flash介质发展


    目前NVMe SSD主流采用的存储介质是NAND Flash。最近几年NAND Flash技术快速发展,主要发展的思路有两条:第一,通过3D堆叠的方式增加NAND Flash的存储密度;第二,通过增加单Cell比特数来提升NAND Flash的存储密度。3D NAND Flash已经成为SSD标配,目前主流发布的SSD都会采用3D NAND Flash技术工艺。从cell的角度来看,目前单个cell可以表示3bit,这就是通常所说的TLC NAND Flash。


    今年单个cell的bit存储密度又提升了33%,可以表示4bit,向前演进至QLC NAND Flash。NAND Flash的不断演进,推动了SSD存储密度不断提升。截止到今天,单个3.5寸SSD盘可以做到128TB的容量,远远超过了磁盘的容量。下图是近几年NAND Flash技术的发展、演进过程。


    640?wx_fmt=png


    从上图可以看出,NAND Flash在不断演进的过程中,一些新的非易失性内存技术也开始发展。Intel已经推出了AEP内存存储介质,可以预计,未来将会是非易失性内存和闪存共存的半导体存储时代。


    2.2 软件层面看SSD——多队列技术


    从软件接口的角度来看,NVMe SSD和普通的磁盘没有太多的区别,在Linux环境下都是标准块设备。由于NVMe SSD采用了最新的NVMe协议标准,因此从软件堆栈的角度来看,NVMe SSD的软件栈简化了很多。在NVMe标准中,和传统的SATA/SAS相比,一个重大的差别是引入了多队列机制,如下图所示。


    640?wx_fmt=png


    何为多队列技术?主机(X86 Server)与SSD进行数据交互的模型采用“生产者-消费者”模型,采用生产者-消费者队列进行数据交互。在原有的AHCI规范中,只定义了一个交互队列,那么主机与HDD之间的数据交互只能通过一个队列通信,多核处理器也只能通过一个队列与HDD进行数据交互。在磁盘存储时代,由于磁盘是慢速设备,所以一个队列也就够用了。


    多个处理器核通过一个共享队列与磁盘进行数据交互,虽然处理器之间会存在资源竞争,但是相比磁盘的性能,处理器之间竞争所引入的开销实在是微乎其微,可以忽略。在磁盘存储时代,单队列有其他的好处,一个队列存在一个IO调度器,可以很好的保证提交请求的IO顺序最优化。


    和磁盘相比,半导体存储介质具有很高的性能,AHCI原有的规范不再适用,原有的假设也已经不复存在,在此背景下NVMe规范诞生了。NVMe规范替代了原有的AHCI规范,并且软件层面的处理命令也进行了重新定义,不再采用SCSI/ATA命令规范集。在NVMe时代,外设和处理器之间的距离更近了,不再需要像SAS一样的面向连接的存储通信网络。相比于以前的AHCI、SAS等协议规范,NVMe规范是一种非常简化,面向新型存储介质的协议规范。该规范的推出,将存储外设一下子拉到了处理器局部总线上,性能大为提升。并且主机和SSD处理器之间采用多队列的设计,适应了多核的发展趋势,每个处理器核与SSD之间可以采用独立的硬件Queue Pair进行数据交互。


    从软件的角度来看,每个CPU Core都可以创建一对Queue Pair和SSD进行数据交互。Queue Pair由Submission Queue与Completion Queue构成,通过Submission queue发送数据;通过Completion queue接受完成事件。SSD硬件和主机驱动软件控制queue的Head与Tail指针完成双方的数据交互。


    2.3 深入理解SSD硬件


    和磁盘相比,NVMe SSD最大的变化在于存储介质发生了变化。目前NVMe SSD普遍采用3D NAND Flash作为存储介质。NAND Flash内部有多个存储阵列单元构成,采用floating gate或者charge trap的方式存储电荷,通过存储电荷的多少来保持数据存储状态。由于电容效应的存在、磨损老化、操作电压干扰等问题的影响,NAND Flash天生会存在漏电问题(电荷泄漏),从而导致存储数据发生变化。因此,从本质上讲,NAND Flash是一种不可靠介质,非常容易出现Bit翻转问题。SSD通过控制器和固件程序将这种不可靠的NAND Flash变成了可靠的数据存储介质。


    为了在这种不可靠介质上构建可靠存储,SSD内部做了大量工作。在硬件层面,需要通过ECC单元解决经常出现的比特翻转问题。每次数据存储的时候,硬件单元需要为存储的数据计算ECC校验码;在数据读取的时候,硬件单元会根据校验码恢复被破坏的bit数据。ECC硬件单元集成在SSD控制器内部,代表了SSD控制器的能力。在MLC存储时代,BCH编解码技术可以解决问题,4KB数据中存在100bit翻转时可以纠正错误;在TLC存储时代,bit错误率大为提升,需要采用更高纠错能力的LDPC编解码技术,在4KB出现550bit翻转时,LDPC硬解码仍然可以恢复数据。下图对比了LDPC硬解码、BCH以及LDPC软解码之间的能力, 从对比结果可以看出,LDPC软解码具有更强的纠错能力,通常使用在硬解码失效的情况下。LDPC软解码的不足之处在于增加了IO的延迟。

    640?wx_fmt=png


    在软件层面,SSD内部设计了FTL(Flash Translation Layer),该软件层的设计思想和Log-Structured File System设计思想类似。采用log追加写的方式记录数据,采用LBA至PBA的地址映射表记录数据组织方式。Log-structured系统最大的一个问题就是垃圾回收(GC)。因此,虽然NAND Flash本身具有很高的IO性能,但受限于GC的影响,SSD层面的性能会大受影响,并且存在十分严重的IO QoS问题,这也是目前标准NVMe SSD一个很重要的问题。


    SSD内部通过FTL解决了NAND Flash不能Inplace Write的问题;采用Wear Leveling算法解决了NAND Flash磨损均衡问题;通过Data Retention算法解决了NAND Flash长时间存放漏电问题;通过Data Migration方式解决Tead Diatribe问题。FTL是NAND Flash得以大规模使用的核心技术,是SSD的重要组成部分。


    640?wx_fmt=png


    NAND Flash内部本身具有很多并发单元,如上图所示,一个NAND Flash芯片由多个Target构成,每个Target包含多个Die。每个Die是一个独立的存储单元,一个Die由多个Plane构成,多个Plane之间共享一套操作总线,多个Plane可以组成一个单元并发操作,构建Multi-plane。一个Plane由若干个Block构成,每个Block是一个擦除单元,该单元的大小也决定了SSD软件层面的GC回收粒度。每个Block由多个page页构成,每个Page是最小写入(编程)单元,通常大小为16KB。SSD内部软件(固件)需要充分利用这些并发单元,构建高性能的存储盘。


    一块普通NVMe SSD的物理硬件结构简单,由大量的NAND Flash构成,这些NAND Flash通过SOC(SSD控制器)进行控制,FTL软件运行在SOC内部,并通过多队列的PCIe总线与主机进行对接。为了提升性能,企业级SSD需要板载DRAM,DRAM资源一方面可以用来缓存数据,提升写性能;另一方面用来缓存FTL映射表。企业级SSD为了提升性能,通常采用Flat mapping的方式,需要占据较多的内存(0.1%)。


    内存容量的问题也限制了大容量NVMe SSD的发展,为了解决内存问题,目前一种可行的方法是增大sector size。标准NVMe SSD的sector size为4KB,为了进一步增大NVMe SSD的容量,有些厂商已经开始采用16KB的sector size。16KB Sector size的普及应用,会加速大容量NVMe SSD的推广。


    3 影响NVMe SSD的性能因素


    NVMe SSD 厂商Spec给出的性能非常完美,前面也给出了NVMe SSD和磁盘之间的性能对比,NVMe SSD的性能的确比磁盘高很多。但在实际应用过程中,NVMe SSD的性能可能没有想象中的那么好,并且看上去不是特别的稳定,找不到完美的规律。和磁盘介质相比,SSD的性能和很多因素相关,分析SSD的性能影响因素,首先需要大体了解SSD构成的主要部分。如下图所示,其主要包括主机CPU、PCIe互连带宽、SSD控制器及FTL软件、后端NAND Flash带宽、NAND Flash介质。影响SSD性能的主要因素可以分成硬件、软件和客观环境三大部分,具体分析如下。


    640?wx_fmt=png


    1,硬件因素


    a)    NAND Flash本身。不同类型的NAND Flash本身具有不同的性能,例如SLC的性能高于MLC,MLC的性能优于TLC。选择不同的工艺、不同类别的NAND Flash,都会具有不同的性能。


    b)    后端通道数(CE数量)及总线频率。后端通道数决定了并发NAND Flash的数量,决定了并发能力。不同的SSD控制器支持不同数量的通道数,也决定了SSD的后端吞吐带宽能力。NAND Flash Channel的总线频率也决定了访问Flash的性能。


    c)    SSD控制器的处理能力。SSD控制器中会运行复杂的FTL(Flash Translation Layer)处理逻辑,将逻辑块读写映射转换成NAND Flash 读写请求。在大数据块读写时,对处理器能力要求不是很高;在小数据块读写时,对处理器能力要求极高,处理器能力很容易成为整个IO系统的性能瓶颈点。


    d)    SSD控制器架构。通常SSD控制器采用SMP或者MPP两种架构,早期的控制器通常采用MPP架构,多个小处理器通过内部高速总线进行互连,通过硬件消息队列进行通信。内存资源作为独立的外设供所有的处理器进行共享。这种架构和基于消息通信的分布式系统类似。MPP架构的很大优势在于性能,但是编程复杂度较高;SMP架构的性能可扩展性取决于软件,编程简单,和在x86平台上编程相似。不同的控制器架构会影响到SSD的总体性能,在SSD设计时,会根据设计目标,选择不同类型的SSD控制器。


    e)    内存支持容量。为了追求高性能,SSD内部的映射资源表会常驻内存,映射表的内存占用大小是盘容量的0.1%,当内存容量不够大时,会出现映射表换入换出的问题,影响到性能。


    f)    PCIe的吞吐带宽能力。PCIe前端带宽体现了SSD的前端吞吐能力,目前NVMe SSD采用x4 lane的接入方式,上限带宽为3GB/s,当后端NAND Flash带宽和处理器能力足够时,前端PCIe往往会成为性能瓶颈点。NAND Flash具有很高的读性能,目前来看,SSD的读性能在很大程度上受限于PCIe总线,因此需要快速推进PCIe4.0标准。


    g)    温度对性能造成影响。在NAND Flash全速运行的情况下,会产生较大的散热功耗,当温度高到一定程度时,系统将会处于不正常的工作状态,为此,SSD内部做了控温系统,通过温度检测系统来调整SSD性能,从而保证系统温度维持在阈值之内。调整温度会牺牲性能,本质上就是通过降低SSD性能来降温。因此,当环境温度过高时,会影响到SSD的性能,触发SSD内部的温度控制系统,调节SSD的性能。


    h)    使用寿命对性能造成影响。NAND Flash在不断擦除使用时,Flash的bit error会不断上升,错误率的提升会影响到SSD的IO性能。


    2、软件因素


    a)    数据布局方式。数据布局方法需要充分考虑NAND Flash中的并发单元,如何将IO操作转换成NAND Flash的并发操作,这是数据布局需要考虑的问题。例如,采用数据交错的方式在多通道page上进行数据布局,通过这种方式可以优化顺序带宽。


    b)    垃圾回收/wear leveling调度方法。数据回收、wear leveling、data retention等操作会产生大量的NAND Flash后端流量,后端流量直接反应了SSD的写放大系数,也直接体现在后端带宽的占用。垃圾回收等产生的流量也可以称之为背景流量,背景流量会直接影响到前端用户性能。因此需要对背景流量和用户流量之间进行合理调度,使得用户IO性能达到最佳。


    c)    OP预留。为了解决坏块、垃圾回收等问题,在SSD内部预留了一部分空闲资源,这些资源被称之为OP(Overprovisioning)。OP越大,GC过程中平均搬移的数据会越少,背景流量会越小,因此,写放大降低,用户IO性能提升。反之,OP越小,性能会越低,写放大会越大。在SSD容量较小的时代,为了提升SSD的使用寿命,往往OP都设置的比较大。


    d)    Bit error处理影响性能。在SSD内部采用多种机制来处理NAND Flash所产生的Bit error。ECC纠错、read retry、soft LDPC以及RAIN都是用来纠正bit翻转导致的错误。当Bit错误率增加时,软件处理的开销越大,在bit控制在一定范围之内,完全可以通过硬件进行纠正。一旦软件参与到bit纠正的时候,会引入较大的性能开销。


    e)    FTL算法。FTL算法会影响到SSD性能,对于不同用途的SSD,FTL的设计与实现是完全不同的,企业级SSD为了追求高性能,通常采用Flat mapping的方式,采用大内存缓存映射表;消费级SSD为了追求低成本,通常采用元数据换入换出的方式,并且采用pSLC+TLC的组合方式进行分层存储,也可以采用主机端内存缓存元数据信息,但是这些方式都会影响到性能。


    f)    IO调度算法。NAND Flash具有严重的性能不对称性,Flash Erase和Program具有ms级延迟,Flash read的延迟在us级。因此,如何调度Erase、Program以及read是SSD后端设计需要考虑的问题。另外,前端IO以及背景IO之间的调度也是需要权衡考虑,通过IO调度可以达到最佳性能表现。在IO调度过程中,还需要利用NAND Flash的特性,例如Program Suspension,通过这些特性的利用,最优化SSD前端IO性能。


    g)    驱动软件。驱动软件运行在主机端,通常分为内核态和用户态两大类,内核态驱动会消耗较多的CPU资源,存在频繁上下文切换、中断处理,因此性能较低;用户态驱动通常采用Polling IO处理模式,去除了上下文切换,可以充分提升CPU效率,提升整体IO性能。


    h)    IO Pattern对性能产生影响。IO Pattern影响了SSD内部的GC数据布局,间接影响了GC过程中的数据搬移量,决定了后端流量。当IO Pattern为全顺序时,这种Pattern对SSD内部GC是最为友好的,写放大接近于1,因此具有最好的性能;当IO Pattern为小块随机时,会产生较多的GC搬移数据量,因此性能大为下降。在实际应用中,需要通过本地文件系统最优化IO Pattern,获取最佳性能。


    3、客观因素


    a)    使用时间越长会导致SSD性能变差。使用时间变长之后,SSD内部NAND Flash的磨损会加重,NAND Flash磨损变大之后会导致bit错误率提升。在SSD内部存在一套完整的bit错误恢复机制,由硬件和软件两大部分构成。当bit错误率达到一定程度之后,硬件机制将会失效。硬件机制失效之后,需要通过软件(Firmware)的方式恢复翻转的bit,软件恢复将会带来较大的延迟开销,因此会影响到SSD对外表现的性能。在有些情况下,如果一块SSD在掉电情况下放置一段时间之后,也可能会导致性能变差,原因在于SSD内部NAND Flash中存储电荷的漏电,放置一段时间之后导致bit错误率增加,从而影响性能。SSD的性能和时间相关,本质上还是与NAND Flash的比特错误率相关。


    b)    环境温度也会对性能造成影响。为了控制SSD温度不能超过上限值,在SSD内部设计有一套温度负反馈机制,该机制通过检测的温度对NAND Flash后端带宽进行控制,达到降低温度的效果。如果一旦温度负反馈机制开始工作,那么NAND Flash后端带宽将会受到限制,从而影响前端应用IO的性能。


    下面从软件的角度出发,重点阐述GC以及IO Pattern对SSD性能的影响。


    3.1 GC对性能的影响


    SSD内部有一个非常厚重的软件层,该软件层用来解决NAND Flash的问题,采用log-structured的方式记录数据。Log-structured方式引入了GC的问题,对于前端业务来讲,GC流量就是背景噪声。GC流量不是时时刻刻存在的,因此,SSD对外体现性能大幅度波动。当SSD为空盘时,性能会非常好,为最佳性能;当SSD被用过一段时间之后,性能会大幅降低。其中GC起到了很重要的作用。企业级SSD在发布Spec的时候,都会发布SSD盘的稳态性能。在性能测试的时候,需要对盘进行老化预处理。通常预处理的方法是顺序写满盘,然后再随机两遍写盘,预处理完成之后,再对盘进行随机读写测试,得到Spec中定义的值。稳态值基本可以认为是盘的下限性能。


    640?wx_fmt=png


    上图所示是多个厂商的盘在空盘和稳态情况下的性能对比,由此可见稳态情况和空盘情况下的性能差距很大。在稳态情况下,SSD内部的GC会全速运行,会占用较多的NAND Flash后端带宽。背景流量和前端数据流的比例也就体现了SSD盘的写放大系数,写放大系数越大,背景流量占用带宽越多,SSD对外体现的前端性能也就越差。写放大系数很多因素相关,例如OP、应用IO Pattern等。如果应用IO Pattern比较好,那么可以降低写放大系数,背景噪声流就会减少,前端业务的性能会提升。例如,在SSD完全顺序写入的情况下,写放大系数可以接近于1,此时GC产生的数据流很少,背景流量基本没有,后端带宽基本被业务数据流占用,因此对外体现的性能会很好。


    GC是影响性能的重要因素,除了影响性能之外,GC会增大写放大,对SSD的使用寿命产生影响。从软件层面的角度考虑,可以通过优化应用IO Pattern的方式优化SSD内部GC,从而进一步提升SSD的性能,优化使用寿命。对于下一代更为廉价的QLC SSD介质,就需要采用这种优化思路,否则无法很好的满足实际业务的应用需求。


    3.2 IO Pattern对性能的影响


    IO Pattern会对SSD的性能产生严重影响,主要表现在如下几个方面:


    1,    不同的IO Pattern会产生不同的写放大系数,不同的写放大系数占用后端NAND Flash带宽不同。当前端应用对SSD采用完全顺序的方式进行写入时,此时是最佳的IO Pattern,对于SSD而言写放大系数接近1,SSD内部的背景流量基本可以忽略,前端性能达到最佳。在实际应用中,很难采用这种完全顺序的数据写模型,但可以通过优化逼近顺序写入。


    2,    不同请求大小的IO之间会产生干扰;读写请求之间会产生干扰。小请求会受到大请求的干扰,从而导致小请求的延迟增加,这个比较容易理解,在HDD上同样会存在这种情况。由于NAND Flash介质存在严重的读写不对称性,因此读写请求之间也会互相干扰,尤其是写请求对读请求产生严重的性能影响。


    3.2.1 顺序写入Pattern对SSD性能优化的奥秘


    在针对闪存系统的设计中,需要考虑IO Pattern对性能产生的影响,通过软件的优化来最优化SSD的使用。在实际应用中完全顺序写入的IO Pattern基本上是不存在的,除非用作顺序写入的日志设备。对于顺序写入优化性能这个结论,需要从SSD内部实现来深入理解,知道根源之后,可以采用合理的方式来逼近顺序写入的模式,从而最优化SSD的性能。


    SSD内部采用log-structured的数据记录模式,并发写入的IO数据按照时间顺序汇聚成大数据块,合并形成的大数据块以Page stripe的方式写入NAND Flash。多个Page stripe会被写入同一个GC单元(Chunk or Superblock),当一个GC单元被写完成之后,该GC单元进入sealed模式(只读),分配新的GC单元写新的数据。在这种模式下,如果多个业务的数据流并发随机的往SSD中写入数据,那么多个应用的数据就会交错在一起被存储到同一个GC单元中。如下图所示,不同应用的数据生命周期不同,当需要回收一个GC单元的时候,会存在大量数据的迁移,这些迁移的数据就会形成写放大,影响性能和使用寿命。


    640?wx_fmt=png


    不同应用的数据交错存储在同一个GC单元,本质上就是不同冷热程度的数据交错存储的问题。从GC的角度来讲,相同冷热程度的数据存储在同一个GC单元上是最佳的,为此三星推出了Multi-stream SSD,该SSD就允许不同应用的数据存储到不同的Stream单元(GC单元),从而提升GC效率,降低写放大。Multi-stream是一种显式的设计方式,需要更改SSD接口以及应用程序。从IO Pattern的角度考虑,可以通过顺序大块的方式也可以逼近类似的效果。


    假设操作SSD只存在一个线程,不同的应用都采用大数据块的方式写入数据,那么在一个时间片段内只存在一个应用的数据往SSD中写入数据,那么在一个GC单元内存储的数据会变得有序和规则。如下图所示,采用上述方法之后,一个GC单元内存储的数据将会变得冷热均匀。在GC过程中会大大减少数据的搬移,从而减少背景流量。


    640?wx_fmt=png


    在实际应用中,上述IO Pattern很难产生,主要是应用很难产生非常大粒度的请求。为此在存储系统设计过程中,可以引入Optane高性能存储介质作为SSD的写缓存。前端不同业务的写请求首先写到Optane持久化介质中,在Optane持久化介质中聚合形成大数据块。一旦聚合形成大数据块之后,再写入SSD,通过这种方式可以最大程度的逼近SSD顺序写入过程,提升SSD的性能和使用寿命。


    3.2.2 读写冲突Pattern对性能的影响


    如下图所示,NAND Flash介质具有很强的读写不对称性。Block Erase和Page Program的延迟会远远高于Page Read所耗费的时间。那么在这种情况下,如果read请求在同一个Flash Channel上和Erase、Program操作冲突,那么read操作将会被Erase/program操作影响。这是在读写混合情况下,读性能会受到影响的重要因素。


    640?wx_fmt=png


    在实际应用过程中,经常会发现应用的测试结果和SSD Spec对不上,会比Spec给出的值要来的低。Spec给出的值通常为纯读或者纯写情况下的性能指标,在读写混合的场景下,性能表现和Spec给出的值就会存在非常大的出入。


    对于不同的SSD,通过测试可以发现在读写混合情况下的性能表现差距会比较大。在SSD处于稳态条件下,应用随机读的情况下,如果引入一个压力不是很大的顺序写,那么会发现不同SSD的抗干扰能力是不同的。有些SSD在写干扰的情况下,读性能会急剧下降,延迟快速上升,QoS性能得不到保证。下图是两个SSD在相同情况下的测试结果,从结果来看,有些SSD的抗写干扰能力比较强,读性能不会急剧下降。


    640?wx_fmt=png


    为什么有些SSD会具备比较强的抗写干扰能力呢?其中的奥秘就在于SSD内部的IO调度器。IO调度器会对write、read 和Erase请求进行调度处理,该调度器算法的不同就会表现出不同的抗干扰能力。目前很多NAND Flash可以支持Program/Erase Suspension的功能,在IO调度处理的过程中,为了提升读性能,降低读请求延迟,可以采用Suspension命令对Program/Erase命令暂停,对read请求优先调度处理。


    读写冲突是SSD内部影响IO QoS的重要因素。在SSD内部通过IO调度器的优化可以提升SSD性能的QoS能力,但是还是无法与存储软件结合来协同优化QoS。为了达到最佳的SSD性能QoS,需要关注Openchannel技术。Openchannel其实只是一种软硬件层次划分的方法,通常来讲,SSD内部的逻辑可以划分为面向NAND资源的物理资源管理层以及面向数据布局的资源映射层。物理资源管理由于和NAND Flash密切相关,因此可以放到SSD内部。


    传统的NVMe SSD需要对外暴露标准的块设备接口,因此需要在SSD内部实现资源映射层。从端至端的角度来看,资源映射层可以与存储软件层结合起来,为此将资源映射层从SSD内部剥离出来,集成至存储软件层。一旦资源映射层从SSD内部剥离之后,需要定义一个新的SSD接口,其中的一种接口方式就是Openchannel。


    盘古分布式存储针对SSD QoS问题进行了大量研究,提出了Object SSD的概念,Object SSD也是一种新的SSD接口方式,其采用对象方式对SSD进行读写删操作,每个对象采用Append write操作方式。这种接口方式可以很好的与分布式存储无缝结合。采用Object SSD之后,SSD内部的大量工作被简化,IO的调度会更加灵活,存储软件与SSD协同配合,达到IO性能的最优化,以及QoS的最大化。


    640?wx_fmt=png


    4 SSD写性能分析模型


    SSD内部的数据流分成两大类,一类为前端用户数据流;另一类为内部背景数据流。前端用户数据流和背景数据流会汇聚成NAND Flash后端流量。当背景数据流不存在时,NAND Flash带宽会被用户数据流全部占据,此时SSD对外表现的性能达到最佳。当SSD具有较大写放大时,会产生很大的背景数据流,背景流会抢占NAND Flash带宽,导致前端用户IO性能降低。为了稳定前端IO性能,在SSD内部的调度器会均衡前端和背景流量,保证前端性能的一致性。背景流量的占比反应了SSD的写放大系数,因此,站在NAND Flash带宽占用的角度可以分析SSD在稳态情况下的性能。


    在此,假设写放大系数为WA,顺序写情况下的总带宽数为B,用户写入流量(随机写入流量)为U。那么,由于GC写放大造成的背景流量为:(WA - 1)* U
    写放大流量为一读一写,都会占用带宽,因此,总带宽可以描述为:


    2  (WA - 1)  U + U = B
    因此,可以得到:
    U = B / (2(WA - 1) + 1) = B / (2  WA - 1)
    上述公式表述了前端用户流量和NAND Flash总带宽、写放大系数之间的关系。


    根据Spec,Intel P4500的顺序写带宽为1.9GB/s,按照上述公式,在随机访问模式下的带宽为: 1900 / (2 * 4 - 1) = 270MB/s,IOPS为67K,根据该公式推导的结果和Spec给出的结果相同。


    下图是Intel P4500和Samsung PM963随机写延迟和推导公式之间的对比。结果非常吻合。


    640?wx_fmt=png


    由此可以推出,随机写性能由SSD内部后端带宽以及写放大系数来决定。因此,从存储软件的角度出发,我们可以通过优化IO Pattern的方式减小写放大系数,从而可以提升SSD的随机写性能。


    5 小结


    闪存存储技术正在飞速发展,闪存介质、SSD控制器、存储系统软件、存储硬件平台都在围绕闪存日新月异的发展。闪存给数据存储带来的价值显而易见,数据中心闪存化是重要发展趋势。NVMe SSD性能受到很多因素的影响,在软件层面可以通过IO Pattern优化SSD的性能,使得整体存储系统的性能达到最佳。

    文章来源:云栖社区


    更多技术已经整理成电子书

    十一期间优惠活动相详细信息如下

    (如满足优惠条件下单可联系修改价格)

    640?wx_fmt=jpeg


    温馨提示:

    请搜索“ICT_Architect”“扫一扫”二维码关注公众号,点击原文链接获取更多电子书详情

    640?wx_fmt=png&wxfrom=5&wx_lazy=1

    求知若渴, 虚心若愚

    640?wx_fmt=gif&wxfrom=5&wx_lazy=1

    展开全文
  • 影响MySQL Server性能的相关因素

    千次阅读 2010-07-30 21:29:00
    影响MySQL Server性能的相关因素

    影响MySQL Server性能的相关因素

           推荐大家一本书《MySQL性能调优与架构设计》,写的真是不错,第6章节的内容同样比较精彩,虽然语言很直白话,但是写的很在理,摘取精华部分,整理下来分享给大家。

     

    前言

    大部分的人都一致地认为一个数据库应用系统(这里的数据库应用系统指所有的使用数据库的系统)的性能瓶颈最容易出现于数据的操作方面,而数据库应用系统的大部分数据操作都是通过数据库管理软件所提供的相关接口完成的。所以数据库管理软件也就很自然的成为了数据库应用系统的性能瓶颈所在,这是当前业务比较普遍的一个看法。但我们的应用系统的性能瓶颈真的就是完全是因为数据库管理软件和数据库主机自身的原因吗?我们将通过本章的内容来进行一个较为深入地分析,让大家了解到一个数据库应用系统的性能到底与哪些地方相关,让大家寻找各自应用系统中出现性能的问题的根本原因,而尽可能清楚地知道该如何去优化自己的应用系统。

     

    1.商业需求对性能的影响

    应用系统中的每一个功能在设计初衷肯定都是出于为用户提供某种服务,或者满足用户的某种需求的,但是,并不是每一个功能在最后都能够很成功,甚至有些功能的推出可能在整个系统中是属于画蛇添足的。不仅没有为用户提高任何体验度,也没有为用户改进多少功能易用性,反而在整个系统中成为一个累赘,带来资源的浪费。

     

    一、不合理需求造成资源投入产出比过低

    需求是否合理很多时候可能并不是很容易界定的,尤其是作为技术人员而言,可能更难以确定一个需求的合理性。即使指出,也不一定会被产品经理们认可。那作为技术人员的我们怎么来证明一个需求是否合理呢?

    1)每次产品经理们提出新的项目(或功能需求)的时候,应该要求他们同时给出该项目的预期收益的量化指标,以备项目上先后统计评估投入产出比率。

    2)在每次项目进行过程中,应该详细记录所有的资源投入,包括人力投入,硬件设施的投入以及其他任何项目相关的资源投入。

    3)项目(或功能需求)上线之后,应该及时通过收集相关数据统计出项目的实际收益值,以便计算投入产出比率的时候使用。

    4)技术部门应该尽可能推动设计出一个项目(或功能需求)的投入产出比率的计算规则。在项目上线一段时间之后,通过项目实际收益的统计数据和项目的投入资源量,计算出整个项目的实际投入产出值,并公布给所有参与项目的部门,同时存放以备后查。

    有了实际的投入产出比率,我们就可以和项目立项之初产品经理们的预期投入产出比率做出比较,判定出这个项目做的是否值得。而且当积累了较多的项目投入产出比率之后,我们可以根据历史数据分析出一个项目合理的投入产出比率应该是多少。这样,在项目立项之初,我们就可以判定出产品经理们的预期投入产出比率是否合理,项目是否真的有进行的必要。

    有了实际的投入产出比率之后,我们还可以拿出数据给老板们看,让他们知道功能并非是越多越好,让他知道有些功能是应该撤下来的,即使撤下该功能可能需要投入不少资源。

    实际上,一般而言,在产品开发及运营部门内部都会做上面所说的这些事情。但很多时候可能更多只是一种形式化的过程。在有些比较规范的公司可能也完成了上面的大部分流程,但是要么数据不公开,要么公开给其他部门的数据存在一定的偏差,不具备真实性。

    为什么会这样呢?其实就是一个原因,就是部门之间的利益冲突及业绩冲突问题。产品经理们总是希望尽可能的让用户觉得自己设计的产品功能齐全,让老板觉得自己做了很多事情。但是从来都不会去关心因为做一个功能所带来的成本投入,或者说是不会特别的关心这一点。而且很多时候是因为他们根本就不了解技术,他们只是一群外行却来领导内行,这不得不说是企业管理过程中出现的一个巨大的漏洞,这样由于他们对于技术理解的空白所带来的复杂度给产品本身带来了很多的负面影响。

    这里我们就拿一个看上去非常简单的功能来分析一下。

    需求:一个论坛贴子问题的统计

    附加要求:实时更新

    在很多人看来,这个功能是非常容易实现的,不就是执行一条SELECT COUNT(*)Query就可以得到结果了吗?是的,确实是只需要如此简单的一条Query语句就可以实现了。但是,如果我们采用的不是MyISAM存储引擎,而是使用Innodb的存储引擎,那么大家可以想像一下,如果存放贴子的表已经有上千万贴子的时候,执行这样一条Query语句需要多少成本?恐怕再好的硬件设备,都不可能在10s之内完成一次查询吧。如果我们的访问量再大一些,还有人觉得这是一件简单的事情吗?

    既然这样查询是不行的,那我们是不是该专门为这个功能建立一个表,就只有一个字段,一条记录,就存放这个统计量,每次有新的贴子产生时候,都将这个值增加1,这样我们每次都只需要查询这个表就可以得到结果了,这个效率肯定能够满足要求了。确实,查询效率肯定能够满足需求,可是如果我们的系统贴子产生的很快,在高峰期时候可能每秒就有几十甚至上百个贴子新增操作的时候,恐怕这个统计表又要成为大家的噩梦了。要么因为并发的问题造成统计结果不准确,要么因为锁资源争用严重造成了整体性能的大幅度下降。

    其实这里问题的焦点不应该是实现这个功能的技术细节,而是在于这个功能的附加要求“实时更新”上面。当一个论坛的贴子数量很大之后,到底有多少人会关注这个统计数据是否是实时变化的呢?有多少人在乎这个数据在短时间内是不精确的?我想恐怕不会有人会傻里巴叽地盯着这个统计数据并追究自己发了一个贴子然后回头刷新时候,新页面发现这个统计数字并没有加1.即使明明白白的告诉用户这个统计数据每过多长时间更新一次,那有怎样?难道会有很多用户会因此很不爽吗?

    只要去掉了这个“实时更新”附加条件,我们就可以非常容易地实现这个功能了。就像之前所提到的那样,通过创建一个统计表,然后通过一个定时任务每隔一定时间段去更新一次这里面的统计值,这样即可以解决统计值查询效率问题,又可以保证不影响新发贴的效率,一举两得。

    实际上,在我们应用的系统中还有很多很多类似的功能点可以优化。如果某些场合的列表页面参与列表的数据量达到一个数量级之后,完全可以不用准确的显示这个列表总共有多少条信息,总共分了多少页,而只需要一个大概估计值或者一个时间段之前的统计值。这样就省略了我们的分页程序需要在分以前实时COUNT出满足条件的记录数。

    其实,在很多应用系统中,实时和准实时,精确与基本准确,在很多地方所带来的性能消耗可能是几个性能的差别。在系统性能优化中,应该尽量分析出那些可以不实时和不完全精确的地方,作出一些相应的调整,可能会给大家带来意想不到的巨大性能提升。

     

    二、无用功能堆积使系统过度复杂影响整体性能

    很多时候,为系统增加某个功能可能并不需要花费太多成本,而要想将一个运行了一段时间的功能从原有系统撤下来却是非常困难的。

    首先,对于开发部门,可能要重新整理很多的代码,找出可能存在与增加该功能所编写的代码有交集的其他功能点,删除没有关联的代码,修改有关联的代码;其次,对于测试部门,由于功能的变动,必须要回归测试所有相关的功能点是否正常。可能由于界定困难,不得不将回归范围扩展到很大,测试工作量也很大。最后,所有与撤除下线某个功能相关的工作参与者来说,又无法带来任何实质性的收益,而恰恰相反是,带来的只可能是风险。

    由于上面的这几个因素,可能很少有公司能够有很完善的项目(或者功能)下线机制,也很少有公司能做到及时将系统中某些不合适的功能下线。所以,我们所面对的应用系统可能总是越来越复杂,越来越庞大,短期内的复杂可能并无太大问题,但是随着时间的积累,我们所面对的系统就会变得极其臃肿。不仅维护困难,性能也会越来越差。尤其是有些并不合理的功能,在设计之初或者是刚上线的时候由于数据量较小,带来不了多少性能损耗。可随着时间的推移,数据库中的数据量越来越大,数据检索越来越困难,对整个系统带来的资源消耗也就越来越大。

    而且,由于系统复杂度的不断增加,给后续其他功能的开发带来实现的复杂度,可能很多本来很简单的功能,因为系统的复杂而不得不增加很多的逻辑判断,造成系统应用程序的计算量不断增加,本身性能就会受到影响。而如果这些逻辑判断还需要与数据库交互通过持久化的数据来完成的话,所带来的性能损失就更大,对整个系统的性能影响也就更大了。

    2.系统架构及实现对性能的影响

    一个WEB应用系统,自然离不开WEB应用程序(WEB App)和应用服务器(App Server)。。App Server 我们能控制的内容不多,大多都是使用已经久经考验的成熟产品,大家能做的也就只是通过一些简单的参数设置调整来进行调优,不做细究。而Web App 大部分都是各自公司根据业务需求自行开发,可控性要好很多。所以我们从Web 应用程序着手分析一个应用程序架构的不同设计对整个系统性能的影响将会更合适。

    上一节中商业需求告诉了我们一个系统应该有什么不应该有什么,系统架构则则决定了我们系统的构建环境。就像修建一栋房子一样,在清楚了这栋房子的用途之后,会先有建筑设计师来画出一章基本的造型图,然后还需要结构设计师为我们设计出结构图。系统架构设计的过程就和结构工程好似设计结构图一样,需要为整个系统搭建出一个尽可能最优的框架,让整个系统能够有一个稳定高效的结构体系让我们实现各种商业需求。

     

    一、数据库中存放的数据都是适合在些存放吗?

    对于有些开发人员来说,数据库就是一个操作最方便的万能存储中心,希望什么数据都存放在数据库中,不论是需要持久化的数据,还是临时存放的过程数据,不论是普通的纯文本格式的字符数据,还是多媒体的二进制数据,都喜欢全部塞如数据库中。因为对于应用服务器来说,数据库很多时候都是一个集中式的存储环境,不像应用服务器那样可能有很多台;而且数据库有专门的DBA 去帮忙维护,而不像应用服务器很多时候还需要开发人员去做一些维护;还有一点很关键的就是数据库的操作非常简单统一,不像文件操作或者其他类型的存储方式那么复杂。

    其实我个人认为,现在的很多数据库为我们提供了太多的功能,反而让很多并不是太了解数据库的人错误的使用了数据库的很多并不是太擅长或者对性能影响很大的功能,最后却全部怪罪到数据库身上。

     

    实际上,以下几类数据都是不适合在数据库中存放的:

    1.二进制多媒体数据

    将二进制多媒体数据存放在数据库中,一个问题是数据库空间资源耗用非常严重,另一个问题是这些数据的存储很消耗数据库主机的CPU 资源。这种数据主要包括图片,音频、视频和其他一些相关的二进制文件。这些数据的处理本不是数据库的优势,如果我们硬要将他们塞入数据库,肯定会造成数据库的处理资源消耗严重。

    2.流水队列数据

    我们都知道,数据库为了保证事务的安全性(支持事务的存储引擎)以及可恢复性,都是需要记录所有变更的日志信息的。而流水队列数据的用途就决定了存放这种数据的表中的数据会不断的被INSERTUPDATE DELETE,而每一个操作都会生成与之对应的日志信息。在MySQL 中,如果是支持事务的存储引擎,这个日志的产生量更是要翻倍。而如果我们通过一些成熟的第三方队列软件来实现这个Queue 数据的处理功能,性能将会成倍的提升。

    3.超大文本数据

    对于5.0.3 之前的MySQL 版本,VARCHAR 类型的数据最长只能存放255个字节,如果需要存储更长的文本数据到一个字段,我们就必须使用TEXT 类型(最大可存放64KB)的字段,甚至是更大的LONGTEXT 类型(最大4GB)。而TEXT 类型数据的处理性能要远比VARCHAR 类型数据的处理性能低下很多。从5.0.3 版本开始,VARCHAR 类型的最大长度被调整到64KB 了,但是当实际数据小于255Bytes 的时候,实际存储空间和实际的数据长度一样,可一旦长度超过255 Bytes 之后,所占用的存储空间就是实际数据长度的两倍。

    所以,超大文本数据存放在数据库中不仅会带来性能低下的问题,还会带来空间占用的浪费问题。

     

    二、是否合理的利用了应用层Cache机制?

    对于Web 应用,活跃数据的数据量总是不会特别的大,有些活跃数据更是很少变化。对于这类数据,我们是否有必要每次需要的时候都到数据库中去查询呢?如果我们能够将变化相对较少的部分活跃数据通过应用层的Cache 机制Cache 到内存中,对性能的提升肯定是成数量级的,而且由于是活跃数据,对系统整体的性能影响也会很大。

    当然,通过Cache 机制成功的案例数不胜数,但是失败的案例也同样并不少见。如何合理的通过Cache 技术让系统性能得到较大的提升也不是通过寥寥几笔就能说明的清楚,这里我仅根据以往的经验列举一下什么样的数据适合通过Cache 技术来提高系统性能:

    1.系统各种配置及规则数据

    由于这些配置信息变动的频率非常低,访问概率又很高,所以非常适合存使用Cache

    2.活跃用户的基本信息数据

    虽然我们经常会听到某某网站的用户量达到成百上千万,但是很少有系统的活跃用户量能够都达到这个数量级。也很少有用户每天没事干去将自己的基本信息改来改去。更为重要的一点是用户的基本信息在应用系统中的访问频率极其频繁。所以用户基本信息的Cache,很容易让整个应用系统的性能出现一个质的提升。

    3.活跃用户的个性化定制信息数据

    虽然用户个性化定制的数据从访问频率来看,可能并没有用户的基本信息那么的频繁,但相对于系统整体来说,也占了很大的比例,而且变更频率一样不会太多。从Ebay PayPal 通过MySQL Memory 存储引擎实现用户个性化定制数据的成功案例我们就能看出对这部分信息进行Cache 的价值了。虽然通过MySQL Memory 存储引擎并不像我们传统意义层面的Cache 机制,但正是对Cache 技术的合理利用和扩充造就了项目整体的成功。

    4.准实时的统计信息数据

    所谓准实时的统计数据,实际上就是基于时间段的统计数据。这种数据不会实时更新,也很少需要增量更新,只有当达到重新Build 该统计数据的时候需要做一次全量更新操作。虽然这种数据即使通过数据库来读取效率可能也会比较高,但是执行频率很高之后,同样会消耗不少资源。既然数据库服务器的资源非常珍贵,我们为什么不能放在应用相关的内存Cache 中呢?

    5.其他一些访问频繁但变更较少的数据

    出了上面这四种数据之外,在我们面对的各种系统环境中肯定还会有各种各样的变更较少但是访问很频繁的数据。只要合适,我们都可以将对他们的访问从数据库移到Cache 中。

     

    三、数据库实现都是最精简的吗?

    从以往的经验来看,一个合理的数据存取实现和一个拙劣的实现相比,在性能方面的差异经常会超出一个甚至几个数量级。我们先来分析一个非常简单且经常会遇到类似情况的示例:

    在我们的示例网站系统中,现在要实现每个用户查看各自相册列表(假设每个列表显示10 张相片)的时候,能够在相片名称后面显示该相片的留言数量。这个需求大家认为应该如何实现呢?我想90%的开发开发工程师会通过如下两步来实现该需求:

    1、通过“SELECT id,subject,url FROM photo WHERE user_id = ? limit 10 得到第一页的相片相关信息。

    2、通过第1 步结果集中的10 个相片id 循环运行十次“SELECT COUNT(*) FROM photo_comment WHERE photh_id = ? 来得到每张相册的回复数量然后再封装展现对象。

     

    此外可能还有部分人想到了如下的方案:

    1、和上面完全一样的操作步骤;

    2、通过程序拼装上面得到的10 photo id,再通过in 查询“SELECT photo_id,count(*) FROM photo_comment WHERE photo_id in (?) GROUP BY photo_id 一次得到10 photo 的所有回复数量,再组装两个结果集得到展现对象。

     

    我们来对以上两个方案做一下简单的比较:

    1.MySQL执行的SQL数量来看,第一种解决方案为111+10)条SQL语句,第二种解决方案为2SQL语句(1+1)。

    2.从应用程序与数据库交互来看,第一种为11次,第二种为2次。

    3.从数据库的IO操作来看,简单假设每次SQL1IO,第一种最少为11IO,第二种小于等于11IO,而且只有当数据非常之离散的情况下,才会需要11次。

    4、从数据库处理的查询复杂度来看,第一种为两类很简单的查询,第二种有一条SQL 语句有GROUP BY 操作,比第一种解决方案增加了了排序分组操作。

    5、从应用程序结果集处理来看,第一种11 次结果集的处理,第二中2 次结果集的处理,但是第二种解决方案中第二词结果处理数量是第一次的10 倍。

    6、从应用程序数据处理来看,第二种比第一种多了一个拼装photo_id 的过程。

     

    我们先从以上6 点来做一个性能消耗的分析:

    1、由于MySQL 对客户端每次提交的SQL 不管是相同还是不同,都需要进行完全解析,这个动作主要消耗的资源是数据库主机的CPU,那么这里第一种方案和第二种方案消耗CPU 的比例是11:2SQL 语句的解析动作在整个SQL 语句执行过程中的整体消耗的CPU 比例是较多的。

    2、应用程序与数据库交互所消耗的资源基本上都在网络方面,同样也是112

    3、数据库IO 操作资源消耗为小于或者等于1:1

    4、第二种解决方案需要比第一种多消耗内存资源进行排序分组操作,由于数据量不大,多出的消耗在语句整体消耗中占用比例会比较小,大概不会超过20%,大家可以针对性测试。

    5、结果集处理次数也为11:2,但是第二中解决方案第二次处理数量较大,整体来说两次的性能消耗区别不大。

    6、应用程序数据处理方面所多出的这个photo_id 的拼装所消耗的资源是非常小的,甚至比应用程序与MySQL 做一次简单的交互所消耗的资源还要少。

    综合上面的这6 点比较,我们可以很容易得出结论,从整体资源消耗来看,第二中方案会远远优于第一种解决方案。而在实际开发过程中,我们的程序员却很少选用。主要原因其实有两个,一个是第二种方案在程序代码实现方面可能会比第一种方案略为复杂,尤其是在当前编程环境中面向对象思想的普及,开发工程师可能会更习惯于以对象为中心的思考方式来解决问题。还有一个原因就是我们的程序员可能对SQL 语句的使用并不是特别的熟悉,并不一定能够想到第二条SQL 语句所实现的功能。对于第一个原因,我们可能只能通过加强开发工程师的性能优化意识来让大家能够自觉纠正,而第二个原因的解决就正是需要我们出马的时候了。SQL 语句正是我们的专长,定期对开发工程师进行一些相应的数据库知识包括SQL 语句方面的优化培训,可能会给大家带来意想不到的收获的。

    这里我们还仅仅只是通过一个很长见的简单示例来说明数据层架构实现的区别对整体性能的影响,实际上可以简单的归结为过渡依赖嵌套循环的使用或者说是过渡弱化SQL 语句的功能造成性能消耗过多的实例。后面我将进一步分析一下更多的因为架构实现差异所带来的性能消耗差异。

     

    四、过度依赖数据库Query语句的功能造成数据库操作效率低下

    前面的案例是开发工程师过渡弱化SQL 语句的功能造成的资源浪费案例,而这里我们再来分析一个完全相反的案例:在群组简介页面需要显示群名称和简介,每个群成员的nick_name,以及群主的个人签名信息。

    需求中所需信息存放在以下四个表中:useruser_profilegroupsuser_group

    我们先看看最简单的实现方法,一条SQL 语句搞定所有事情:

    SELECT name,description,user_type,nick_name,sign

    FROM groups,user_group,user ,user_profile

    WHERE groups.id = ?

    AND groups.id = user_group.group_id

    AND user_group.user_id = user.id

    AND user_profile.user_id = user.id

    当然我们也可以通过如下稍微复杂一点的方法分两步搞定:

    首先取得所有需要展示的group 的相关信息和所有群组员的nick_name 信息和组员类别:

    SELECT name,description,user_type,nick_name

    FROM groups,user_group,user

    WHERE groups.id = ?

    AND groups.id = user_group.group_id

    AND user_group.user_id = user.id

    然后在程序中通过上面结果集中的user_type 找到群主的user_id 再到user_profile 表中取得群主的签名信息:

    SELECT sign FROM user_profile WHERE user_id = ?

    大家应该能够看出两者的区别吧,两种解决方案最大的区别在于交互次数和SQL 复杂度。而带来的实际影响是第一种解决方案对user_profile 表有不必要的访问(非群主的profile 信息),造成IO 访问的直接增加在20%左右。而大家都知道,IO 操作在数据库应用系统中是非常昂贵的资源。尤其是当这个功能的PV 较大的时候,第一种方案造成的IO 损失是相当大的。

     

    五、重复执行相同的SQL 造成资源浪费

    这个问题其实是每个人都非常清楚也完全认同的一个问题,但是在应用系统开发过程中,仍然会常有这样的现象存在。究其原因,主要还是开发工程师思维中面向对象的概念太过深入,以及为了减少自己代码开发的逻辑和对程序接口过度依赖所造成的。

    我曾经在一个性能优化项目中遇到过一个案例,某个功能页面一侧是“分组”列表,是一列“分组”的名字。页面主要内容则是该“分组”的所有“项目”列表。每个“项目”以名称(或者图标)显示,同时还有一个SEO 相关的需求就是每个“项目”名称的链接地址中是需要有“分组”的名称的。所以在“项目”列表的每个“项目”的展示内容中就需要得到该项目所属的组的名称。按照开发工程师开发思路,非常容易产生取得所有“项目”结果集并映射成相应对象之后,再从对象集中获取“项目”所属组的标识字段,然后循环到“分组”表中取得需要的”组名“。然后再将拼装成展示对象。

    看到这里,我想大家应该已经知道这里存在的一个最大的问题就是多次重复执行了完全相同的SQL得到完全相同的内容。同时还犯了前面第一个案例中所犯的错误。或许大家看到之后会不相信有这样的案例存在,我可以非常肯定的告诉大家,事实就是这样。同时也请大家如果有条件的话,好好Review 自己所在的系统的代码,非常有可能同样存在上面类似的情形。

    还有部分解决方案要远优于上面的做法,那就是不循环去取了,而是通过Join 一次完成,也就是解决了第一个案例所描述的性能问题。但是又误入了类似于第二个案例所描述的陷阱中了,因为实际上他只需要一次查询就可以得到所有“项目”所属的“分组”的名称(所有项目都是同一个组的)。

    当然,也有部分解决方案也避免了第二个案例的问题,分为两条SQL,两步完成了这个需求。这样在性能上面基本上也将近是数量级的提升了。

    但是这就是性能最优的解决方案了么?不是的,我们甚至可以连一次都不需要访问就获得所需要的“分组”名称。首先,侧栏中的“分组”列表是需要有名称的,我们为什么不能直接利用到呢?

    当然,可能有些系统的架构决定了侧栏和主要内容显示区来源于不同的模板(或者其他结构),那么我们也完全可以通过在进入这个功能页面的链接请求中通过参数传入我们需要的“分组”名称。这样我们就可以完全不需要根据“项目”相关信息去数据库获取所属“分组”的信息,就可以完成相应需求了。当然,是否需要通过请求参数来节省最后的这一次访问,可能会根据这个功能页面的PV 来决定,如果访问并不是非常频繁,那么这个节省可能并不是很明显,而应用系统的复杂度却有所增加,而且程序看上去可能也会不够优雅,但是如果访问非常频繁的场景中,所节省的资源还是比较可观的。

    上面还仅仅只是列举了我们平时比较常见的一些实现差异对性能所带来的影响,除了这些实现方面所带来的问题之外,应用系统的整体架构实现设计对系统性能的影响可能会更严重。下面大概列举了一些较为常见的架构设计实现不当带来的性能问题和资源浪费情况。

    1Cache 系统的不合理利用导致Cache 命中率低下造成数据库访问量的增加,同时也浪费了Cache系统的硬件资源投入。

    2、过度依赖面向对象思想,对系统架构的要求过于完美,造成实现逻辑复杂化。

    3、对可扩展性的过渡追求,促使系统设计的时候将对象拆得过于离散,造成系统中大量的复杂Join语句,而MySQL Server 在各数据库系统中的主要优势在于处理简单逻辑的查询,这与其锁定的机制也有较大关系。

    4、对数据库的过渡依赖,将大量更适合存放于文件系统中的数据存入了数据库中,造成数据库资源的浪费,影响到系统的整体性能,如各种日志信息。

    5、过度理想化系统的用户体验,使大量非核心业务消耗过多的资源,如大量不需要实时更新的数据做了实时统计计算。

    以上仅仅是一些比较常见的症结,在各种不同的应用环境中肯定还会有很多不同的性能问题,可能需要大家通过仔细的数据分析和对系统的充分了解才能找到,但是一旦找到症结所在,通过相应的优化措施,所带来的收益也是相当可观的。

    3.Query语句对系统性能的影响

    前面一节我们介绍了应用系统的实现差异对数据库应用系统整体性能的影响,这一节我们将分析SQL语句的差异对系统性能的影响。

    我想对于各位读者来说,肯定都清楚SQL 语句的优劣是对性能有影响的,但是到底有多大影响可能每个人都会有不同的体会,每个SQL 语句在优化之前和优化之后的性能差异也是各不相同,所以对于性能差异到底有多大这个问题我们我们这里就不做详细分析了。我们重点分析实现同样功能的不同SQL 语句在性能方面会产生较大的差异的根本原因,并通过一个较为典型的示例来对我们的分析做出相应的验证。

    为什么返回完全相同结果集的不同SQL 语句,在执行性能方面存在差异呢?这里我们先从SQL 语句在数据库中执行并获取所需数据这个过程来做一个大概的分析了。

    MySQL Server 的连接线程接收到Client 端发送过来的SQL 请求之后,会经过一系列的分解Parse,进行相应的分析。然后,MySQL 会通过查询优化器模块(Optimizer)根据该SQL 所设涉及到的数据表的相关统计信息进行计算分析,然后再得出一个MySQL 认为最合理最优化的数据访问方式,也就是我们常说的“执行计划”,然后再根据所得到的执行计划通过调用存储引擎借口来获取相应数据。然后再将存储引擎返回的数据进行相关处理,并以Client 端所要求的格式作为结果集返回给Client 端的应用程序。

    注:这里所说的统计数据,是我们通过ANALYZE TABLE 命令通知MySQL对表的相关数据做分析之后所获得到的一些数据统计量。这些统计数据对MySQL 优化器而言是非常重要的,优化器所生成的执行计划的好坏,主要就是由这些统计数据所决定的。实际上,在其他一些数据库管理软件中也有类似相应的统计数据。

    我们都知道,在数据库管理软件中,最大的性能瓶颈就是在于磁盘IO,也就是数据的存取操作上面。而对于同一份数据,当我们以不同方式去寻找其中的某一点内容的时候,所需要读取的数据量可能会有天壤之别,所消耗的资源也自然是区别甚大。所以,当我们需要从数据库中查询某个数据的时候,所消耗资源的多少主要就取决于数据库以一个什么样的数据读取方式来完成我们的查询请求,也就是取决于SQL 语句的执行计划。

    对于唯一一个SQL 语句来说,经过MySQL Parse 之后分解的结构都是固定的,只要统计信息稳定,其执行计划基本上都是比较固定的。而不同写法的SQL语句,经过MySQL Parse 之后分解的结构结构就可能完全不同,即使优化器使用完全一样的统计信息来进行优化,最后所得出的执行计划也可能完全不一样。而执行计划又是决定一个SQL 语句最终的资源消耗量的主要因素。所以,实现功能完全一样的SQL 语句,在性能上面可能会有差别巨大的性能消耗。当然,如果功能一样,而且经过MySQL 的优化器优化之后的执行计划也完全一致的不同SQL 语句在资源消耗方面可能就相差很小了。当然这里所指的消耗主要是IO资源的消耗,并不包括CPU 的消耗。

    下面我们将通过一两个具体的示例来分析写法不一样而功能完全相同的两条SQL 的在性能方面的差异。

     

    示例一

    需求:取出某个group(假设id 100)下的用户编号(id),用户昵称(nick_name)、用户性别(sexuality)、用户签名(sign)和用户生日(birthday),并按照加入组的时间(user_group.gmt_create)来进行倒序排列,取出前20个。

     

    解决方案一

    SELECT id,nick_name

    FROM user,user_group

    WHERE user_group.group_id = 1

    and user_group.user_id = user.id

    ORDER BY gmt_create desc

    limit 100,20;

     

    解决方案二

    SELECT user.id,user.nick_name

    FROM (

    SELECT user_id

    FROM user_group

    WHERE user_group.group_id = 1

    ORDER BY gmt_create desc

    limit 100,20) t,user

    WHERE t.user_id = user.id;

     

    我们先来看看执行计划:

    sky@localhost : example 10:32:13> explain

    -> SELECT id,nick_name

    -> FROM user,user_group

    -> WHERE user_group.group_id = 1

    -> and user_group.user_id = user.id

    -> ORDER BY user_group.gmt_create desc

    -> limit 100,20/G

    *************************** 1. row ***************************

    id: 1

    select_type: SIMPLE

    table: user_group

    type: ref

    possible_keys: user_group_uid_gid_ind,user_group_gid_ind

    key: user_group_gid_ind

    key_len: 4

    ref: const

    rows: 31156

    Extra: Using where; Using filesort

    *************************** 2. row ***************************

    id: 1

    select_type: SIMPLE

    table: user

    type: eq_ref

    possible_keys: PRIMARY

    key: PRIMARY

    key_len: 4

    ref: example.user_group.user_id

    rows: 1

    Extra:

    sky@localhost : example 10:32:20> explain

    -> SELECT user.id,user.nick_name

    -> FROM (

    -> SELECT user_id

    -> FROM user_group

    -> WHERE user_group.group_id = 1

    -> ORDER BY gmt_create desc

    -> limit 100,20) t,user

    -> WHERE t.user_id = user.id/G

    *************************** 1. row ***************************

    id: 1

    select_type: PRIMARY

    table: <derived2>

    type: ALL

    possible_keys: NULL

    key: NULL

    key_len: NULL

    ref: NULL

    rows: 20

    Extra:

    *************************** 2. row ***************************

    id: 1

    select_type: PRIMARY

    table: user

    type: eq_ref

    possible_keys: PRIMARY

    key: PRIMARY

    key_len: 4

    ref: t.user_id

    rows: 1

    Extra:

    *************************** 3. row ***************************

    id: 2

    select_type: DERIVED

    table: user_group

    type: ref

    possible_keys: user_group_gid_ind

    key: user_group_gid_ind

    key_len: 4

    ref: const

    rows: 31156

    Extra: Using filesort

     

    执行计划对比分析:

    解决方案1中的执行计划显示MySQL 在对两个参与Join 的表都利用到了索引,user_group表利用了user_group_gid_ind索引(key: user_group_gid_ind),user 表利用到了主键索引(key:PRIMARY),在参与Join MySQL 通过Where过滤后的结果集与user 表进行Join,最后通过排序取出Join 后结果的“limit 100,20条结果返回。

    解决方案2SQL 语句利用到了子查询,所以执行计划会稍微复杂一些,首先可以看到两个表都和解决方案1一样都利用到了索引(所使用的索引也完全一样),执行计划显示该子查询以user_group 为驱动,也就是先通过user_group 进行过滤并马上进行这一论的结果集排序,也就取得了SQL 中的“limit 100,20条结果,然后与user 表进行Join,得到相应的数据。这里可能有人会怀疑在自查询中从user_group表所取得与user 表参与Join的记录条数并不是20 条,而是整个group_id=1 的所有结果。那么请大家看看该执行计划中的第一行,该行内容就充分说明了在外层查询中的所有的20 条记录全部被返回。

    通过比较两个解决方案的执行计划,我们可以看到第一中解决方案中需要和user 表参与Join 的记录数MySQL 通过统计数据估算出来是31156,也就是通过user_group 表返回的所有满足group_id=1 的记录数(系统中的实际数据是20000)。而第二种解决方案的执行计划中,user 表参与Join 的数据就只有20条,两者相差很大,通过本节最初的分析,我们认为第二中解决方案应该明显优于第一种解决方案。

    下面我们通过对比两个解决觉方案的SQL 实际执行的profile 详细信息,来验证我们上面的判断。由于SQL 语句执行所消耗的最大两部分资源就是IOCPU,所以这里为了节约篇幅,仅列出BLOCK IO CPU两项profile 信息(Query Profiler 的详细介绍将在后面章节中独立介绍):

     

    先打开profiling 功能,然后分别执行两个解决方案的SQL 语句:

    sky@localhost : example 10:46:43> set profiling = 1;

    Query OK, 0 rows affected (0.00 sec)

    sky@localhost : example 10:46:50> SELECT id,nick_name

    -> FROM user,user_group

    -> WHERE user_group.group_id = 1

    -> and user_group.user_id = user.id

    -> ORDER BY user_group.gmt_create desc

    -> limit 100,20;

    +--------+-----------+

    | id     | nick_name |

    +--------+-----------+

    | 990101 | 990101 |

    | 990102 | 990102 |

    | 990103 | 990103 |

    | 990104 | 990104 |

    | 990105 | 990105 |

    | 990106 | 990106 |

    | 990107 | 990107 |

    | 990108 | 990108 |

    | 990109 | 990109 |

    | 990110 | 990110 |

    | 990111 | 990111 |

    | 990112 | 990112 |

    | 990113 | 990113 |

    | 990114 | 990114 |

    | 990115 | 990115 |

    | 990116 | 990116 |

    | 990117 | 990117 |

    | 990118 | 990118 |

    | 990119 | 990119 |

    | 990120 | 990120 |

    +--------+-----------+

    20 rows in set (1.02 sec)

     

    sky@localhost : example 10:46:58> SELECT user.id,user.nick_name

    -> FROM (

    -> SELECT user_id

    -> FROM user_group

    -> WHERE user_group.group_id = 1

    -> ORDER BY gmt_create desc

    -> limit 100,20) t,user

    -> WHERE t.user_id = user.id;

    +--------+-----------+

    | id     | nick_name |

    +--------+-----------+

    | 990101 | 990101 |

    | 990102 | 990102 |

    | 990103 | 990103 |

    | 990104 | 990104 |

    | 990105 | 990105 |

    | 990106 | 990106 |

    | 990107 | 990107 |

    | 990108 | 990108 |

    | 990109 | 990109 |

    | 990110 | 990110 |

    | 990111 | 990111 |

    | 990112 | 990112 |

    | 990113 | 990113 |

    | 990114 | 990114 |

    | 990115 | 990115 |

    | 990116 | 990116 |

    | 990117 | 990117 |

    | 990118 | 990118 |

    | 990119 | 990119 |

    | 990120 | 990120 |

    +--------+-----------+

    20 rows in set (0.96 sec)

     

    查看系统中的profile 信息,刚刚执行的两个SQL 语句的执行profile 信息已经记录下来了:

     

    sky@localhost : example 10:47:07> show profiles/G

    *************************** 1. row ***************************

    Query_ID: 1

    Duration: 1.02367600

    Query: SELECT id,nick_name

    FROM user,user_group

    WHERE user_group.group_id = 1

    and user_group.user_id = user.id

    ORDER BY user_group.gmt_create desc

    limit 100,20

    *************************** 2. row ***************************

    Query_ID: 2

    Duration: 0.96327800

    Query: SELECT user.id,user.nick_name

    FROM (

    SELECT user_id

    FROM user_group

    WHERE user_group.group_id = 1

    ORDER BY gmt_create desc

    limit 100,20) t,user

    WHERE t.user_id = user.id

    2 rows in set (0.00 sec)

    sky@localhost : example 10:47:34> SHOW profile CPU,BLOCK IO io FOR query 1;

    +--------------------+----------+-----------+------------+--------------+---------------+

    | Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |

    +--------------------+----------+-----------+------------+--------------+---------------+

    | (initialization) | 0.000068 | 0 | 0 | 0 | 0 |

    | Opening tables | 0.000015 | 0 | 0 | 0 | 0 |

    | System lock | 0.000006 | 0 | 0 | 0 | 0 |

    | Table lock | 0.000009 | 0 | 0 | 0 | 0 |

    | init | 0.000026 | 0 | 0 | 0 | 0 |

    | optimizing | 0.000014 | 0 | 0 | 0 | 0 |

    | statistics | 0.000068 | 0 | 0 | 0 | 0 |

    | preparing | 0.000019 | 0 | 0 | 0 | 0 |

    | executing | 0.000004 | 0 | 0 | 0 | 0 |

    | Sorting result | 1.03614 | 0.5600349 | 0.428027 | 0 | 15632 |

    | Sending data | 0.071047 | 0 | 0.004 | 88 | 0 |

    | end | 0.000012 | 0 | 0 | 0 | 0 |

    | query end | 0.000006 | 0 | 0 | 0 | 0 |

    | freeing items | 0.000012 | 0 | 0 | 0 | 0 |

    | closing tables | 0.000007 | 0 | 0 | 0 | 0 |

    | logging slow query | 0.000003 | 0 | 0 | 0 | 0 |

    +--------------------+----------+-----------+------------+--------------+---------------+

    16 rows in set (0.00 sec)

    sky@localhost : example 10:47:40> SHOW profile CPU,BLOCK IO io FOR query 2;

    +--------------------+----------+----------+------------+--------------+---------------+

    | Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |

    +--------------------+----------+----------+------------+--------------+---------------+

    | (initialization) | 0.000087 | 0 | 0 | 0 | 0 |

    | Opening tables | 0.000018 | 0 | 0 | 0 | 0 |

    | System lock | 0.000007 | 0 | 0 | 0 | 0 |

    | Table lock | 0.000059 | 0 | 0 | 0 | 0 |

    | optimizing | 0.00001 | 0 | 0 | 0 | 0 |

    | statistics | 0.000068 | 0 | 0 | 0 | 0 |

    | preparing | 0.000017 | 0 | 0 | 0 | 0 |

    | executing | 0.000004 | 0 | 0 | 0 | 0 |

    | Sorting result | 0.928184 | 0.572035 | 0.352022 | 0 | 32 |

    | Sending data | 0.000112 | 0 | 0 | 0 | 0 |

    | init | 0.000025 | 0 | 0 | 0 | 0 |

    | optimizing | 0.000012 | 0 | 0 | 0 | 0 |

    | statistics | 0.000025 | 0 | 0 | 0 | 0 |

    | preparing | 0.000013 | 0 | 0 | 0 | 0 |

    | executing | 0.000004 | 0 | 0 | 0 | 0 |

    | Sending data | 0.000241 | 0 | 0 | 0 | 0 |

    | end | 0.000005 | 0 | 0 | 0 | 0 |

    | query end | 0.000006 | 0 | 0 | 0 | 0 |

    | freeing items | 0.000015 | 0 | 0 | 0 | 0 |

    | closing tables | 0.000004 | 0 | 0 | 0 | 0 |

    | removing tmp table | 0.000019 | 0 | 0 | 0 | 0 |

    | closing tables | 0.000005 | 0 | 0 | 0 | 0 |

    | logging slow query | 0.000004 | 0 | 0 | 0 | 0 |

    +--------------------+----------+----------+------------+--------------+---------------+

     

    我们先看看两条SQL执行中的IO消耗,两者区别就在于“Sorting result”,我们回顾一下前面执行计划的对比,两个解决方案的排序过滤数据的时机不一样,排序后需要取得的数据量一个是20000,一个是20,正好和这里的profile 信息吻合,第一种解决方案的“Sorting result”的IO 值是第二种解决方案的将近500 倍。然后再来看看CPU 消耗,所有消耗中,消耗最大的也是“Sorting result”这一项,第一个消耗多出的缘由和上面IO 消耗差异是一样的。

    结论:通过上面两条功能完全相同的SQL 语句的执行计划分析,以及通过实际执行后profile 数据的验证,都证明了第二种解决方案优于第一种解决方案。同时通过后者的实际验证,也再次证明了我们前面所做的执行计划基本决定了SQL 语句性能。

    4.Schema设计对系统的性能影响

    前面两节中,我们已经分析了在一个数据库应用系统的软环境中应用系统的架构实现和系统中与数据库交互的SQL 语句对系统性能的影响。在这一节我们再分析一下系统的数据模型设计实现对系统的性能影响,更通俗一点就是数据库的Schema 设计对系统性能的影响。

    在很多人看来,数据库Schema 设计是一件非常简单的事情,就大体按照系统设计时候的相关实体对象对应成一个一个的表格基本上就可以了。然后为了在功能上做到尽可能容易扩展,再根据数据库范式规则进行调整,做到第三范式或者第四范式,基本就算完事了。

    数据库Schema 设计真的有如上面所说的这么简单么?可以非常肯定的告诉大家,数据库Schema 设计所需要做的事情远远不止如此。如果您之前的数据库Schema 设计一直都是这么做的,那么在该设计应用于正式环境之后,很可能带来非常大的性能代价。

    由于在后面的“MySQL 数据库应用系统设计”中的“系统架构最优化“这一节中会介较为详细的从性能优化的角度来分析如何如何设计数据库Schema,所以这里暂时先不介绍如何来设计性能优异的数据库Schema 结构,仅仅通过一个实际的示例来展示Schema 结构的不一样在性能方面所带来的差异。

     

    需求概述:一个简单的讨论区系统,需要有用户,用户组,组讨论区这三部分基本功能。

    1、需要存放用户数据的表

    2、需要存放分组信息和存放用户与组关系的表

    3、需要存放讨论信息的表

     

    解决方案:

    原始方案一:分别用用四个表来存放用户,分组,用户与组关系以及各组的讨论帖子的信息如下:

    user 用户表:

    +-------------+---------------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +-------------+---------------+------+-----+---------+-------+

    | id | int(11) | NO | | 0 | |

    | nick_name | varchar(32) | NO | | NULL | |

    | password | char(64) | YES | | NULL | |

    | email | varchar(32) | NO | | NULL | |

    | status | varchar(16) | NO | | NULL | |

    | sexuality | char(1) | NO | | NULL | |

    | msn | varchar(32) | YES | | NULL | |

    | sign | varchar(64) | YES | | NULL | |

    | birthday | date | YES | | NULL | |

    | hobby | varchar(64) | YES | | NULL | |

    | location | varchar(64) | YES | | NULL | |

    | description | varchar(1024) | YES | | NULL | |

    +-------------+---------------+------+-----+---------+-------+

    groups 分组表:

    +--------------+---------------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +--------------+---------------+------+-----+---------+-------+

    | id | int(11) | NO | | NULL | |

    | gmt_create | datetime | NO | | NULL | |

    | gmt_modified | datetime | NO | | NULL | |

    | name | varchar(32) | NO | | NULL | |

    | status | varchar(16) | NO | | NULL | |

    | description | varchar(1024) | YES | | NULL | |

    +--------------+---------------+------+-----+---------+-------+

    user_group 关系表:

    +--------------+-------------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +--------------+-------------+------+-----+---------+-------+

    | user_id | int(11) | NO | MUL | NULL | |

    | group_id | int(11) | NO | MUL | NULL | |

    | user_type | int(11) | NO | | NULL | |

    | gmt_create | datetime | NO | | NULL | |

    | gmt_modified | datetime | NO | | NULL | |

    | status | varchar(16) | NO | | NULL | |

    +--------------+-------------+------+-----+---------+-------+

    group_message 讨论组帖子表:

    +--------------+--------------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +--------------+--------------+------+-----+---------+-------+

    | id | int(11) | NO | | NULL | |

    | gmt_create | datetime | NO | | NULL | |

    | gmt_modified | datetime | NO | | NULL | |

    | group_id | int(11) | NO | | NULL | |

    | user_id | int(11) | NO | | NULL | |

    | subject | varchar(128) | NO | | NULL | |

    | content | text | YES | | NULL | |

    +--------------+--------------+------+-----+---------+-------+

     

    优化后方案二:

    user 用户表:

    +-------------+---------------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +-------------+---------------+------+-----+---------+-------+

    | id | int(11) | NO | | 0 | |

    | nick_name | varchar(32) | NO | | NULL | |

    | password | char(64) | YES | | NULL | |

    | email | varchar(32) | NO | | NULL | |

    | status | varchar(16) | NO | | NULL | |

    +-------------+---------------+------+-----+---------+-------+

    user_profile 用户属性表(记录与user 一一对应):

    +-------------+---------------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +-------------+---------------+------+-----+---------+-------+

    | sexuality | char(1) | NO | | NULL | |

    | msn | varchar(32) | YES | | NULL | |

    | sign | varchar(64) | YES | | NULL | |

    | birthday | date | YES | | NULL | |

    | hobby | varchar(64) | YES | | NULL | |

    | location | varchar(64) | YES | | NULL | |

    | description | varchar(1024) | YES | | NULL | |

    +-------------+---------------+------+-----+---------+-------+

    groups user_group 这两个表和方案一完全一样

    group_message 讨论组帖子表:

    +--------------+--------------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +--------------+--------------+------+-----+---------+-------+

    | id | int(11) | NO | | NULL | |

    | gmt_create | datetime | NO | | NULL | |

    | gmt_modified | datetime | NO | | NULL | |

    | group_id | int(11) | NO | | NULL | |

    | user_id | int(11) | NO | | NULL | |

    | author | varchar(32) | NO | | NULL | |

    | subject | varchar(128) | NO | | NULL | |

    +--------------+--------------+------+-----+---------+-------+

    group_message_content 帖子内容表(记录与group_message 一一对应):

    +--------------+---------+------+-----+---------+-------+

    | Field | Type | Null | Key | Default | Extra |

    +--------------+---------+------+-----+---------+-------+

    | group_msg_id | int(11) | NO | | NULL | |

    | content | text | NO | | NULL | |

    +--------------+---------+------+-----+---------+-------+

     

    我们先来比较一下两个解决方案所设计的Schema 的区别。区别主要体现在两点,一个区别是在group_message 表中增加了author 字段来存放发帖作者的昵称,与user 表的nick_name 相对应,另外一个就是第二个解决方案将user 表和group_message 表都分拆成了两个表,关系分别都是一一对应。

    方案二看上去比方案一要更复杂一些,首先是表的数量多了2 个,然后是在group_message 中冗余存放了作者昵称。我们试想一下,一个讨论区系统,访问最多的页面会是什么?我想大家都会很清楚是帖子标题列表页面。而帖子标题列表页面最主要的信息就是都是来自group_message 表中,同时帖子标题后面的作者一般都是通过用户名成(昵称)来展示。按照第一种解决方案来设计的Schema,我们就需要执行类似如下这样的SQL 语句来得到数据:

    SELECT t.id, t.subject,user.id, u.nick_name

    FROM (

    SELECT id, user_id, subject

    FROM group_message

    WHERE group_id = ?

    ORDER BY gmt_modified DESC LIMIT 20

    ) t, user u

    WHERE t.user_id = u.id

     

    但是第二中解决方案所需要执行的SQL 就会简单很多,如下:

    SELECT t.id, t.subject, t.user_id, t.author

    FROM group_message

    WHERE group_id = ?

    ORDER BY gmt_modified DESC LIMIT 20

     

    两个SQL 相比较,大家都能很明显的看出谁优谁劣了,第一个是需要读取两个表的数据进行Join,与第二个SQL 相比性能差距很大,尤其是如果第一个再写的差一点,性能更是非常糟糕,两者所带来的资源消耗就更相差悬殊了。

    不仅仅如此,由于第一个方案中的group_message 表中还包含一个大字段“content”,该字段所存放的信息要占整个表的绝大部分存储空间,但在这条系统中执行最频繁的SQL 之一中是完全不需要该字段所存放信息的,但是由于这个SQL 又没办法做到不访问group_message 表的数据,所以第一条SQL 在数据读取过程中会需要读取大量没有任何意义的数据。

    在系统中用户数据的读取也是比较频繁的,但是大多数地方所需要的用户数据都只是用户的几个基本属性,如用户的id,昵称,密码,状态,邮箱等,所以将用户表的这几个属性单独分离出来后,也会让大量的SQL 语句在运行的时候减少数据的检索量,从而提高性能。

    可能有人会觉得,在我们将一个表分成两个表的时候,我们如果要访问被分拆出去的信息的时候,性能不是就会变差了吗?是的,对于那些需要访问如user signmsn 等原来只需要一个表就可以完成的SQL 来说,现在都需要两条SQL 来完成,性能确实会有所降低,但是由于两个表都是一对一的关联关系,关联字段的过滤性也非常高,而且这样的查询需求在整个系统中所占有的比例也并不高,所以这里所带来的性能损失实际上要远远小于在其他SQL 上所节省出来的资源,所以完全不必为此担心。

    5.硬件环境对系统性能的影响

    之前的所有部分都是介绍整个系统中的软件环境对系统性能的影响,这一节我们将从系统环境来分析对数据库系统的影响,并从数据库服务器主机的角度来做一些针对性的优化建议。

    任何一个系统的硬件环境都会对起性能起到非常关键的作用,这一点我想每一位读者朋友都是非常清楚的。而数据库应用系统环境中,由于数据库自身的特点和在系统中的角色决定了他在整个系统中是最难以扩展的部分。所以在大多数环境下,数据库服务器主机(或者主机集群)的性能在很大程度上决定了整个应用系统的性能。

    既然我们的数据库主机资源如此重要,肯定很多读者朋友会希望知道,数据库服务器主机的各部分硬件到底谁最重要,各部分对整体性能的影响各自所占的比例是多少,以便能够根据这些比例选取合适的主机机型作为数据库主机。但是我只能很遗憾的告诉大家,没有任何一个定律或者法则可以很准确的给出这个答案。

    当然,大家也不必太沮丧。虽然没有哪个法则可以准确的知道我们到底该如何选配一个主机的各部分硬件,但是根据应用类型的不同,总体上还是有一个可以大致遵循的原则可以参考的。

    首先,数据库主机是存取数据的地方,那么其IO 操作自然不会少,所以数据库主机的IO 性能肯定是需要最优先考虑的一个因素,这一点不管是什么类型的数据库应用都是适用的。不过,这里的IO 性能并不仅仅只是指物理的磁盘IO,而是主机的整体IO 性能,是主机整个IO 系统的总体IO 性能。而IO 性能本身又可以分为两类,一类是每秒可提供的IO 访问次数,也就是我们常说的IOPS 数量,还有一种就是每秒的IO 总流量,也就是我们常说的IO 吞吐量。在主机中决定IO 性能部件主要由磁盘和内存所决定,当然也包括各种与IO 相关的板卡。

    其次,由于数据库主机和普通的应用程序服务器相比,资源要相对集中很多,单台主机上所需要进行的计算量自然也就比较多,所以数据库主机的CPU 处理能力也不能忽视。

    最后,由于数据库负责数据的存储,与各应用程序的交互中传递的数据量比其他各类服务器都要多,所以数据库主机的网络设备的性能也可能会成为系统的瓶颈。

    由于上面这三类部件是影响数据库主机性能的最主要因素,其他部件成为性能瓶颈的几率要小很多,所以后面我们通过对各种类型的应用做一个简单的分析,再针对性的给出这三类部件的基本选型建议。

     

    一、典型OLTP 应用系统

    对于各种数据库系统环境中大家最常见的OLTP 系统,其特点是并发量大,整体数据量比较多,但每次访问的数据比较少,且访问的数据比较离散,活跃数据占总体数据的比例不是太大。对于这类系统的数据库实际上是最难维护,最难以优化的,对主机整体性能要求也是最高的。因为他不仅访问量很高,数据量也不小。

    针对上面的这些特点和分析,我们可以对OLTP 的得出一个大致的方向。

    虽然系统总体数据量较大,但是系统活跃数据在数据总量中所占的比例不大,那么我们可以通过扩大内存容量来尽可能多的将活跃数据cache 到内存中;

    虽然IO 访问非常频繁,但是每次访问的数据量较少且很离散,那么我们对磁盘存储的要求是IOPS 表现要很好,吞吐量是次要因素;

    并发量很高,CPU 每秒所要处理的请求自然也就很多,所以CPU 处理能力需要比较强劲;

    虽然与客户端的每次交互的数据量并不是特别大,但是网络交互非常频繁,所以主机与客户端交互的网络设备对流量能力也要求不能太弱。

     

    二、典型OLAP 应用系统

    用于数据分析的OLAP 系统的主要特点就是数据量非常大,并发访问不多,但每次访问所需要检索的数据量都比较多,而且数据访问相对较为集中,没有太明显的活跃数据概念。

    基于OLAP 系统的各种特点和相应的分析,针对OLAP 系统硬件优化的大致策略如下:

    数据量非常大,所以磁盘存储系统的单位容量需要尽量大一些;

    单次访问数据量较大,而且访问数据比较集中,那么对IO 系统的性能要求是需要有尽可能大的每秒IO 吞吐量,所以应该选用每秒吞吐量尽可能大的磁盘;

    虽然IO 性能要求也比较高,但是并发请求较少,所以CPU 处理能力较难成为性能瓶颈,所以CPU 处理能力没有太苛刻的要求;

    虽然每次请求的访问量很大,但是执行过程中的数据大都不会返回给客户端,最终返回给客户端的数据量都较小,所以和客户端交互的网络设备要求并不是太高;

    此外,由于OLAP 系统由于其每次运算过程较长,可以很好的并行化,所以一般的OLAP 系统都是由多台主机构成的一个集群,而集群中主机与主机之间的数据交互量一般来说都是非常大的,所以在集群中主机之间的网络设备要求很高。

     

    三、除了以上两个典型应用之外,还有一类比较特殊的应用系统,他们的数据量不是特别大,但是访问请求及其频繁,而且大部分是读请求。可能每秒需要提供上万甚至几万次请求,每次请求都非常简单,可能大部分都只有一条或者几条比较小的记录返回,就比如基于数据库的DNS 服务就是这样类型的服务。

    虽然数据量小,但是访问极其频繁,所以可以通过较大的内存来cache 住大部分的数据,这能够保证非常高的命中率,磁盘IO 量比较小,所以磁盘也不需要特别高性能的;

    并发请求非常频繁,比需要较强的CPU 处理能力才能处理;

    虽然应用与数据库交互量非常大,但是每次交互数据较少,总体流量虽然也会较大,但是一般来说普通的千兆网卡已经足够了。

    在很多人看来,性能的根本决定因素是硬件性能的好坏。但实际上,硬件性能只能在某些阶段对系统性能产生根本性影响。当我们的CPU 处理能力足够的多,IO 系统的处理能力足够强的时候,如果我们的应用架构和业务实现不够优化,一个本来很简单的实现非得绕很多个弯子来回交互多次,那再强的硬件也没有用,因为来回的交互总是需要消耗时间。尤其是有些业务逻辑设计不是特别合理的应用,数据库Schema 设计的不够合理,一个任务在系统中又被分拆成很多个步骤,每个步骤都使用了非常复杂的Query 语句。笔者曾经就遇到过这样一个系统,该系统是购买的某知名厂商的一个项目管理软件。该系统最初运行在一台Dell2950 PC Server 上面,使用者一直抱怨系统响应很慢,但我从服务器上面的状态来看系统并繁忙(系统并发不是太大)。后来使用者强烈要求通过更换硬件设施来提升系统性能,虽然我一直反对,但最后在管理层的要求下,更换成了一台Sun S880 小型机,主机CPU 的处理能力至少是原来机器的3 倍以上,存储系统也从原来使用本地磁盘换成使用EMC 的中断存储CX300。可在试用阶段,发现系统整体性能没有任何的提升,最终还是取消了更换硬件的计划。

    所以,在应用系统的硬件配置方面,我们应该要以一个理性的眼光来看待,只有合适的才是最好的。并不是说硬件资源越好,系统性能就一定会越好。而且,硬件系统本身总是有一个扩展极限的,如果我们一味的希望通过升级硬件性能来解决系统的性能问题,那么总有一天将会遇到无法逾越的瓶颈。到那时候,就算有再多的钱去砸也无济于事了。

     

    6.Schema设计对系统的性能影响

    虽然本章是以影响MySQL Server 性能的相关因素来展开分析,但实际上很多内容都对于大多数数据库应用系统适用。数据库管理软件仅仅是实现了数据库应用系统中的数据存取操作,和数据的持久化。

    数据库应用系统的优化真正能带来最大收益的就是商业需求和系统架构及业务实现的优化,然后是数据库Schema 设计的优化,然后才是Query 语句的优化,最后才是数据库管理软件自身的一些优化。通过笔者的经验,在整个系统的性能优化中,如果按照百分比来划分上面几个层面的优化带来的性能收益,可以得出大概如下的数据:

    需求和架构及业务实现优化:55%

    Query 语句的优化:30%

    数据库自身的优化:15%

    很多时候,大家看到数据库应用系统中性能瓶颈出现在数据库方面,就希望通过数据库的优化来解决问题,但不管DBA 对数据库多们了解,对Query 语句的优化多么精通,最终还是很难解决整个系统的性能问题。原因就在于并没有真正找到根本的症结所在。

    所以,数据库应用系统的优化,实际上是一个需要多方面配合,多方面优化的才能产生根本性改善的事情。简单来说,可以通过下面三句话来简单的概括数据库应用系统的性能优化:商业需求合理化,系统架构最优化,逻辑实现精简化,硬件设施理性化。

    展开全文
  • 影响项目进度的软因素分析

    万次阅读 2010-06-30 15:18:00
     由于制定进度计划的工具主要是甘特图和网络图(包括cpm/ pert ,关键路径法和计划评审技术) ,所以很多人一想到进度管理就是绘制甘特图或网络图,而对其他影响项目进度的因素反而忽视了。许多项目经理出现了不学...
  • 影响滤波器实现结构的三大因素

    千次阅读 2011-08-08 18:25:49
    影响滤波器实现结构的三大因素    在对数字信号进行滤波时,在根据信号的特性计算出滤波器系数之后,还要考虑用何种结构来实现所设计的滤波器。通常,人们往往更注重滤波器系数的求解,而经常忽略滤波器的实现...
  • 构建全要素能源效率演进的面板数据模型,运用1993~2014年面板数据模型,采用DEA模型测算国家全要素能源效率,对其与影响因素之间的关系进行面板协整检验和估计,计算各影响因素对全要素能源效率增长率的贡献率。...
  • 对城市旅游效率及其影响因素分析有助于旅游业资源投入组合的优化和利用能力的提高。采用DEA方法,利用河南省18个地市2012—2014年的旅游产业面板数据,对旅游资源利用的综合效率、技术效率、规模效率和规模收益进行...
  • 影响封装的最大因素是封装的效率,也就是硅片面积与封装引脚面积之比。某些插针网格阵列(PGA)的效率不足10%;某些焊球阵列(BGA)的效率能达到20%;芯片规模封装(CSP)的效率在80%以上;而多芯片模块(MCM或系统封装...
  • 设计中,对于布通率的的提高有一套完整的方法... 多年来,人们总是认为电路层数越少成本就越低,但是影响电路的制造成本还有许多其它因素。近几年来,多层之间的成本差别已经大大减小。在开始设计时采用较多的电
  • 一、组织系统对项目的影响 1.1 组织治理与项目治理 1.2 组织结构形式 I 职能式组织(直线式组织) II 矩阵式组织 III 项目式组织 IV 复合型组织、项目联络员与项目协调员 1.3 管理要素 1.4 项目管理办公室PMO 二、...
  • 为了提高采空区的充填效率,需要对影响充填装置充填效率的各种因素进行分析研究。在干式充填气力输送实验中,通过改变影响节流孔特性的结构参数,包括开孔形式和开孔面积,研究其对采空区充填效率影响。研究结果为...
  • 无线通信距离的主要性能指标有四个: 一是发射机的射频输出功率; 二是接收机的接收灵敏度, ...三是系统的抗干扰能力;...兼容性标准(如北美的FCC、欧洲的EN规范)均只限制发射 ...一、影响无线通信
  • 针对传统三防漆工艺受技术因素及环境因素影响存在可控度不高、涂覆一致性差等问题,提出了一种改进的矿用PCB组件三防漆涂覆工艺;介绍了三防漆涂覆方式和材料的选择,研究了矿用PCB组件三防漆涂覆工艺方法和内容。...
  • 首先,通过一组六因素五水平的正交试验得出每一因子对收尘效率影响,并且初步得出每一因子在其不同的作用水平下收尘效率变化的规律性,其次,再进行单因素试验,以验证收尘效率随每个因素单独变化时的规律性,最后依据...
  • OEE(设备综合效率)

    千次阅读 2018-12-05 19:08:52
    国际上对OEE的定义为:OEE是(全局设备效率)的英文缩写。OEE是一个独立的测量工具,它用来表现实际的生产能力相对于理论产能的比率。 设备综合效率OEE是由可用率,表现性以及质量指数三个关键要素组成。 设备OEE= ...
  • 结合实验对集成涡流系统进行分析,得到分离孔尺寸、热端管长 度、喷嘴结构以及入口压力、 冷流比等因素对涡流能量分离效果和 效率影响 。研究结果表明 :入口压力在 0.4 5 MPa、冷流比在0.7~0 .8、冷端孔...
  • 通过溶解态铝絮体聚合度、 pH值变化等指标的检测分析,阐明这些影响因素对电絮凝效率的作用机制.结果表明,电流密度为13 mA/cm2、初始pH值在中性或弱碱性范围时,反应60 min后,Ni2+去除率可达99%以上;废水中的Ca...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 52,701
精华内容 21,080
关键字:

影响板换效率的因素