常见的磁盘I/O和网络I/O优化技巧

房东的猫 提交于 2021-01-09 09:01:09

磁盘I/O 优化

性能检测

应用程序通过访问磁盘来读取数据,而磁盘I/O 通常都是很耗时间的,所以一般我们来判断I/O是否有瓶颈的时候,就需要一些参数指标来参考。

  • WAIT 指标 :
    压测应用程序,查看系统I/O wait 指标是否正常,如果测试机器有4个CPU ,那么理想的I/O wait 参数不应该超过25% ,如果超过了25% ,那么就很可能成为程序的性能瓶颈,在Linux 下,可以通过iostat 命令查看。
  • IOPS(每秒读取次数) : 
    查看应用程序最低要求的IOPS 是多少,磁盘的IOPS 能不能达到要求。 每个磁盘的IOPS通常都在一定的范围内,当然这个和存储在磁盘上的数据块大小和访问方式相关。但主要是由磁盘的转速决定的。转速越高,则磁盘IOPS 越高。

提升I/O性能

通常提升I/O性能的方法有:

  • 增加缓存,减少磁盘访问次数。
  • 优化磁盘管理系统,设计最优磁盘方式策略,和磁盘的寻址策略,这是从底层操作系统层面的考虑。
  • 设计合理的磁盘存储数据块,以及访问的策略。这是从应用层方面考虑的,比如给存放的数据加索引,通过寻址索引来加快和减少磁盘的访问量,以及异步和非阻塞的方式来加快磁盘访问速度。
  • 当然我们现在通常采用一种叫做 RAID(磁盘阵列)的技术。  就是将不同的磁盘组合起来以提高I/O性能,现在有多种RAID 技术,每种RAID 技术对I/O性能的提升也不同。 可以用一个RAID 因子来代表, 通过磁盘的读写吞吐量 可以通过iostat 命令来获取,所以就可以计算出理论的IOPS 值 。 公式可以写作:                
(磁盘数 * 每块磁盘的IOPS)/(磁盘的吞吐量 + RAID因子 * 磁盘读写的吞吐量)=IOPS 
  这个公式的详情请自行百度。

  RAID 策略 以及说明 

磁盘阵列             说明 
RAID 0   数据被平均写到多个磁盘阵列中,写和读数据都是平行的,所以磁盘的IOPS可以提升一倍
RAID 1

 RAID 1 的主要作用是能够提高数据的安全性,它将一份数据分别复制到多个磁盘阵列中,并不能

提升IOPS ,但是相同的数据有多个备份。通常用于对数据安全性较高的场合中。

RAID 5   这种设计方式是前两种的折中方式,它将信息平均写到所有磁盘阵列总数减一的磁盘中,往另外
一个磁盘写入这份数据的奇偶检验信息。如果其中有一个磁盘损坏,就可以通过其他磁盘的数据和
这个数据的奇偶检验信息来恢复这份数据。
RAID 0+1 就如名字一样,根据数据的备份情况进行分组,一份数据同时写到多个备份磁盘中,同时多个磁盘也会进行读写。

 TCP网络参数调优

我们知道要建立一个TCP连接,就必须要知道对方的IP 和一个未被使用的端口号,由于32位操作系统的端口号通常是由两个字节表示,所以就只有2^65535个端口号。所以说,一台主机能够建立的连接是有限的。还有 0~1024 端口是受保护的,像80,22,21 这些端口都不是能够被随意占用的。

在Linux 中 我们通过查看  /proc/sys/net/ipv4/ip_local_port_range 文件来查看当前能够使用的端口范围, 如果可分配的端口较少,在遇到大量的并发请求的时候就会成为瓶颈。由于端口有限导致大量的请求等待连接,这样性能就会压不上去。 另外 如果发现有大量的TIME_WAIT 的话,可以设置  /proc/sys/nettcp_fin_timeout 为更小的值来快速释放请求。

网络参数            说明   
echo "1024 65535">/proc/sys/net/ipv4/ip_local_port_rang  设置向外连接可用端口范围        
echo 1 >/proc/sys/net/ipv4/tcp_tw_reuse  设置  time_wait  连接重用
echo 1 >/proc/sys/net/ipv4/tcp_tw_recycle  设置快速回收  time_wait  连接
echo 180000 >/proc/sys/net/ipv4/tcp_max_tw_buckets  设置最大time_wait 连接长度
echo 0 > /proc/sys/net/ipv4/tcp_timestamps   表示是否启用以一种比超时重发更精确的方法来启用对RTT的计算
echo 1>/proc/sys/net/ipv4/tcp_window_scaling   设置TCP/IP会话的滑动窗口大小是否可变 
echo 20000 >/proc/sys/net/ipv4/tcp_max_syn_backlog  设置最大等待处于客户端还没有应答回来的连接数
echo 10000 >/proc/sys/net/core/somaxconn  设置每一个处于监听状态的端口监听队列的长度
echo 10000 > /proc/sys/net/core/netdev_max_backlog  设置最大等待CPU处理的包的数目
echo 2000000>/proc/sys/fs/file-max  设置最大打开文件数
echo 15>/proc/sys/net/ipv4/tcp_fin_timeout  设置FIN-WAIT-2状态等待回收时间

echo 16777216 >/proc/sys/net/core/rmem_max

 设置最大的系统套接字数据接收缓冲大小
echo 262144 > /proc/sys/net/core/rmem_default   设置默认的系统套接字数据接收缓冲大小
echo 16777216 >/proc/sys/net/core/wmen_max   设置最大的系统套接字数据发送缓冲大小
echo 262144 >/proc/sys/net/core/wmen_default  设置默认的系统套接字数据发送缓冲大小
echo "4096 87380 16777216" > /proc/sys/net/ipv4/tcp_rmem  设置最大的TCP 数据发送缓冲大小,三个值分别是 最小,默认,和最大值
echo "4096 65535 16777216"/proc/sys/net/ipv4/tcp_wmem  设置默认的TCP数据接收缓冲大小,三个值分别是 最小,默认,和最大值

 调优参数

 

以上的设置都是临时的,系统重启之后会自动丢失, Linux 还提供其他查看当前TCP 统计的信息

  • cat/proc/net/netstat  : 查看TCP的统计信息。
  • cat/proc/net/snmp : 查看当前系统的连接情况。
  • netstat -s : 查看网络的统计信息。

网络I/O优化

网络I/O 优化的基本处理原则。

  • 减少网络交互的次数。    要减少网络交互的次数,通常需要在网络交互的两端设置缓存。像Orcle的jdbc驱动程序就提供了对查询的SQL结果的缓存,在客户端和数据库端都有,可有效的减少对数据库的访问。 还有个方法,就是合并访问请求。将多个请求合并到一个包中,后面再打包返回。 比如访问页面时,通常会有多个JS或CSS 文件,我们可以将多个JS 文件合并在一个HTTP链接中,每个文件用逗号隔开,然后发送到后端的Web服务器,根据这个URL链接再拆分为各个文件,最后打包一并返回给前端浏览器。       这些都是减少网络I/O的方法。
  • 减少网络传输数据量的大小。 通常是将数据压缩后再传输,以及通过设计简单的协议,尽量通过读取协议头来获取有用的价值信息
  • 尽量减少编码。在网络I/O中,数据传输都是以字节形式进行的,所以通常要进行序列化。但是我们发送到数据都是以字符形式的,所以必须要经过编码,这个过程是非常耗时的。所以在要经过网络I/O传输时,尽量以字节形式发送,提前将字符转化为字节。减少传输过程中,从字符到字节的转化过程。

交互场景

  同步与异步

   同步:

     同步的思想是:所有的操作都做完,才返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的感觉)。这种情况下,用户不能关闭界面,如果关闭了,即迁移程序就中断了。 同步是一种很可靠的任务序列,要么都成功,要么都失败。

   异步:

    将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。但是用户没有卡死的感觉,会告诉你,你的请求系统已经响应了。你可以关闭界面了。 异步 是一种不可靠的任务序列。

 阻塞与非阻塞

  阻塞与非阻塞主要是从CPU的消耗上来说的,阻塞就是CPU停下来等待一个慢的操作完成以后,CPU 才接着完成其他工作。 非阻塞就是在这个慢的操作执行时,CPU去做其他地方工作,等这个操作完成时CPU再接着完成后续操作。  虽然从表面上看,非阻塞的方式可以明显的提高CPU的利用率,但是也带来另一种结果,就是系统的线程切换增加。增加的CPU 使用时间能不能补偿系统的切换成本就需要好好的评估。 

两种方式的组合

组合的方式有四种,分别是同步阻塞,同步非阻塞,异步阻塞,异步非阻塞,四种方式都对I/O性能有影响。

组合方式 性能分析
同步阻塞 最常用的一种用法,使用也是最简单的,但是I/O性能一般很差,CPU 大部分处于空闲状态
同步非阻塞 提升I/O性能的常用手段,就是将I/O阻塞改成非阻塞的方式,尤其是在网络I/O是长连接同时传输数据也不是很多
的情况下,提升性能非常有效。
这种方式通常能提升I/O性能,但是会增加CPU 消耗,要考虑增加的I/O性能能不能补偿CPU 的消耗,也就是系统
的瓶颈是在CPU上还是I/O上。
异步阻塞

这种方式在分布式数据库上经常用到,比如,在一个分布式数据库中写一条记录,通常会有一份是同步阻塞的的记录
,还有2~3份备份记录会写到其他机器上,这些备份记录通常都采用异步阻塞的方式写I/O 

  异步阻塞对网络 I/O 能够提升效率,尤其是像上面说的,能够同时写多份相同的数据的情况。

异步非阻塞 这种组合方式用起来比较复杂,只有在一些非常复杂的分布式情况下使用,集群之间的消息同步机制一般都采用这种
I/O 组合形式,
它适合同时要传很多份相同的数据到集群中不同的机器。同时数据的传输量虽然不大,却非常繁琐的情况,这种网络
I/O用这种方式性能能达到最高。

 四种组合方式以及性能分析

虽然异步和非阻塞能够提升I/O 的性能,但是也会带来一些额外的性能成本,比如:会增加线程数量从而增加CPU的消耗,同时也会导致程序设计复杂度的上升。如果设计得不好,反而会导致性能下降。所以在实际应用时要根据应用场景综合评估。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!