September 2010 Archives

对齐操作和非对齐操作

| 1 Comment | No TrackBacks

操作是否对齐是一个简单而容易忽略的性能(有时是可靠性)问题。对齐主要是指读写操作不产生不必要地跨越存储设备上原生存储单元的访问,这里的存储单元说的是在访问路径上的任何设备,它可以是外存,也可以是内存,甚至是CPU附近或内建的快取缓存,等等。

在C/C++中,对于内存的访问多数是在编译时可以预测的。一般来说编译器会在编译过程中自动对数据结构进行补足(除非由于某种需要而指定了__packed),并对可能产生这类问题的冒险行为,例如将一个较短的数据类型的指针cast成一个较长数据类型的指针进行警告。因此,在希望有较高性能的硬件平台上,不对齐的内存字操作往往会导致硬件异常(Alpha、IA64、SPARC64等)。但是对于便宜的PC硬件(x86和amd64)来说,为了保证和先前硬件的兼容性,它们往往会选择默默承受这样的问题,并在CPU的microcode中将这类操作转换成两次读操作。

通过仔细地编写C代码,可以在某些情况下减少非对齐或比字长短的操作,许多C的字符串处理函数都可采用这种方法。例如,在实现 strlen(3) 函数时,可以采取下面的策略:

  1. 将指针ptr向前取整到整字边界bp;
  2. 判断bp开始的字中是否有纯0的字节,如果有,则从ptr开始扫描到bp所指下一字前的每个字节,若找到则返回值;
  3. 从bp下一字开始,均先判断整个字中是否有纯0字节;如果没有,直接访问下一个字。

上面只是关于 strlen(3) 采用的技巧的粗略介绍。当然,由于好的程序绝对不会将 strlen(3) 放在关键路径上,因此这个改进的现实意义并不太大。实际测试中,这个改进版本的 strlen(3) 平均比按字节比较的版本快5.2倍,而对非常短的字符串则只有最多16%左右的性能损失。

对于外围设备的操作对齐相对来说更复杂一些。例如,采用4k扇区的硬盘,或者采用RAID的磁盘阵列,其固件需要将写操作拆成和物理扇区或stripe同样的大小,将数据读出,然后再重写。这个过程比较耗时(实际测试显示,在 WD AV25 硬盘上,对齐的4k写操作和未对齐的4k写操作的IOPS可相差达60倍),对于RAID,如RAID5的情形,还可能进一步引发一致性问题。

要避免这类问题,唯一的办法是对存储格式进行合理的规划。例如,采用的记录尺寸应为块尺寸的整数倍(对于多数 Unix 文件系统来说这并不是问题),或采用日志的方式将写操作收集起来先行写入整个存储块,然后在提交阶段将写操作凑成整块来做。

不过需要注意的是,操作系统的存储驱动必须能够告诉文件系统如何对齐。FreeBSD中,这是通过g_provider对象的stripesize和stripeoffset属性来暴露给文件系统的。如果操作系统本身没有提供对齐支持,在分区时强制分区以整物理扇区,而不是整逻辑磁道(17个512 byte扇区)的位置开始,也可以在一定程度上缓解这个问题。

关于备份

| 2 Comments | No TrackBacks

指望硬盘不挂掉是 很拼人品的事情(附带说一句,从某种意义上说,21世纪的硬盘质量并没有下降,只是单位容量出现故障的概率没有显著提高,而硬盘容量的扩大使得单块硬盘的故障率看起来提高了,但是如果我们从单位容量的故障率来看,坏损率并没有非常显著的增长)。所以想要长久地保存数据,就必须采用各式各样的冗余和备份手段。冗余和备份是不一样的,前者往往会采用同样的访问控制逻辑,提供在线或近线的数据存储,强调的是数据访问的及时性;而后者则强调的是数据的可恢复性。

关于访问控制

一般来说,不希望备份与原始数据采取相同的访问控制机制。例如,对网站来说,可以读写数据库的那个 Web 访客的数据库账户,很可能并不能直接读写网站的备份数据。有时,备份甚至是以一种"外科手术"的方式进行的:对文件系统做快照,然后将快照打包发到异地的另一套系统。

采取不同的访问控制机制有很多好处。备份的目的之一是保护先前版本的数据不受影响。举个现实生活中的例子,公司的账簿可能会影印之后放到档案寄存机构,而公司会计可能并不负责,甚至没有权限去调出账簿副本。在这个例子中,由于副本和正本由两个角色分别负责,为确保其不被其中任何一个人恶意篡改提供了一定的保障。

对于服务器或桌面系统,这种控制也同样重要。例如,用户可能有权限删除自己的文件,但不应有权限以同样的方式删除或修改备份。这种限制可以缓解由于误操作或入侵(例如木马、或特权提升)导致的损失。这一点是备份与冗余之间的重要区别。

推 or 拉?

两种方式各有利弊,但我个人比较倾向于使用拉(即备份机登录原始数据的机器)的方式而不是推的方式。原因是备份机往往可以设置更为严厉的安全策略,例如放在防火墙后面,等等,而攻击者在入侵成功之后,想要找到备份机在什么地方也需要一些时间,从而给检测入侵创造条件。推的方式的优点是可以比较方便地控制何时备份,以及备份的I/O占的比例,不过,通过合理地设计备份系统,并不是拉的方式并不是完全不能实现这类功能。

关于异地备份

将备份与原始数据放在同一个物理位置(例如同一个机房、同一棟建筑、同一座城市,甚至同一个省或同一个国家/大洲)很可能是有风险的。一般来说,副本与原始数据的距离越远,从备份的可靠性角度考虑便越有把握,同时,将备份设在电费和托管费用较低的二三线城市,也可以在一定程度上降低整个系统的运营成本。

离线备份

离线备份往往用于保存非常有价值并且不经常改变的数据。例如将数据刻录成光盘邮寄给不同大洲的人,等等。不过,离线备份的问题是其访问控制很可能不太容易,想要解决这个问题,可以采用门限加密的方法(例如,将数据分成三份,密钥也分成三份,给三个备份点分别发第其中的1,2;1,3;2,3,在这个方案中,攻击者必须掌握三份备份中的至少两份才能够恢复密文内容)对数据进行处理。

出现钓支付宝鱼的网站了

| 11 Comments | No TrackBacks

今天看到一则消息说,百度搜索支付宝会找到一个钓鱼网站(现在应该已经撤掉了)。去那个钓鱼网站看了一眼,发现居然是装的正版支付宝插件。

相信插件能保护客户的安全的人可以洗洗睡了,你们根本不配说"安全"两个字,除了供一两个三流技术人员拿大量客户计算机的安全开玩乐和练手之外,这些控件没有价值。

续前。

除了硬件上直接采用的降噪措施之外,一些软件方面的配置也可以提高其效果。

首先是BIOS中的配置。风扇转速最低可调整为"Energy Saving"(即使用30%的频率)。启用Active Power State之后,可节省大约2W左右的耗电(这个选项的默认值是Disabled)。

然后是FreeBSD本身的配置。我个人采用的配置包括:

  • 禁用硬盘的APM。WD的这款硬盘默认的APM值为128,这样它每隔大约10秒没有操作时就会将磁盘转速降低。这类操作对磁盘的寿命有一定影响(一般来说磁盘的机械部分支持10万到20万次这样的操作),因此可将其设为254;
  • 启用磁盘的AAM。这个配置的好处是让磁盘控制其磁头臂的加速度,其效果是减少噪音,并且有一定的节能效果。注意:实际测试显示这个设置产生的节能效果基本上可以忽略不计,并且会稍微降低一些性能。磁盘的AAM数值设置为128(默认为254);
  • 将经常写的日志放到 /tmp (使用tmpfs);
  • 将收集entropy(随机数种子)的频率由每11分钟一次降低到每天一次;
  • 启用 AHCI 磁盘驱动;将ahci通道的pm_level全部设置为5(设备在闲置125ms之后可申请通道链路进入SLUMBER模式)
  • 禁用APIC时钟。
  • 禁用AT RTC时钟。
  • 对于没有驱动的PCI设备,将其置入D3模式(停电)。

上述设置,除了ahci部分之外,可将系统闲置时的功耗降低到17W左右。

以下是实现中采用的loader.conf相关的部分:

hint.apic.0.clock=0
hint.atrtc.0.clock=0
hw.pci.do_power_nodriver=3
hint.ahcich.0.pm_level=5
hint.ahcich.1.pm_level=5
hint.ahcich.2.pm_level=5
hint.ahcich.3.pm_level=5
hint.ahcich.4.pm_level=5
hint.ahcich.5.pm_level=5

FreeBSD的textdump

| No Comments | No TrackBacks

最近遇到一些奇怪的bug,因为是对恢复时间有比较高要求的系统,所以顺便研究了一下用FreeBSD的textdump来代替更早前出现的minidump的方法。

minidump是2004年初提出的,FreeBSD 6.2-RELEASE开始加入了这个功能,并且在7.x开始默认启用。具体原理是在panic时做dump的时候只存储那些映射为内核内存的物理内存页。这种做法实际上是赌VM的页表在崩溃的时候没有被写坏(绝大多数情况下这是成立的,除非在调试VM本身)。

UPDATE: 杨总 说,Solaris上有一个叫 Fast Crash Dump 的功能。看了一下介绍,是在dump的时候用指定的压缩算法去压缩再转存。先记一笔。

textdump是Robert N. M. Watson在2008年提出的一个新概念,从7.0-RELEASE开始引入:

  • 在编译内核时,需要加入内核调试器。
  • 指定的 ddb 脚本可以挂在某个特定的事件上,比如 panic 进入 kdb 时自动执行
  • 系统提供一个默认的ddb脚本,保存下面这些信息:
    1. 内核编译时的配置
    2. ddb的输出(具体是:show locks; show alllocks; show lockedvnods; show pcpu; bt; ps; alltrace;),基本上足够cover分析常见问题所需的信息
    3. 内核msgbuf的内容(类似dmesg)
    4. panic信息(如果是panic的话)
    5. 内核版本。

启用textdump是需要内核调试器的,因此有一定的安全风险,例如可以从控制台进入ddb。使用时的内核编译配置是options KDB、 DDB和SC_DISABLE_KDBKEY(禁止在控制台热键呼出调试器),然后在 /etc/rc.conf 中加入 ddb_enable="YES" 令系统在引导过程中将ddb脚本汇入内核,并指定dumpdev。

需要注意的是目前textdump与KDB_UNATTENDED不兼容,因为后者会令内核不调用调试器而直接重启。

textdump保存的内容非常少,因此可以大大减少dump所需的时间。

最近找时间做了一个家用的路由器。用基于 Intel Atom 处理器的解决方案并不便宜(与传统的嵌入式解决方案相比),但因为软硬件都是 x86,因此开发起来会方便一些。另一方面,Atom的计算性能要远高于其他的传统嵌入式方案。

配置:

SMCI这款X7SPA-H主板采用的是ICH9R芯片组,有6个SATA接口,支持AHCI。采用4G内存的原因主要是希望使用ZFS,同时作为存储服务器使用。由于空间原因,这款CPU使用被动散热片。

PC-781机箱可以配置外接的直流电源(类似笔记本的电源)。采用这种配置的考虑是外接电源不需要使用风扇散热,整个机箱总共只有1个小风扇(题外话:因为功率不大,实际上这个风扇并不是必须的),从而减少噪声。

由于没有光驱,因此使用U盘以memstick映像来安装。在 sysinstall 中选 FixIt >> USB 之后就可以手动安装了。

关于磁盘布局:WD AV-25使用的是WD的"Advanced Format",即4k扇区的格式。由于对系统而言扇区仍然是512字节,因此在分区时应以8扇区对齐。这块硬盘的GPT分区为:

34开始,94扇区:boot

128开始,16777216扇区:swap

16777344开始到结尾:zfs

(待续)

Monthly Archives

Pages

OpenID accepted here Learn more about OpenID
Powered by Movable Type 5.2.3