实战分享|Write Cache设置效果为何有差异?

简介: sdparm和hdparm去修改HDD的write cache,发现在系统下write cache设置的效果有差异。

Write Cache这个概念对于大家应该不陌生,主要是机械HDD中会有很明显的效果。

  • Write Cache Enable,WCE:数据不会直接落盘,而是写入DRAM缓存后就直接返回了,对于随机写和顺序写的性能都会有所改善。这个场景,对于数据保护的要求可能存在一定的风险,如果数据在cache中还未刷入落盘,掉电数据也会丢失
  • Write Cache Disable,WCD:数据需要完全落入碟片后才算写入成功,性能会有下降,但是数据安全是可靠的,即使断电,数据可以保证落盘。

小编曾经在研究HBA-Expander-HDD架构性能相关问题时遇到过一个有趣的现象,在linux系统下用两个工具:sdparm和hdparm去修改HDD的write cache,发现在系统下write cache设置的效果有差异

按照官网(https://wiki.archlinux.org/title/Hdparm)的定义,两个工具都是针对sata/sas盘进行参数读取的工具,而且相辅相成,是对好兄弟,为何在设置write cache过程表现的不一样呢?这个就是本文主要的趣事分解。

首先,我们先来看hdparm修改write cache的方式和原理。

查看write cache的状态:hdparm -W /dev/sdX

打开write cache:hdparm -W 1 /dev/sdX

关闭write cache:hdparm -W 0 /dev/sdX

hdparm源码中设置write cache的代码:


/* prototypes and stuff for ATA command ioctls */#include <linux/types.h>enum {  ...  ATA_OP_SETFEATURES    = 0xef,  ...};




if (set_wcache) {    if (get_wcache) {      printf(" setting drive write-caching to %d", wcache);      on_off(wcache);    }    if (!wcache)      err = flush_wcache(fd);    if (ioctl(fd, HDIO_SET_WCACHE, wcache)) {      __u8 setcache[4] = {ATA_OP_SETFEATURES,0,0,0}; #通过ATA set feature命令完成设置      setcache[2] = wcache ? 0x02 : 0x82;      if (do_drive_cmd(fd, setcache, 0)) {        err = errno;        perror(" HDIO_DRIVE_CMD(setcache) failed");      }    }    if (!wcache)      err = flush_wcache(fd);  }


基于上面的代码,我们也可以看到hdparm通过kernel libata ATA set feature命令完成设置与硬盘完成交互,最终完成write cache的设置。

那么,sdparm又是怎么修改WCE的呢?

打开write cache:sdparm --set=WCE --save /dev/sdX

关闭write cache:sdparm--clear=WCE --save /dev/sdX

sdparm源码中设置write cache的代码:


for (k = 0; k < num_devices; ++k) {        r = 0;        pdt = -1;        if (op->verbose > 1)            pr2serr(">>> about to open device name: %s\n",                    device_name_arr[k]);        sg_fd = open_and_simple_inquiry(device_name_arr[k], rw, &pdt,                                        &protect, op);        if (sg_fd < 0) {            if (0 == ret)                ret = -sg_fd;            continue;        }

       if (op->inquiry) {            if (op->examine)                r = examine_vpd_page(sg_fd, pn, spn, op, req_pdt, protect);            else                r = sdp_process_vpd_page(sg_fd, pn, ((spn < 0) ? 0: spn), op,                                         req_pdt, protect, NULL, 0, NULL, 0);        } else {            if (cmd_str && scmdp)   /* process command */                r = sdp_process_cmd(sg_fd, scmdp, cmd_arg, pdt, op);            else {                  /* mode page */                if (op->examine)                    r = examine_mode_page(sg_fd, pn, op, req_pdt);

               else                    r = process_mode_page(sg_fd, &mp_settings, pn, spn,                                          set_clear, (NULL != get_str), op,                                          pdt);            }}


基于上面的代码,我们也可以看到sdparm基于SCSI协议交互,通过SCSI mode pages, 实现write cache设置。

通过上面代码,我们可以看到hdparm和sdparm命令走的通道不完全一样,结合linux storage stack看可能会更加容易对比理解:

  • hdparm走的是libata的通道。也就是在HBA+Expander的架构中,在系统通过hdparm修改write cache时,HBA和expander都不会感知write cache的设置,设置write cache的命令会直接透传HDD
  • sdparm走的是SCSI+mpt3sas驱动的通道。当系统需要修改write cache时,会先经过SATL转换层翻译成ATA命令,这时HBA和expander都会感知write cache的设置


相关文章
|
3月前
|
存储 缓存 算法
内存系列学习(四):Cache和Write Buffer一般性介绍
内存系列学习(四):Cache和Write Buffer一般性介绍
141 0
|
内存技术
mode:类型非常多 r:只读 从头部开始读 io.UnsupportedOperation: not writable w:写入 每次都是从头部开始写 原有的内容
mode:类型非常多 r:只读 从头部开始读 io.UnsupportedOperation: not writable w:写入 每次都是从头部开始写 原有的内容
|
机器学习/深度学习 Linux 芯片
Cache Line 伪共享发现与优化
作者:吴一昊,杨勇 ### 1. 关于本文 ### 本文基于 Joe Mario 的[一篇博客](https://joemario.github.io/blog/2016/09/01/c2c-blog/) 改编而成。
5689 1
|
存储 算法 数据库