一、Kafka的生产集群部署1.1 方案背景假设每天集群需要承载10亿数据。一天24小时，晚上12点到凌晨8点几乎没多少数据。使用二八法则估计，也就是80%的数据（8亿）会在16个小时涌入，而且8亿的80%的数据（6.4亿）会在这16个小时的20%时间（3小时）涌入。QPS计算公式：640000000 ÷ (3x60x60) = 60000，也就是说高峰期的时候Kafka集群要扛住每秒6万的并发。磁盘空间计算，每天10亿数据，每条50kb，也就是46T的数据。保存2个副本（在上一篇中也提到过其实两个副本会比较好，因为follower需要去leader那里同步数据，同步数据的过程需要耗费网络，而且需要磁盘空间，但是这个需要根据实际情况考虑），46 2 = 92T，保留最近3天的数据。故需要 92 3 = 276T1.2 QPS方面部署Kafka，Hadoop，MySQL···等核心分布式系统，一般建议直接采用物理机，抛弃使用一些低配置的虚拟机的想法。高并发这个东西，不可能是说，你需要支撑6万QPS，你的集群就刚好把这6万并发卡的死死的。加入某一天出一些活动让数据量疯狂上涨，那整个集群就会垮掉。但是，假如说你只要支撑6w QPS，单台物理机本身就能扛住4~5万的并发。所以这时2台物理机绝对绝对够了。但是这里有一个问题，我们通常是建议，公司预算充足，尽量是让高峰QPS控制在集群能承载的总QPS的30%左右（也就是集群的处理能力是高峰期的3~4倍这个样子），所以我们搭建的kafka集群能承载的总QPS为20万~30万才是安全的。所以大体上来说，需要5~7台物理机来部署，基本上就很安全了，每台物理机要求吞吐量在每秒4~5万条数据就可以了，物理机的配置和性能也不需要特别高。1.3 磁盘方面1.3.1 磁盘数量需要5台物理机的情况，需要存储276T的数据，平均下来差不多一台56T的数据。这个具体看磁盘数和盘的大小1.3.2 SAS还是SSD现在我们需要考虑一个问题：是需要SSD固态硬盘，还是普通机械硬盘？SSD就是固态硬盘，比机械硬盘要快，那么到底是快在哪里呢？其实SSD的快主要是快在磁盘随机读写，就要对磁盘上的随机位置来读写的时候，SSD比机械硬盘要快。比如说MySQL这种就应该使用SSD了（MySQL需要随机读写）。比如说我们在规划和部署线上系统的MySQL集群的时候，一般来说必须用SSD，性能可以提高很多，这样MySQL可以承载的并发请求量也会高很多，而且SQL语句执行的性能也会提高很多。因为写磁盘的时候kafka是顺序写的。机械硬盘顺序写的性能机会跟内存读写的性能是差不多的，所以对于Kafka集群来说其实使用机械硬盘就可以了。如果是需要自己创业或者是在公司成本不足的情况下，经费是能够缩减就尽量缩减的。1.4 内存角度JVM非常怕出现full gc的情况。kafka自身的jvm是用不了过多堆内存的，因为kafka设计就是规避掉用jvm对象来保存数据，避免频繁full gc导致的问题，所以一般kafka自身的jvm堆内存，分配个10G左右就够了，剩下的内存全部留给os cache。那服务器需要多少内存呢。我们估算一下，大概有100个topic，所以要保证有100个topic的leader partition的数据在操作系统的内存里。100个topic，一个topic有5个partition。那么总共会有500个partition。每个partition的大小是1G（在上一篇中的日志分段存储中规定了.log文件不能超过1个G），我们有2个副本，也就是说要把100个topic的leader partition数据都驻留在内存里需要1000G的内存。我们现在有5台服务器，所以平均下来每天服务器需要200G的内存，但是其实partition的数据我们没必要所有的都要驻留在内存里面，只需要25%的数据在内存就行，200G * 0.25 = 50G就可以了（因为在集群中的生产者和消费者几乎也算是实时的，基本不会出现消息积压太多的情况）。所以一共需要60G（附带上刚刚的10G Kafka服务）的内存，故我们可以挑选64G内存的服务器也行，大不了partition的数据再少一点在内存，当然如果能够提供128G内存那就更好。1.5 CPU coreCPU规划，主要是看你的这个进程里会有多少个线程，线程主要是依托多核CPU来执行的，如果你的线程特别多，但是CPU核很少，就会导致你的CPU负载很高，会导致整体工作线程执行的效率不太高，上一篇的Kafka的网络设计中讲过Kafka的Broker的模型。acceptor线程负责去接入客户端的连接请求，但是他接入了之后其实就会把连接分配给多个processor，默认是3个，但是一般生产环境建议大家还是多加几个，整体可以提升kafka的吞吐量比如说你可以增加到6个，或者是9个。另外就是负责处理请求的线程，是一个线程池，默认是8个线程，在生产集群里，建议大家可以把这块的线程数量稍微多加个2倍~3倍，其实都正常，比如说搞个16个工作线程，24个工作线程。后台会有很多的其他的一些线程，比如说定期清理7天前数据的线程，Controller负责感知和管控整个集群的线程，副本同步拉取数据的线程，这样算下来每个broker起码会有上百个线程。根据经验4个cpu core，一般来说几十个线程，在高峰期CPU几乎都快打满了。8个cpu core，也就能够比较宽裕的支撑几十个线程繁忙的工作。所以Kafka的服务器一般是建议16核，基本上可以hold住一两百线程的工作。当然如果可以给到32 cpu core那就最好不过了。1.6 网卡现在的网基本就是千兆网卡（1GB / s），还有万兆网卡（10GB / s）。kafka集群之间，broker和broker之间是会做数据同步的，因为leader要同步数据到follower上去，他们是在不同的broker机器上的，broker机器之间会进行频繁的数据同步，传输大量的数据。那每秒两台broker机器之间大概会传输多大的数据量？高峰期每秒大概会涌入6万条数据，约每天处理10000个请求，每个请求50kb，故每秒约进来488M数据，我们还有副本同步数据，故高峰期的时候需要488M * 2 = 976M/s的网络带宽，所以在高峰期的时候，使用千兆带宽，网络还是非常有压力的。综上描述10亿数据，6w/s的吞吐量，276T的数据，5台物理机 硬盘：11（SAS） * 7T，7200转 内存：64GB/128GB，JVM分配10G，剩余的给os cache CPU：16核/32核 网络：千兆网卡，万兆更好二、Kafka的集群搭建进到Kafka的config文件夹下，会发现有很多很多的配置文件，可是都不需要你来修改，你仅仅需要点开一个叫作server.properties的文件就够了。【broker.id】 每个broker都必须自己设置的一个唯一id，可以在0~255之间 【log.dirs】 这个极为重要，kafka的所有数据就是写入这个目录下的磁盘文件中的，如果说机器上有多块物理硬盘，那么可以把多个目录挂载到不同的物理硬盘上，然后这里可以设置多个目录，这样kafka可以数据分散到多块物理硬盘，多个硬盘的磁头可以并行写，这样可以提升吞吐量。ps：多个目录用英文逗号分隔 【zookeeper.connect】 连接kafka底层的zookeeper集群的 【Listeners】 broker监听客户端发起请求的端口号，默认是9092 【num.network.threads】默认值为3 【num.io.threads】默认值为8 细心的朋友们应该已经发现了，这就是上一篇我们在网络架构上提到的processor和处理线程池的线程数目。 所以说掌握Kafka网络架构显得尤为重要。 现在你看到这两个参数，就知道这就是Kafka集群性能的关键参数了 【unclean.leader.election.enable】 默认是false，意思就是只能选举ISR列表里的follower成为新的leader，1.0版本后才设为false，之前都是true，允许非ISR列表的follower选举为新的leader 【delete.topic.enable】 默认true，允许删除topic 【log.retention.hours】 可以设置一下，要保留数据多少个小时，这个就是底层的磁盘文件，默认保留7天的数据，根据自己的需求来就行了 【min.insync.replicas】 acks=-1（一条数据必须写入ISR里所有副本才算成功），你写一条数据只要写入leader就算成功了，不需要等待同步到follower才算写成功。但是此时如果一个follower宕机了，你写一条数据到leader之后，leader也宕机，会导致数据的丢失。因为实际的集群搭建说真的没有太大难度，所以搭建的过程就不详细展开了，网上应该很多相关资料三、Kafka的简单集群操作在操作Kafka集群的时候，不同的Kafka版本命令的写法是不一样的，所以其实如果需要了解一下，推荐直接到官网去查看上一篇时也有提到说Kafka在0.8版本以前存在比较大的问题，1.x的算是目前生产环境中使用较多的版本在quickStart就能看到相关的命令，比如① 创建主题bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test 将该命令修改一下 zookeeper localhost:2181 --replication-factor 2 --partitions 2 --topic tellYourDream 这时候就是zookeeper的地址为localhost:2181 两个分区，两个副本，一共4个副本，topic名称为“tellYourDream”了还得注意，一般来说设置分区数建议是节点的倍数，这是为了让服务节点分配均衡的举措。② 查看主题：bin/kafka-topics.sh --list --zookeeper localhost:2181③ 生产信息 bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test This is a message This is another message④ 消费信息 bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning This is a message This is another message这里有个细节需要提及一下，就是我们0.8版本的kafka找的是zookeeper，zookeeper上确实是也存在着元数据信息。不过这存在着一些问题，zookeeper本身有一个过半服务的特性，这是一个限制，过半服务是指任何的请求都需要半数节点同意才能执行。每次有写请求，它都要投票，因为它要保持数据的强一致性，做到节点状态同步，所以高并发写的性能不好。不适合做高并发的事。zookeeper是Kafka存储元数据和交换集群信息的工具，主要是处理分布式一致性的问题。⑤ 集群测试下面的命令就是生产50W条数据，每条数据200字节，这条命令一运行就会产生一条报告，可以很直观的看到集群性能，看不懂的情况搜索引擎也可以很好地帮助你解决问题测试生产数据 bin/kafka-producer-perf-test.sh --topic test-topic --num-records 500000 --record-size 200 --throughput -1 --producer-props bootstrap.servers=hadoop03:9092,hadoop04:9092,hadoop05:9092 acks=-1每次消费2000条，集群没跑挂那就稳妥了测试消费数据 bin/kafka-consumer-perf-test.sh --broker-list hadoop03:9092,hadoop04:9092,hadoop53:9092 --fetch-size 2000 --messages 500000 --topic test-topic 四、KafkaManagerKafkaManager使用scala写的项目。安装步骤可以参考kafka集群管理工具kafka-manager部署安装，非常不错。使用方法可以通过搜索引擎查找。安装好了之后可以使用jps命令查看一下，会多出一个名字叫做ProdServerStart的服务功能介绍1. 管理多个kafka集群 2. 便捷的检查kafka集群状态(topics,brokers,备份分布情况,分区分布情况) 3. 选择你要运行的副本 4. 基于当前分区状况进行 5. 可以选择topic配置并创建topic(0.8.1.1和0.8.2的配置不同) 6. 删除topic(只支持0.8.2以上的版本并且要在broker配置中设置delete.topic.enable=true) 7. Topic list会指明哪些topic被删除（在0.8.2以上版本适用） 8. 为已存在的topic增加分区 9. 为已存在的topic更新配置 10. 在多个topic上批量重分区 11. 在多个topic上批量重分区(可选partition broker位置)五、KafkaOffsetMonitorKafkaOffsetMonitor就是一个jar包而已，是一个针对于消费者的工具。它可以用于监控消费延迟的问题，不过对于重复消费和消息丢失等就无法解决，因为之后如果需要讲解SparkStreaming，flink这些用于消费者的实践的话，会使用到这个工具，所以现在先不展开，了解一下即可启动命令：java -cp KafkaOffsetMonitor-assembly-0.3.0-SNAPSHOT.jar \ com.quantifind.kafka.offsetapp.OffsetGetterWeb \ --offsetStorage kafka \ --zk xx:2181,xx:2181,xx:2181/kafka_cluster \ --port 8088 \ --refresh 60.seconds \ --retain 2.days还有一些跨机房同步数据的像MirrorMaker这些，酌情使用。转载自 https://juejin.im/post/5dd34f735188254efb3bd12b
转载自知乎一句话结论：现代大容量硬盘组成的RAID 5单盘故障后，重建失败的概率相当高，不可忽略；但数据本身还是基本安全的（会丢失部分文件），只是可能需要一个比较麻烦的恢复方案。楼上包括高赞回答在内一堆说两个硬盘同时坏的，要加一个热备盘的，都是没仔细看过问题里面的链接就回答的。在回答问题的现在，这个链接失效了，但网上还是有人转载过的，例如这篇[1]：DBA亲，你们的RAID5阵列有保障吗？marbury关注0人评论10546人阅读2014-02-21 10:30:24 该文章主要整理论坛内容。（论坛地址：http://bbs.et8.net/bbs/showthread.php?t=1026112）很多人遇到过服务器RAID5挂掉，往往掉一个盘后，第二个盘也立刻挂掉。引用：RAID 5也是以数据的校验位来保证数据的安全，但它不是以单独硬盘来存放数据的校验位，而是将数据段的校验位交互存放于各个硬盘上。这样，任何一个硬盘损坏，都可以根据其它硬盘上的校验位来重建损坏的数据。硬盘的利用率为n-1。如果挂掉两个盘，数据就玩完了。 理论上两个硬盘同时失效的概率是很低的，但为什么会这样呢？ 引用：从数学角度说，每个磁盘的平均无故障时间 (MTBF) 大约为 50 万至 150 万小时(也就是每 50～150 年发生一次硬盘损坏)。实际往往不能达到这种理想的情况，在大多数散热和机械条件下，都会造成硬盘正常工作的时间大幅减少。考虑到每个磁盘的寿命不同，阵列中的任何磁盘都可能出现问题，从统计学角度说，阵列中 N 个磁盘发生故障的机率比单个磁盘发生故障的机率要大 N 倍。结合上述因素，如果阵列中的磁盘数量合理，且这些磁盘的平均无故障时间 (MTBF) 较短，那么在磁盘阵列的预期使用寿命过程中，就很有可能发生磁盘故障(比方说每几个月或每隔几年就会发生一次故障)。 两块磁盘同时损坏的几率有多大呢(“同时”就是指一块磁盘尚未完全修复时另一块磁盘也坏掉了)?如果说 RAID 5 阵列的MTBF相当于MTBF^2，那么这种几率为每隔10^15个小时发生一次(也就是1万多年才出现一次)，因此不管工作条件如何，发生这种情况的概率是极低的。从数学理论角度来说，是有这种概率，但在现实情况中我们并不用考虑这一问题。不过有时却是会发生两块磁盘同时损坏的情况，我们不能完全忽略这种可能性，实际两块磁盘同时损坏的原因与MTBF基本没有任何关系。 对这种情况来说，这里首先要引入一个一般人不常接触到的概念：BER 硬盘误码率,英文是BER(Bit Error Rate),是描述硬盘性能的一个非常重要的参数,是衡量硬盘出错可靠性的一个参数。这个参数代表你写入硬盘的数据，在读取时遇到不可修复的读错误的概率。从统计角度来说也比较少见，一般来说是指读取多少位后会出现一次读取错误。 随着硬盘容量增加，驱动器读取数据的误读率就会增加，而硬盘容量暴涨，误码率的比例一直保持相对增加。一个1TB的驱动器是需要更多读取整个驱动器，这是在RAID重建期间发生错误的概率会比300G 驱动器遇到错误的几率大。 那这个错误的几率到底有多大呢？或者说，我们写入多少GB数据，才会遇到1byte的读取错误呢？看这篇文章：http://lenciel.cn/docs/scsi-sata-reliability/对于不同类型的硬盘（以前企业级、服务器、数据中心级硬盘用SCSI/光纤，商用、民用级别是IDE；现在对应的则是SAS/SATA； 他们的MRBF（平均无故障时间）是接近的，但是BER便宜的SATA硬盘要比昂贵的SCSI硬盘的误码率（BER）要高得多。 也就是说，出现某个sector无法读取的情况，SATA要比SCSI严重得多。具体区别在固件上：遇到读取不过去，或者写入不过去的坏道时，家用硬盘会花费1分钟以上的时间去尝试纠正错误，纠正不了就直接用备用扇区代替，这个时间超过阵列控制器能容忍的限度，所以遇到这种情况直接掉盘；企业级的磁盘会把这项工作放在后台进行，不需要停顿1分钟左右的时间，从而不影响阵列运行。在BER 硬盘误码率上没有任何区别。 按照文中的计算，一个1TB的硬盘，通常你无法读取所有sector的概率达到了56%，因此你用便宜的大容量SATA盘，在出现硬盘故障的情况下重建RAID的希望是：无法实现。 用1TB的SATA硬盘做RAID5的话，当你遇到一个硬盘失效的情况，几乎剩下的两个以上硬盘（RAID5最少组合是3个）铁定会遇到一个硬盘读取错误，从而重建失败。 所以，以前小硬盘做RAID5，基本很少遇到同时挂掉两个盘的情况；现在硬盘大了，出问题的概率也越来越大了。 对于跑RAID的用户，对整个硬盘进行读取的事情经常发生。即使系统足够和谐，知道不对你报告那些出现在你从不读取的文件中的坏道，但是也只是略过了报告这一步：它还是会找到所有的坏道，56%就来了。还有所谓的监控专用企业级SATA，其原理就是在固件上做手脚，让硬盘即使遇到写入的数据读取错误，也不管三七二十一直接跳过，不再重试读取（标准硬盘的读取方式是遇到某个扇区CRC错误自动重新再去读，直到读到正确的数据为止）。这对监控数据来说是理所当然的（大多数监控的硬盘都是在不停地写入，但是很少需要读取），除非遇到出现问题需要重现影像时。 现有的Raid5阵列的磁盘中有未检测到的错误的话，Hot Spare没办法解决。Hot Spare只能在某个磁盘下线的时候，及时的替换下线的盘进行Raid重建，如果其他磁盘有错误的话，重建还是会可能失败。 解决方法还是要在阵列健康状态下，进行定期或者其他方式的错误检查。一般的硬件阵列卡，也就是插在主板PCI/PCIX/PCIE/或者主板集成的RAID5，压根就没数据巡检（scrub）功能。企业级的数据存储，也只有到盘阵级别（比如IBM DS3000/4000/5000，DELL MD3000....etc）才有这类功能，但是你也看不到检查的结果，最多能在日志里看到某个硬盘CRC失败，然后跳红灯掉出来，阵列柜告警通知你换硬盘。你别想知道这个硬盘到底是彻底挂了呢，还是有读取错误，还是有坏道。。。总之两眼一抹黑。（ZFS上的RAIDZ有数据巡检（scrub）功能） 总结遇到RAID5一次挂掉俩盘的概率1、使用越大容量的硬盘做RAID5，遇到BER 扇区的概率越大；比如用100G硬盘做RAID5就比用1TB的安全；2、使用越多盘数的硬盘做RAID5，遇到BER 扇区的概率越大；比如用3个盘做的RAID5，比6个盘做的RAID5安全；3、使用越便宜的硬盘做RAID5，遇到BER 扇区的概率越大；比如用SCSI/FC/SAS盘比用IDE/SATA的RAID5安全；4、RAID5里面存放的数据越多，塞得越满，遇到BER 扇区的概率越大；比如存了100G数据的比存了1TB数据的RAID5安全；（REBUID时只读取存过数据的扇区，某些卡则不管三七二十一要读完整个盘） RAID1/RAID10参与重建的只有一个盘,与raid5所有盘都需要参与重建相比，故障概率降低；RAID1 某一组磁盘故障，也不需要强制上线的操作，因为数据仍然存在，不需要组RAID也能读取，哪怕是换到其他没有raid卡的机器上数据仍能读出；而RAID5如果不能强制第二个掉下的硬盘上线，你一点东西都读不到。 对于DB来说：做raid 1+0 是最好不过啦！（备份时必不可少的；当RAID处理降级状态时，如重要数据容量不大，建议先做备份，当然这种备份应该是异机的，不可备份至当前已降级的RAID中。如果在REBUILD当中出现另外硬盘离线的情况导致RAID卷OFFLINE，切不可重建RAID，如确定后离线的硬盘，可通过强制上线恢复数据(有些控制器没有选项，就没办法了)本文出自 “技术成就梦想” 博客，请务必保留此出处http://weipengfei.blog.51cto.com/1511707/1006565这篇文章有两个我认为不正确的地方：用硬盘厂家标称的MTBF来计算第二块硬盘发生故障概率是不适当的。如果参考谷歌的论文[2]，5年内硬盘的最高年平均故障率为8.6%（下面估算中用稍高一点的10%进行估算）。按照这篇文章所说的1TB硬盘，假设平均写入速度为100MB/s计算，重建RAID 5需要写满一个硬盘，大概需要 ![[公式]](https://www.zhihu.com/equation?tex=1e12+%5Cdiv+100e6+%5Cdiv+3600+%3D+2.78) 小时。如果以8盘RAID5计算的话，单个硬盘故障后还有7个硬盘，在2.78小时内单个硬盘发生故障的概率可以用 ![[公式]](https://www.zhihu.com/equation?tex=10+%5C%25+%5Cdiv+365+%5Cdiv+24+%5Ctimes+2.78+%3D+3.17e-5) 计算。7个硬盘在2.78小时一个或一个以上硬盘出现故障的概率可以用binomial distribution（二项分布）的概率质量公式计算： ![[公式]](https://www.zhihu.com/equation?tex=Pr%5Cleft%28+X+%5Cgeq+1+%5Cright%29+%3D+%5Csum_%7Bi%3D1%7D%5E%7B7%7D%7B+%5Cbinom%7B7%7D%7Bi%7D+p%5E%7B7%7D+%5Cleft%281-p%5Cright%29%5E%7B7-i%7D%7D) ，其中P=3.17e-5。这里的这个公式可以简化为 ![[公式]](https://www.zhihu.com/equation?tex=1-Pr%280%29%3D1-%5Cbinom%7B7%7D%7B0%7Dp%5E%7B0%7D%281-p%29%7B7%7D) 后用Excel计算，计算函数为=1-BINOMDIST(0,7,3.17e-5,TRUE），计算结果为2.22e-4，也就是0.022%。如果考虑到RAID 5重建过程中还有其它IO应用，或者RAID卡重建性能较差，导致重建速度降低，假设平均写入速度只有20MB/s，则重建时间约为14小时，重建过程中出现第二个硬盘故障的概率为0.11%。也就是大概每1000次重建可能出现1次第二个硬盘故障。也就是说，在一个部署了上万硬盘并且均组成RAID5阵列的数据中心中，几乎每年都会发生一例，并非是文中所说的“在现实情况中我们并不用考虑这一问题”。2019年的今天，单个硬盘最大容量已经达到14TB，假设重建速度保持在20MB/s，这个概率会进一步提升到1.54%；即使重建速度提升到50MB/s，这个概率还有0.62%，超过1/200。不过即使这样，和因为URE导致的重建失败的概率（见后文）相比，这也是一个相当低的概率。“一个1TB的硬盘，通常你无法读取所有sector的概率达到了56%”这句话是不正确的，要搞清楚这个概率的出处，需要去看文中链接的文章。不过，这篇文章中引用的链接地址无法访问的，估计是博主换了域名，通过搜索找到新域名链接[3]，但[3]依然没有给出这个数据是如何计算出来的。只提到：最近看到一篇文章讨论SATA和SCSI硬盘的可靠性问题。这篇文章的结论是：两种硬盘的故障率（MTBF）是极其接近的，只不过便宜的SATA硬盘要比昂贵的SCSI硬盘的误码率（BER）要高得多。也就是说，出现某个sector无法读取的情况，SATA要比SCSI严重得多。按照他的计算，一个1TB的硬盘，通常你无法读取所有sector的概率达到了56%，因此你在出现硬盘故障的情况下重建RAID的希望是：无法实现。点击上面的“这篇文章”的链接[4]，原文部分摘录如下：Where there is a difference between models, though, is with our old friend, the bit error rate. The bit error rate is the rate at which a block just can’t be read from the disk, due to not being able to recover data from the PRML and ECC codes on the platter. The whole drive doesn’t fail, but you can’t read that block. In a RAID system, this triggers reconstruction of that block from the remaining drives.As I describe in the video “The Trouble with RAID”, this bit error rate is the biggest problem with RAID technology today. In the event of a drive failure in a RAID 4 or RAID 5 set, every remaining drive must be read perfectly from start to finish or else data will be lost. With a 7+1 set of terabyte drives, this means 7 TB must be read. A bit error rate of 1 in 10^14 means that there’s a 44% chance that can’t be done.摘录部分翻译如下：然而，不同型号（译注：原文指消费级硬盘及SCSI/光纤通道硬盘）之间存在的差异是我们所熟知的误码率。误码率是指由于无法通过PRML和ECC从盘片上的恢复数据而无法从磁盘读取某个扇区数据的概率。硬盘整体来说并未发生故障，但用户无法读取该扇区的数据。在RAID系统中，这会触发用其它硬盘上的数据对该扇区数据恢复的重建过程。正如我在视频中描述的“RAID的麻烦”一样，这种误码率是当今RAID技术最大的问题。如果RAID 4或RAID 5中的驱动器发生故障，则剩余的每个硬盘都必须从头到尾“完美”的读取一遍，否则将会导致数据丢失。使用7+1个1 TB容量硬盘，这意味着必须读取7 TB。1/10^14的误码率为意味着有44％的概率无法做到（“完美”读取7TB数据）。译注：PRML：Partial-response maximum-likelihood，部分响应最大似然，一种提高磁头读取磁盘后产生的微弱模拟信号数字化准确度的技术。ECC：Error Correct Code，纠错码，一种通过传输/保存冗余编码的数据位，在原始数据发生传输错误时可以检测到错误并恢复出正确数据的技术。[4]所提到的bit error rate，现在各家硬盘厂商的Datasheet中通常叫Non-recoverable Read Error rate，网上包括维基通常用Unrecoverable Read Error rate（URE，本文均使用此缩写），也就是[1]所提到的“写入硬盘的数据，在读取时遇到不可修复的读错误的概率”。稍微解释一下，这个读错误产生的原因可能在于：数据写入硬盘时，数字信号转换为盘片上的模拟磁场信号过程中发生错误；数据存放过程中，因为外界的电磁干扰/宇宙射线/写入周围单元时磁头位置偏离导致的磁单元中部分磁性材料极性翻转；读取数据时，磁场信号转换为数字信号过程中发生错误；在硬盘内部，这种错误其实是经常发生的，但一般来说每个扇区可能也就1~3 bit的数据发生这种错误。因此机械硬盘每个扇区后面有若干位ECC纠错码（早期的512B扇区硬盘是每扇区50Byte，现在的4K扇区硬盘是每扇区100Byte[5]），可以用于纠正此类错误。然而ECC不是万能的，如果读取某个扇区的数据时发生错误的位过多，ECC也无能为力，这个时候就发生“不可恢复的读取错误（也就是前面定义中的Unrecoverable Read Error）”了。按照硬盘厂家提供的参数，发生这种情况的概率——也就是URE，消费级硬盘一般是1e-14，企业级硬盘发生URE的概率一般是1e-15。[4]并没有给出具体的计算根据URE计算RAID5重建成功概率的公式，这里稍微补充一下。如果某款硬盘的URE是1e-14/bit（这个可以从各家硬盘厂商的DataSheet中查到），并不代表每读取1e+14 bit就一定出现一次URE。同样可以用二项分布公式计算，读取1e14bit发生URE的概率：0次： ![[公式]](https://www.zhihu.com/equation?tex=Pr%5Cleft%28+X+%3D+0+%5Cright%29+%3D+%5Cbinom%7B1e14%7D%7B0%7D+%5Cleft%28+1e-14+%5Cright%29%5E%7B0%7D+%5Cleft%281+-+1e-14%5Cright%29%5E%7B1e14%7D%3D36.79+%5C%25)1次： ![[公式]](https://www.zhihu.com/equation?tex=Pr%5Cleft%28+X+%3D+1+%5Cright%29+%3D+%5Cbinom%7B1e14%7D%7B1%7D+%5Cleft%28+1e-14+%5Cright%29%5E%7B1%7D+%5Cleft%281+-+1e-14%5Cright%29%5E%7B1e14-1%7D%3D29.05+%5C%25)2次： ![[公式]](https://www.zhihu.com/equation?tex=Pr%5Cleft%28+X+%3D+2+%5Cright%29+%3D+%5Cbinom%7B1e14%7D%7B2%7D+%5Cleft%28+1e-14+%5Cright%29%5E%7B2%7D+%5Cleft%281+-+1e-14%5Cright%29%5E%7B1e14-2%7D%3D22.94+%5C%25)……不过1e14次试验，1e-14的概率这样的数字，Excel是算不了了，可以用Python的scipy库计算：>>> from scipy.stats import binom >>> binom.pmf(0, 1e14, 1e-14) 0.36787944117144045 >>> binom.pmf(1, 1e14, 1e-14) 0.2904884966524753 >>> binom.pmf(2, 1e14, 1e-14) 0.22937831594696387 >>> binom.pmf(3, 1e14, 1e-14) 0.04041420666321343 >>> binom.pmf(4, 1e14, 1e-14)我们只关心不发生URE的概率，也就是0次。因此二项分布的概率质量函数可以这样简化：![[公式]](https://www.zhihu.com/equation?tex=%5Cbegin%7Bequation%7D+%5Cbegin%7Baligned%7D+Pr%28X%3D0%29%26%3D%5Cbinom%7Bn%7D%7Bk%3D0%7Dp%5E%7Bk%7D%281-p%29%7Bn-k%7D%5C%5C+%26%3D%5Cfrac%7Bn%21%7D%7B0%21%28n-0%29%21%7Dp%5E%7B0%7D%281-p%29%5E%7Bn%7D%5C%5C+%26%3D%281-p%29%5E%7Bn%7D+%5Cend%7Baligned%7D+%5Cend%7Bequation%7D+)而4个1TB硬盘组成的RAID 5，单盘故障后的重建过程需要读取的数据量为1e12 Byte×8 bit/Byte×(4-1)=24Tbit，而读取24Tbit过程中没有发生URE的概率则是(1-1e14)^24e12=78.68%。用Excel可以很轻松计算出重建RAID5过程中，不同误码率，不同容量的硬盘，组成4/8盘RAID 5的重建成功/失败概率，见下表（PS：Excel用简化公式计算和用scipy直接计算的结果会稍有出入，但可以忽略）。表中8个URE为1e-14建立的RAID 5重建成功概率为57.15%，和[4]所说的44%失败比较接近了。所以前面[1]所说的56%，是8个1TB硬盘组成的RAID5，重建过程中因为发生URE导致重建失败的概率。而单个1TB硬盘完全读取，发生URE的概率应该是7.68%。进一步观察估算结果，其实单个硬盘全盘读取，8TB容量出现URE概率已经接近50%了。也所以现在8TB以上（含8TB）的硬盘，即使是消费级的，也都是1e-15的URE——起码希捷的最新产品线是这样。倒是企业级的Exos 5E8只有一款8TB型号，反倒标称的URE参数是1e-14。从上表可见4个URE为1e-14的1TB硬盘组成的RAID 5重建失败的概率为21.32%，其实已经相当高了；8个URE为1e-14的硬盘组RAID5的话，1~2TB还可以拼一下脸，3~4TB那叫玩命，6~8TB就是碟中谍了。需要说明的是，通常RAID 5是在硬件层面（有独立主控芯片的RAID卡，常说的硬RAID）或者块设备驱动层面（主板或操作系统，软RAID）实现的，与文件系统独立。因此RAID控制芯片或者驱动是无法知道RAID上某一段数据，到底是存有数据的文件，还是某个已经被删除的文件；也不知道某一段全0的数据，到底是未使用空间还是某个预分配磁盘空间但未使用的数据库文件。因此即使一个1TB*8，可用空间7TB的RAID 5，假设用户仅仅存放了50GB数据，重建的时候还是必须把7TB的数据全部读取一遍的。对于这种情况，RAID 5EE、RAID 2.0，以及由文件系统本身实现类似RAID 5的RAID Z1（ZFS文件系统），则是可以仅重建已经使用的50GB数据。对比前面分析，重建过程中第二块硬盘出现故障导致重建失败的概率，8个1TB硬盘低速重建也不过0.11%，但因为URE导致重建失败的概率则是高达42.85%。题目和其它部分答案所提到的热备盘，其意义在于RAID卡/驱动发现单个硬盘故障的时候，可以马上进入重建过程。假设没有热备盘，需要24小时后才能开始重建，按照前面的计算，8个1TB硬盘组成的RAID 5的重建时间从14小时延长到38小时，这个期间第二块硬盘发生故障的概率约为0.30%，和发生URE导致重建失败的42.85%相比，几乎可以忽略了。所以，现代大容量硬盘组成的RAID5重建失败，并非是两个硬盘同时坏导致（不过从另一个角度来说，可以认为一个硬盘坏的时候，另外一个硬盘已经存在隐患，全盘读取会导致隐患暴露）。因此不要买同一批次硬盘组RAID，保留一个热备盘更安全这两个观点，起码在大容量硬盘流行的现在，已经是过时的观点了。事实上，如果RAID卡或者驱动支持RAID 6，与其留一个热备盘，不如直接把RAID 5升级为RAID 6。最后需要补充的是，发生URE导致重建失败，并非意味着全部数据丢失——这是唯一值得安慰的地方。数据基本上都还在可以恢复的，只是根据不同的RAID实现方案，可能需要不同的恢复方案：如果RAID卡/驱动允许，可以继续以降级模式运行，那么直接把所有数据复制到另外一个阵列就好；如果RAID卡遭遇URE后，强制某个硬盘离线并且不能重新上线，就需要找专业的数据恢复了。不过因为URE的存在，这两种方案都可能会丢失一个或多个文件。严重的话，丢失文件系统结构的元数据（Metadata），会导致文件系统崩溃，只能通过数据恢复软件对整个阵列进行全盘扫描来恢复，这样恢复的成功率就很低了。好在通常元数据很小，发生这种情况的概率也很低。反过来，运气最好就是URE发生在未使用的空白区域上，则对数据没有任何影响。另外，不管哪一种恢复方案，由于需要另外一个同等容量的阵列来存放恢复出来的数据，对于家庭用户来说，通常都是非常麻烦——或者成本高昂的事情。所以我在多个家用NAS主题下的回答，都明确反对家用NAS使用RAID 5。作为RAID 5的替代方案，答主建议如下：经济条件允许的，采购支持RAID 6的RAID卡，多牺牲一块硬盘的容量组建RAID 6。DIY NAS的，使用支持ZFS的操作系统，多牺牲一块硬盘容量组RAID Z2。使用成品NAS的，牺牲一块硬盘容量组RAID 10（四盘位）或者RAID 6（5盘位及以上）玩不转Linux/BSD/Solaris的，又不需要阵列的持续性能的，用SnapRAID+计划任务。想安全的话，多牺牲一块硬盘组双校验盘的SnapRAID，等效RAID 6；经济原因或者机箱位置不够的，组单校验盘的SnapRAID也可以，因为SnapRAID是基于文件生成校验数据，即使碰到URE也只会丢失单个文件。最后的最后：RAID不是备份，重要数据，请做好备份。RAID不是备份，重要数据，请做好备份。RAID不是备份，重要数据，请做好备份。备份到移动硬盘，或者加密同步到网盘都是更安全的方案。[1] DBA亲，你们的RAID5阵列有保障吗？-史振宁的技术博客-51CTO博客[2] Failure Trends in a Large Disk Drive Population - Research - GooglePDF[3] SCSI和SATA的稳定性[4] Are Fibre Channel and SCSI Drives More Reliable?[5] Seagate 中国
Cache和Buffer是两个不同的概念，简单的说，Cache是加速“读”，而buffer是缓冲“写”，前者解决读的问题，保存从磁盘上读出的数据，后者是解决写的问题，保存即将要写入到磁盘上的数据。在很多情况下，这两个名词并没有严格区分，常常把读写混合类型称为buffer cache，本文后续的论述中，统一称为cache。Oracle中的log buffer是解决redo写入的问题，而data buffer cache则解决data block的读写问题。对于Oracle来说，如果IO没有在SGA中命中，都会发生物理IO，Oracle并不关心底层存储的类型，可能是一套存储系统，可能是本地磁盘，可能是RAID 10，也可能是RAID 5，可能是文件系统，也可能是裸设备，或是ASM。总之，Oracle把底层的存储系统称为存储子系统。在存储系统中，cache几乎无处不在（在后面的论述中，我们统称为cache），文件系统有cache，存储有cache，RAID控制器上有cache，磁盘上也有cache。为了提高性能，Oracle的一个写操作，很有可能写在存储的cache上就返回了，如果这时存储系统发生问题，Oracle如何来保证数据一致性的问题。Oracle数据库最重要的特性是：Write ahead logging，在data block在写入前，必须保证首先写入redo log，在事务commit时，同时必须保证redo log被写入。Oracle为了保证数据的一致性，对于redo log采用了direct IO，Direct IO会跳过了OS上文件系统的cache这一层。但是，OS管不了存储这一层，虽然跳过了文件系统的cache，但是依然可能写在存储的cache上。一般的存储都有cache，为了提高性能，写操作在cache上完成就返回给OS了，我们称这种写操作为write back，为了保证掉电时cache中的内容不会丢失，存储都有电池保护，这些电池可以供存储在掉电后工作一定时间，保证cache中的数据被刷入磁盘，不会丢失。不同于UPS，电池能够支撑的时间很短，一般都在30分钟以内，只要保证cache中的数据被写入就可以了。存储可以关闭写cache，这时所有的写操作必须写入到磁盘才返回，我们称这种写操作为write throuogh，当存储发现某些部件不正常时，存储会自动关闭写cache，这时写性能会下降。RAID卡上也有cache，一般是256M，同样是通过电池来保护的，不同于存储的是，这个电池并不保证数据可以被写入到磁盘上，而是为cache供电以保护数据不丢失，一般可以支撑几天的时间。还有些RAID卡上有flash cache，掉电后可以将cache中的内容写入到flash cache中，保证数据不丢失。如果你的数据库没有存储，而是放在普通PC机的本地硬盘之上的，一定要确认主机中的RAID卡是否有电池，很多硬件提供商默认是不配置电池的。当然，RAID卡上的cache同样可以选择关闭。磁盘上的cache，一般是16M-64M，很多存储厂商都明确表示，存储中磁盘的cache是禁用的，这也是可以理解的，为了保证数据可靠性，而存储本身又提供了非常大的cache，相比较而言，磁盘上的cache就不再那么重要。SCSI指令中有一个FUA(Force Unit Access)的参数，设置这个参数时，写操作必须在磁盘上完成才可以返回，相当于禁用了磁盘的写cache。虽然没有查证到资料，但是我个人认为一旦磁盘被接入到RAID控制器中，写cache就会被禁用，这也是为了数据可靠性的考虑，我相信存储厂商应该会考虑这个问题。至此，我们可以看到Oracle的一个物理IO是经历了一系列的cache之后，最终被写入到磁盘上。cache虽然可以提高性能，但是也要考虑掉电保护的问题。关于数据的一致性，是由Oracle数据库，操作系统和存储子系统共同来保证的。
在vmware环境下，有时出现虚拟机磁盘不够用的情况，需要给原有硬盘扩容或者新增硬盘，但一般情况下下，Linux扩容硬盘或者新增硬盘都需要重启系统后才能识别，下面主要讲如何在不重启系统的情况下，如何实现硬盘空间的扩容（前提是系统使用LVM）。vmware操作首先，在esxi（或者workstation）中选择虚拟机设置，选中硬盘，直接调整大小（只能增加，不能减少），或者添加一块新的硬盘。磁盘扩容后系统操作完成虚拟机硬盘扩容后，登录到系统中，执行fdisk -l命令，发现硬盘空间并未增加，如图：此时，需要重新扫描存储设备的SCSI总线，有两种方式：方法1 .echo 1 > /sys/class/scsi_disk/2\:0\:0\:0/device/rescan如下图，其中红框部分需要根据实际的路径进行替换重新执行fdisk，发现磁盘容量已经增加。方法 2 .echo 1 > /sys/block/$DISK/device/rescan其中，$DISK用需要重新扫描的磁盘代替，如sda、sdb等添加磁盘后系统操作[root@localhost ~]# grep mpt /sys/class/scsi_host/host?/proc_name /sys/class/scsi_host/host2/proc_name:mptspi [root@localhost ~]# echo "- - -" > /sys/class/scsi_host/host2/scan其中，host2使用第一步中获取的名称替换。扫描SCSI总线后对LVM的操作系统能识别到磁盘之后，接下来要做的就是扩容LVM了，分为以下几种情况；非系统磁盘扩容，使用pvresize对pv进行扩容，之后按照正常lv扩容流程进行扩容即可。pvresize /dev/sdb lvextend -l +100%FREE <lvname>添加磁盘，扩容lvm，使用pvcreate将新加的磁盘创建为新的pv，将pv加入到vg，然后扩容lv即可。扩容完成lv之后，需要对文件系统重新定义大小，执行resize2fs 设备文件名即可另外，系统盘扩容后，暂时没找到不重启扩容的方法，如有哪位朋友有好的方法，欢迎提出常见问题：创建pv的时候报错：Device /dev/sdb1 not found (or ignored by filtering).执行partprobe命令，使kernel重新读取分区信息即可