最近这段时间,我花了很多时间来更好的理解Hekaton——SQL Sever 2014里的全新内存表技术。我看了很多文章,了解了Haktaon的各种内部数据存储结构(主要是哈希索引和Bw-tree)。另外我也看了不少关于这方面的讲座。

但不止一次,有很多的误报,神话和误解出现,人们对Hektaton的认识发生了错误。从大家对Hekaton的提问就可以看出,我们需要整理Hekaton的知识,向大家重新传达它的相关知识,让大家更好的理解Hekaton,在Hekaton合适的场景来更好的使用它。

下面只是一些我罗列听到的大家关于Hekaton的问题:

  • “Hekaton是内存存储技术,是否意味着数据不再永驻?”
  • “Hekaton只在特定架构的CPU里可以运行?”
  • “当你迁移到Hekaton,对于你的工作量,你会获得100倍的性能提升?”
  • “在Hekaton里,没有锁,阻塞,自旋锁。”

这只是在过去我听到的误解中,头条的一部分。因此这篇文章的目的澄清这些最大误解和问题,我也会告诉你为什么它们是错误的。嗯,让我们从我的最头条开始(没特定顺序)!

“对于事务,Hekaton也提供ACID属性么?”

当我开始讨论Hekaton时,这个总是我第一个想澄清的:当你使用Hekaton时,对于你的事务,它还是有ACID属性的!Hekaton里的事务一直是有原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)的。SQL Server只是内部使用不同的概念和方法来保证这4个重要属性。

  • 原子性(Atomicity):对于你处理的事务,还是可以前滚(rolled forward)和后滚(rolled back),即使你的SQL Server崩溃,对于你启用Hekaton的数据库,SQL Server还是可以通过故障修复(crash recovery )(只要通过SQL Server重启,你的数据还是持续的(persisting )——下面会详细描述)
  • 一致性(Consistency):Hekaton也提供“总是”有一致的数据。这个在当前很容易做到,因为Hekaton的最大局限性之一是不能创建外键(Foreign-Keys),只能本身约束。因此基本上启用Hekaton的表,是在内部进行约束的。
  • 隔离性(Isolation):几天前,有人想说服我,Hekaton提供你脏读(Dirty Reads),因为没有锁和阻塞(Locking and Blocking)。错了!!!Hekaton使用所谓的多版本并发控制(Multi Version Concurrency Control ,MVCC)的方法,才有没锁的神奇可能。当你读取数据的时候,你取回的是在你开始的语句/事务后不在有效的数据(取决于使用的事务隔离级别(Transaction Isolation Level))。因此在Hekaton里没有脏读(Dirty Reads)。
  • 持久性(Durability):这个要分情况。当你使用架构和数据(DURABILITY=SCHEMA_AND_DATA)持久性创建你的Hekaton表,在SQL Server崩溃时,数据还是存在的。它会从事务日志里恢复,即Hekaton写的检查点文件。这点非常重要:当你想要你的数据持久时,Hekaton还是会使用事务日志,这也意味着你的事务日志是Hekaton的最后性能瓶颈之一。当和传统基于传统硬盘的表相比,Hekaton这里使用非常高效的日志模型。这里其中一个改变是,只有数据修改被日志,不是在索引级别。当你在基于传统硬盘表里执行INSERT,SQL Server需要为“每个”索引(聚集和非聚集索引)的INSERT日志。在Hekaton里,SQL Server只日志一次INSERT,因为在SQL Server启动期间,所有的Hekaton索引(哈希索引,范围索引)都会重建。因此对事务日志的影响是尽可能小的。

当你使用只有架构,不包含数据(DURABILITY = SCHEMA_ONLY)的Hekaton表时,你的Hekaton事务的持久性就没有了:当你的SQL Server崩溃了,或者你重启SQL Server,在Hekaton表里的所有数据会丢失。因此没有持久性。因此在事务日志里也没有日志记录。当然这个用法只在特殊场景里使用才有意义,例如为你的数据仓库进行数据加载。如果SQL Server崩溃,你就要重启你的ETL进程。你是可以重建你丢失的数据。

“Hekaton是微软提供的No-SQL方法?”

这个误解也非常有意思。有人想说服我说Hekaton是微软开发的No-SQL的新方法。得了吧,使用Hekaton我们还是在讨论有所有ACID属性的关系数据库(参阅刚才说的)。Hekaton和No-SQL是2个完全不同的东西,也没有共同点。Hekaton内部使用优雅而快速的方法来实现关系数据库的特性——就这样!

“Hekaton只在特定架构的CPU上运行?”

哇哦,我想我站错了地方!Hekaton只在特定模型/架构上运行,因为Hekaton内部使用所谓的原子CAS运算(原子比较与交换Atomic Compare & Swap, or Atomic Compare & Exchange)。那句话是完全错误的!当然,内部的Bw-tree使用CAS运算作为多个原子步骤做出树里SMOs(结构修改运算,Structure Modification Operations)。Hekaton这里内部使用“InterlockedCompareExchange”的WIN32 API函数。这个函数只在特定内存位置的值和原始值比较,如果2个一样的话,在内存位置会写入新值。函数本身在CPU级别作为一个原子汇编指令执行,意味着没有别的线程可以干涉那个汇编函数。它作为一个原子块(atomic block)从开始到结束执行。

这里的神话是,需要的汇编函数只在特定CPU架构上支持。这没错,但是这个汇编函数从奔腾处理器开始就支持了!在386和486架构上,函数本身是不支持的……从刚才提到的MSDN文章里的要求部分看到,支持的最低系统版本是Windows XP!因此当你在前Windows XP系统里安装SQL Server 2014时,这个神话倒是真的!

“在Hekaton里,没有锁,阻塞,自旋锁。”

理论上这句话是对的。这句话可以从不同方面辩论。我们从第1个方面开始。Hekaton“本身”是没有锁,阻塞和自旋锁的,但是你还是和SQL Server的传统关系引擎打交道。这就意味着,当你离开Hekaton宇宙时,你还是和基于原始代码的SQL Server打交道(对此,我表示遗憾……),例如事务日志管理器( Transaction Log Manager)。这些代码还是有闩锁(latches)和自旋锁(spinlocks)用来保持不同线程访问的同步。从这个角度来说,上述语句是部分正确的。

第2个方面在Hekaton里你还是有阻塞(blocking)的地方是,当你进行原子CAS操作时,一个原子CAS操作不能被不同的线程中断。因此在Bw-Trees里SMOs(结构修改运算,Structure Modification Operations)可以以聪明、优雅的方式实现。着也意味着当你想在同个Bw-Tree里的同个页里同时执行一个SMO是,一个线程会胜出,其他的线程需要重试原子CAS操作。同时发生了什么呢?线程会旋转,再次尝试CAS操作。我的基本理解是,原子CAS操作本身是就像一个Criticial Section同步概念包装的汇编函数。这就意味着你的线程需要旋转,你在丢失CPU周期,并增加了你事务的闭锁性。当然,SMOs应该非常非常少见,因此这没什么大不了的——但还是有线程旋转的可能,当有为底层同步对象(或者汇编函数)的竞争时。

这是我在原子CAS操作上的基本理解。如果我对此的理解是错误的,欢迎随时纠正我!

“因为在Hekaton里不支持INT IDENTITY值,使用序列(Sequences)?”

这句也非常有意思。我没有在吹嘘这句话!为什么?因为在你的SQL Server数据库里,序列(Sequences)是一个共享对象,意味着访问的当前值是由SQL Server同步的。这个同步在竞争中结束,意味着你不能延伸你的工作量,Hekaton的一切都是延伸工作量。

我用序列值在CTP1上做过一些测试,一旦你在你的Hekaton表/存储过程上执行大量的并行线程,你就会触发序列生成器(Sequence Generator)里的竞争。当然在一些内部页,序列生成器(Sequence Generator)存储着当前值,当序列生成器读写这些特定页时,就会发生闩锁(latch) 。在序列生成器里,你就用闩锁竞争(Latch Contention)结束它了,你的Hekaton工作量也不会延伸。在我的测试里也没太大区别,如果我请求整个范围的序列值,或者当我使用缓存,也没有区别。序列生成器始终是瓶颈。

那你如何克服这个特定问题?使用老好朋友UNIQUEIDENTIFIER。这些值彼此间是完全独立生成的,意味着当你生成新值时,没有涉及到共享资源,因此你可以剔除这个瓶颈,直到你触发CPU 的100%的使用率(包括像事务日志,网络带宽等其他瓶颈)前,Hekaton的工作量是可以不断延伸的。

“对于你的程序,Hekaton是完全透明的(is completely transparent)。”

这句话是对的,只要你对数据库设计没想法。我刚才已提过,在第1个发布里不能创建外键(Foreign-Keys)来检查约束。我从没看过任何基于磁盘的表,可以逐个迁移到内存优化表(Memory-Optimized table)。还记得么,INT IDENTITY 值目前尚不支持。当你迁移到Hekaton时,你做的不只是简单的切换来获得100倍的性能提升。抱歉!

“对于你的程序,Hekaton是完全透明的。”

这句话是对的,只要你对数据库设计没想法。我刚才已提过,在第1个发布里不能创建外键(Foreign-Keys)来检查约束。我从没看过任何基于磁盘的表,可以逐个迁移到内存优化表(Memory-Optimized table)。还记得么,INT IDENTITY 值目前尚不支持。当你迁移到Hekaton时,你做的不只是简单的切换来获得100倍的性能提升。抱歉!

“对于范围索引(Range Indexes),Hekaton使用传统的B+树结构。”

错!范围索引使用所谓的Bw-Tree,这个当前SQL Server为聚集和非聚集索引使用的B+树结构几乎一样。Bw-tree是基于B-Link tree——大家可能有点迷糊了,和传统的B+树相比,Bw-Tree有3个重大不同:

  • 中间层的页存储大范围的键值,在下一层的页存储小范围的键值。因为在页上存储了大范围的键值,Smos(例如页分裂)可以在2个原子操作实现(通过2个原子CAS执行)。这个概念来自于B-Link tree的设计原则。
  • 页“从不”改变,因此这个会导致CPU缓存线无效,这个会穿越传播到整个内存架构,这是非常昂贵的(在浪费CPU周期这方面)。当Hekaton需要改变内存中的页,不会接触到原始内存位置,Hekaton只创建一个新的Delta记录,这就是修改操作。所谓的”页面映射表(Page Mapping Table)“指向新的Delta记录,Delta记录对应的原始记录并未修改。因为这个方式CPU缓存线无效可以避免。
  • 页大小是弹性的,并不是一直的8kb大小。

“在数据库里,Hekaton提供你超快的业务逻辑。”

从微软观点来说这个是对的,因为自SQL Server 2012起SQL Server是在CPU核心层授权的。你用的CPU周期越多,需要的CPU就越多,你付给微软的授权就越多。但从架构观点来说是错的!数据库处理的是存储和获取数据,但是数据库不是一个应用服务器,应用服务器才处理业务……想想看。当你有CPU竞争时,因为你在数据库服务器里运行大量的业务逻辑,你应该重构你的数据库,因此你把你的业务逻辑移向专用的应用服务器,作为SQL Server的授权完全不一样——你为操作系统付钱,这就是错的原因!

“我如何迁移我的整个SAP数据库到Hekaton。微软对此有提供工具么?”

当你想把整个数据库迁移到Hekaton时,请先好好想想。Hekaton是用来解决特定问题的,像闩锁竞争(Latch Contention)。只有把特定的表和存储过程迁移到Hekaton时才有意义——并不是“所有”的数据库!对于每个数据库对象(表,存储过程),SQL Server需要把它们编译和链接成对应的DLL文件(然后载入sqlservr.exe的运行空间,这样要花费时间)。当你重启你的SQL Server时或者进行故障群集转移时,也会执行编译和链接。这会直接影响你HA方式的目标恢复时间(Recovery Time Objective,RTO)

小结

我希望已经帮你澄清了Hekaton的一些神话,误报和误解。而且我一直强调的是:如果是“对的”问题,Hekaton可以帮解决;如果你有传统的问题(错误的索引设计,糟糕的存储性能)果断放弃Hekaton吧,先做好你的家庭作业先。

Hekaton就像F1赛车:

你技术不好的话,F1赛车也帮不了你!

感谢关注,期待您的留言!

参考文章:

https://www.sqlpassion.at/archive/2013/11/30/myths-and-misconceptions-about-hekaton/

Hekaton的神话与误解的更多相关文章

  1. 第17/24周 悲观并发控制(Pessimistic Concurrency)

    大家好,欢迎回到性能调优培训.今天标志着第5个月培训的开始,这个月我们会谈论SQL Server里的锁.阻塞和死锁(Locking, Blocking, and Deadlocking). SQL S ...

  2. The Road to SDN: An Intellectual History of Programmable Networks

    文章名称:The Road to SDN: An Intellectual History of Programmable Networks 文章来源:Feamster N , Rexford J , ...

  3. 【论文】The Road to SDN: An Intellectual History of Programmable Networks

    目录 ABSTRACT: 1 Introduction: 2 The Road to SDN: 2.1 Active Networking Technology push and use pull I ...

  4. 软件项目发展历史<人月神话>这本书好

    几乎是计算机软件开发的发展历史     人月神话,增加人手并不一定能提高开发速度. 原因在于,有些任务是无法分解的,存在先后顺序.无法同步进行. 增加人手,增加的是沟通成本,相互牵制.可以分解的任务就 ...

  5. 《The Mythical Man-Month(人月神话)》读后感(2)

    第10章 未雨绸缪 在化学领域中,在实验室可以进行的反应过程,并不能在工厂中一步实现.一个被称为“ 实验性工厂(pilot planet)”的中间步骤是非常必要的,它会为提高产量和在缺乏保护的环境下运 ...

  6. 关于DevOps的七大误解,99%的人都曾中过招!

    [摘要] DevOps方法可以为组织带来显著的积极影响,降低成本.提高效率,使开发团队的工作更加精简.为了掌握这个过程的优势,有必要认识到DevOps是什么.不是什么.在本文中,就将讨论一些流传甚广的 ...

  7. 【原】谈谈对Objective-C中代理模式的误解

    [原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...

  8. .NET开源进行时:消除误解、努力前行(本文首发于《程序员》2015第10A期的原始版本)

    2014年11月12日,ASP.NET之父.微软云计算与企业级产品工程部执行副总裁Scott Guthrie,在Connect全球开发者在线会议上宣布,微软将开源全部.NET核心运行时,并将.NET ...

  9. 被误解的MVC和被神化的MVVM(转)

    转载自:http://www.infoq.com/cn/articles/rethinking-mvc-mvvm 原文作者:唐巧 被误解的 MVC MVC 的历史 MVC,全称是 Model View ...

随机推荐

  1. Android GPS 临近触发

    前面介绍过LocationManager有一个addProximityAlert(double latitude,double longitude,float radius,long expirati ...

  2. linux的库文件

    静态库和动态库 在windows中静态库是以 .lib 为后缀的文件,共享库是以.dll 为后缀的文件.在linux中静态库是以 .a 为后缀的文件,共享库是以 .so为后缀的文件. 以linux下的 ...

  3. 使用Installutil安装系统服务方法

    系统必须装有.net Framework2.0然后点击开始-运行输入以下指令即可完成相应操作安装服务:C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/Ins ...

  4. ELK——为调试 Logstash Grok 表达式,安装 GrokDebuger 环境

      内容 安装 RVM 安装 Ruby 和 Gems 安装 Rails 安装 jls-grok Ruby grok 解析 调试 grok 注意:不要用 root 执行以下操作. 用 logstash ...

  5. Oracle 11g RAC环境下Private IP修改方法及异常处理

    Oracle 11g RAC环境下Private IP修改方法及异常处理 Oracle 11g RAC环境下Private IP修改方法及异常处理 一. 修改方法 1. 确认所有节点CRS服务以启动 ...

  6. Vim 练级攻略

    以下的文章翻译自<Learn Vim Progressively>,我认为这是给新手最好的VIM的升级教程了,没有列举全部的命令,仅仅是列举了那些最实用的命令. 很不错. -------- ...

  7. 云计算的三层SPI模型

    (转自:http://hi.baidu.com/fengjun8216/item/b15bbef4dcf74049922af27b) 一般而言,云计算架构可以用三层SPI模型来表述. 一.基础设施即服 ...

  8. [原创]Android Handler使用Message的一个注意事项

    最近发现了一个莫名其妙的问题,在使用Handler.post(Runnable)这个接口时,Runnable有时候没有运行,非常奇怪,后来发现是因为调用Handler.removeMessage()时 ...

  9. 给MySQL官方提交的bug report备忘

    1.  Bug #72215 When LOCK_plugin conflicts very much, one uninstall-audit-plugin operation crash  htt ...

  10. Java的wait(), notify()和notifyAll()使用小结

    wait(),notify()和notifyAll()都是java.lang.Object的方法: wait(): Causes the current thread to wait until an ...