不要立即检查刚做过的事情,也不要立即读刚写过的数据。绝对不要为了验证而立即读刚写过的数据。为了近期内的运维需要,可以把数据存储在本地或分布式的缓存中。验证工作相对于不太可能出现的故障来说成本更高。这种活动有悖于有效扩展的需求。
绝对不要为了验证数据而立即读刚写入的数据,而要读并处理与写操作相关的错误。把数据存储在本地可以避免对刚刚写入的数据的其他读操作。
木匠有句名言:“量两次,锯一次。”你可能从中学的木工老师那里听过这句话一他可能还缺了根手指。抛开少手指这事不说,这句名言还是很有道理的,正所谓实践出真知。最好在切割前验证测量的准确度,因为错误的测量结果会导致生产浪费,例如切出一块大小不对的木板。我们当然不会那么做。然而,我们所要强调的是怎样减少另一种浪费,即立即验证刚写入的数据。
在过去的几年中,我们发现自己常常会问客户:“读并验证刚写人的数据,你认为这真的有意义吗?”这种问题出的率令我们吃惊。有时,客户的理由很充分,但没有一条是我们认同的。通常,客户看起来就像是那种被当场抓住的知道自己做了不该做的事的孩子。那些对回答经过深思熟虑(虽然在我们看来是破坏了价值)的客户声称,他们的应用需要绝对确保数据不只是被写入了,还要写得正确。但要记住,我们绝大多数客户都有SaS或商务平台,他们不是在运行核电站,也不是要把人类送往太空,更不是在控制几千架客机的起落或治疗癌症。对于写错或者计算错数据的恐惧,一直都是耗费开发者额外时间的主因。这种恐惧在计算的早期发展阶段可能还算合理,Tanden和Stratus公司分别在20世纪70年代末期和80年代初期设计容错计算机就与这种恐惧有着定的关系。这种系统的主要意图是减少系统的平均故障时间(MTTF),采用的方法是“冗余一切”,即包括CPU、存储、内存、内存路径和存储路径等在内的所有设备都有冗余。这种模型必须对并行计算和存储的系统的结果进行对比,才能验证系统在正确运行。本书的一位作者曾经为一台年代久远的Stratus小型计算机开发过应用,在他为此工作的两年中,该系统从来没有出现过两个处理器间的计算错误,也没有出现过写内存或硬盘的错误。
现在,这种恐惧已经比20世纪70年代末期和80年代初期少多了。事实上,对那些刚写入数据就要执行读操作的客户,当我们问起他们通常是多长时间会发现一次错误时,他们回答得都相当一致,都说从来没有发现过。问题是,除非对由于写操作产生的错误数据进行操作时发生了问题,否则他们绝对不会发现错误。当然,数据损坏也常常发生,但是大多数情况下,只有在真正的写操作时才能发现这种数据损坏。与其投入两倍的工作量,从而让存储、数据库和系统事务减半,不如看看操作返回的错误代码,进行适当的处理。这里补充说明一下,数据损坏的最佳保护措施是正确地做到高可用性,在备用数据库或复制存储设备上保存多个数据副本。最理想的情况是最终实现多个实时站点。
当然,并非所有的“写后立即读”的操作都是由于过分仔细的程序员为了验证刚写入的数据而产生的。有时,也可能是最终用户请求了刚写人的数据。这里,我们不禁要问:为什么这些客户不把常用的(包括已写入的)数据保存在本地呢?如果刚写入某些数据,而且很可能会再用到这些数据,那么最好把它保存在本地。这种情况一个常见的例子是许多产品中的注册流程。通常,在把用户数据保存为永久注册记录之前,有一个阶段会把这些数据呈现给用户。另一个例子,是许多电子商务站点利用购物车实现的购买流程。无论哪哪种情况,如果你在写入的数据将来还会被用到,那么最好把它们在本地保留一份。关于如何进行缓存以及缓存哪些数据。
前面论述的重点是要得到一个结论,即重复操作会降低有效扩展的能力。事实上,它会造成事务成本加倍。因此,如果你的解决方案要规避由错误的写操作带来的几百万美金的损失,那可能需要几千万的额外基础设施作保障。根据我们的经验,即使在编程时间和基础设施上投资了,也没办法完全避免这种风险。在大多数情况下,写后即读的操作都是不好的,因为它不只让成本翻倍,限制了扩展性,而且还不能降低风险,从而使成本与收益不相称。毫无疑问,也许会有需要这种操作的地方,但是相比众多技术团队和公司验证过的最佳实践来说,这种情况少之又少。
细心的读者可能已经发现,我们的原则中存在冲突。需要本地存储的信息代表状态,肯定需要跟服务器保持一致才有用。从宏观角度说,我们同意这种说法,如果一定要做个选择,那么我们会只开发无状态的应用,以确保不会出现写后即读的操作。这说明,我们的原则是常规的,是“通常如此”的,而不是特定的或“唯一正确”的。绝对不要重复你的工作,绝对要维护大型的无状态应用。这两种说法有冲突吗?是的。那么冲突可以解决吗?当然要想解决这一原则冲突,就要站在很高的角度来看。我们既想让系统不浪费资源(如写后即读读),想让系统是无状态的。要实现这一点,我们决定绝对不会为了验证而读数据。我们也同意,有日时为了速度和扩展,我们也希望保持密切关系,而不去读刚写人的数据。这意味着需要维护一些状态信息,但是我们可以把它限制在某些事务中,在这些事务中读刚写入的数据是必要的。虽然这种方法有悖于我们介绍的原则,但是如果这种方法在有限的操作中引1人了状态,从而降低了成本,增加了扩展性,那么它也是可行的。
与所有原则一样,总有例外的情况。如果你存在于一个受控制的环境中,要求必须对10096的写入数据进行验证,然后加密、备份,你应该怎么做呢?我们不确定是否存在这样的环境,但是如果它存在,就一定要满足它的要求,例如不能阻止写后即读的操作。为了减少写后即读的操作且不阻止用户交易,下面列出了一个问题清单以及你能采用的步骤。
管理要求/法律要求。这个动作是管理要求或者法律要求的吗?如果是,你确定自己理解得正确吗?很少会有要求明确说你要做的与用户交易一致。即使这样说了,这样的要求也很少(可能是绝对不)适用于所有操作的。
竞争性差别。这个动作具有竞争性差别吗?请小心回答,如果答案是“是的”,那么这个答案太一般化了,而且通常是错误的。考虑到你所预计的错误发生的概率很小,你的竞争对手不进行次检查而造成的错误只占所有错误的0.001%,那么即使你正确规避了这些错误,也很难令人相信你能战胜对手。
异步完成。如果出于管理要求(虽然令人怀疑但仍是可能的)或竞争性差别(毫无疑问不可能),必须写后即读,那么可以考虑。
在本地写入,不中断交易。网站制作处理故障的方法很多,可以通过日志重建数据,然后再从处理队列中重新执行,最糟糕的情况是要求用户再输入一次数据,这种情况发生的概率很小。如果故障发生在为了实现高可用性而向远程数据备份复制数据的过程中,那么只需要重新申请那个记录或交易即可。在任何情况下,都不要因为要向两个数据源同步写入数据而中断用户交易。
>>> 查看《不要立即检查刚做过的工作》更多相关资讯 <<<
本文地址:http://nlpc.cn/news/html/3466.html