• [参赛经验分享] 2019华为云数据库TaurusDB性能挑战赛亚军参赛总结
    大家好,我们是watermelon团队,今天我们的答辩展示主要分为四个部分来介绍。首先是我们的团队和成员的简介然后是我们对这次题目重点的理解接下来,我会介绍一下我们最基础的架构,包括网络、磁盘、缓存等最后,重点介绍我们每一个性能优化点团队名叫watermelon,我们三个人都是在读的研究生,分别来自浙江大学和上海交通大学,都是明年毕业。初赛和复赛的成绩都是第四名,历史成绩非常的稳定。我们总结了几个题目重点:首先,KV 都是定长的:这样简化了⽂件和内存的操作和管理。第二点,value远大于key:把 KV 分离存储,解除索引和数据之间的耦合性。第三点,线程数固定:测评程序固定使用 16 个线程访问数据库。第四点,只需要保证进程意外退出时的持久性:所以可以利用操作系统的缓存对写入方式进行一些优化。第五点,分阶段测评:随机写、随机读、顺序读三个阶段互相没有重叠。第六点,计算节点无状态:我们知道,在这种基于共享存储的计算存储分离架构下,所有持久化数据只能存于存储节点,计算节点只进行逻辑操作。第七点,数据读取的线程和数据写入线程之间没有绑定关系:就是说,每个线程不是只读取自己写入的数据。  //与初赛不一样,读取线程id不一读的是相同id写入的数据最后一点,随机读的随机性在每个时刻只局限在一个 10M 热点分区内:并且热点分区按写入的顺序逆序推进。 下面是我们方案的核心架构:    我们计算节点和存储节点的线程采用一对一的tcp连接,因为测评程序是16线程,所以连接数就是16。在存储节点,我们有数据持久化产生的文件,以及读写文件的缓存。在计算节点,我们维护了读数据的缓存,但是没有写数据的缓存,因为要保证计算节点被 kill 的数据持久性。并且我们的索引也是只在计算节点上维护的,在数据库启动阶段从存储节点把索引数据拉到计算节点。接下来,具体介绍一下我们的文件组织形式:首先,按写入线程进行数据的分区,就是说,每个写入线程只顺序写自己的分区文件,这样就避免了多线程写同一个文件冲突的问题。然后,在每个分区内,将 key 和 value 分离存储为两个文件,一个是key log,一个是value log。可以解除索引和数据之间的耦合性。并且我们为了提高写入value 的速度,对 value 进行了缓存,缓存中凑齐若干个value后,再一起进行刷盘。为了保证缓存不丢失,缓存也使用了mmap的形式,因此对应有一个缓存文件。我们的索引也是按分区进行构建的,每个分区是一个hash,里面存的是该分区所有数据的索引项,索引项就是一个 key 和 一个value offset复赛的优化历程,我们从最开始跑通的 2300 分,到最后的 780 分,中间经过了好几次架构和方法的改变。首先我们的第一个优化是,我们在启动阶段把 key 从存储节点批量的传到计算节点,这样相比每个 key 都请求一次,批量的方法相当于减少了一半的网络请求,使得时间提升了 300 秒。接下来,由于我们无法搞定网络传输大数据包的问题,因此我们选择先在存储节点实现顺序读和随机读的缓存,这样减少了存储节点的 io 次数,时间提升了 500s再后来,我们解决了网络传输的问题,所以先在计算计算节点进行了顺序读的缓存,成绩提升到 1100s这样紧接着,我们按存储节点缓存一样的思路,把随机读缓存也拿到了计算节点,这样做之后我们的成绩就已经突破了 800s在最后阶段,我们又优化了一些细节问题,最终成绩是 781s围绕读写文件,缓存策略,和网络传输这三个方面,来讲解我们是如何把这个系统的性能压榨到极致的。对于 key 这种小数据量的读写模式,采用 mmap 可以利用 page cache 将小数据读写转换为整个内存页的读写,减少了系统调用的时间消耗。value 的大小为固定 4KB,我们知道,写入数据大小要对齐 ssd 的内部 page 时,可以达到最优写入性能。我们经过线上测试,按 1M 大小顺序写入数据可以达到最大吞吐量。所以,为每一个分区分配一个容量为 1M 的写缓冲区,写满 256 个 value 再将缓存数据一起刷盘,刷盘方式采用 direct io。并且,用 mmap 做缓存,可以保证数据持久性。第二点,我们来看,如何做随机读的缓存,使得缓存命中率最高。现在背景是,随机读在每个时刻只局限在一个 10M 热点分区内,并且热点分区按写入的顺序逆序推进。看图,上面是我们实际存储的文件,按10M分为了若干个block,就是说,我们的缓存只能按 block 对齐进行加载数据。然后,下面是测评的热点分区示意图,我们发现一共 400w 数据,热点分区的边界跟实际数据 10M 边界很可能是不对齐的,并且边界值未知。所以,如果我们只用单个 10M 的缓存,会出现下面这样的问题。假设当前阶段,测评程序要随机访问 hot1 这个热点分区。第一个位置,我们缓存加载了block3,然后,访问第二个位置,发现缓存失效,加载了block2,继续访问第三个位置,缓存又失效了,重现加载回了block3所以,这样就产生了一个缓存来回震荡的问题,极端情况是,我要访问400万数据,一共要加载400万次大块的缓存,肯定超时,还不如不做缓存。我们的方案是,采用两个 10M 的buffer,一前一后,一起往前推进,这样非常完美了避免了缓存来回震荡的问题。并且这个 buffer 不一定是10M,只要大于10M都可以解决这个问题。第三点,我们来看,如何使得网络的传输效率最高。我们发现,写入阶段的网络传输时间主要瓶颈是在周转时间上,也就是说,不是网络有多么拥塞导致网络传输变慢,而是说,value发过去再回来,本身就需要这么长的时间。所以我们的优化只能是让存储节点尽可能快的返回ack信号,我们的做法是在数据写入存储节点的mmap之后,就返回ack,而不用等待page cache 刷盘。对于持久性,recover 阶段会把 cachebuffer 里面的数据都重新写进 value 文件里。对于大块数据进行拆分,然后进行多次发送,可以在发送的同时进行流量控制,使吞吐量保持在一个较高的水平。我们的流量控制方法非常简单粗暴,在发送每两个 4k 数据之间,直接加一个延时,延时的方法是让 CPU 自旋一会。并且,存储节点也做了读缓存,把存储节点的读缓存,批量拆分传到计算节点。最后,回到一个宏观的位置上来看,通过这次比赛,我们严格按照计算存储分离的思想来设计了我们的系统架构。对基于共享存储的计算存储分离架构有了一些认知和理解。首先,我们看计算节点我们的架构只支持一个 RW 节点,进行数据的写入。但是 RO 节点在理论上是可以无限扩展的。并且,由于底层的共享存储,所以主从复制的延迟可以做到非常低。当 RW 写入一个 kv 数据,对于 RO 节点,它只需要更新已经存在自己 buffer pool 中的数据,而如果发现 RW 写入的数据不在它的 buffer pool 中,那它什么也不做。只有在 RO 节点读取数据时,发现要请求的数据不在自己的buffer pool中,它才去下面的存储节点中拉取这个数据到自己的 buffer pool 中。这样看来,我们在实现高可用功能时候,可以很直接的进行主从切换,RO 节点可以迅速提升为 RW 节点,直接开始对外服务。再看存储节点我们当前只是在单个节点上保证了数据的持久性,而这种 kv 存储可以扩展为分布式架构,采用多副本存储,从而能获得更好的容错性,和更好的读写性能。所以这样一整套架构,可以解决很多实际的痛点,因此,会成为当今云数据库的一个趋势。
  • [参赛经验分享] 2019华为云数据库TaurusDB性能挑战赛季军赛题总结
    1 前言回顾第一次参加性能挑战赛—第四届阿里中间件性能挑战赛,那时候真的是什么都不会,只有一腔热情,借着比赛学会了 Netty、学会了文件 IO 的最佳实践,到了这次华为云举办的 TaurusDB 性能挑战赛,已经是第三次参加比赛了,同时也是最“坎坷”的一次比赛。经过我和某位不愿意透露姓名的 96 年小迷妹的不懈努力,最终跑分排名为第 3 名。如果要挑选一个词来概括这次比赛的核心内容,那非”计算存储分离“莫属了,通过这次比赛,自己也对计算存储分离架构有了比较直观的感受。为了比较直观的体现计算存储分离的优势,以看电影来举个例子:若干年前,我总是常备一块大容量的硬盘存储小电影,但自从家里带宽升级到 100mpbs 之后,我从来不保存电影了,要看直接下载/缓冲,基本几分钟就好了。这在几年前还不可想象,如今是触手可及的事实,归根到底是随着互联网的发展,网络 IO 已经不再是瓶颈了。计算存储分离架构相比传统本地存储架构而言,具有更加灵活、成本更低等特性,但架构的复杂性也会更高,也会更加考验选手的综合能力。计算存储分离架构的含义:存储端有状态,只存储数据,不处理业务逻辑。计算端无状态,只处理逻辑,不持久化存储数据。2 赛题概览比赛整体分成了初赛和复赛两个部分,初赛要求实现一个简化、高效的本地 kv 存储引擎,复赛在初赛的基础上增加了计算存储分离的架构,计算节点需要通过网络传输将数据递交给存储节点存储。计算节点和存储节点共用上述的接口,评测程序分为 2 个阶段:正确性评测此阶段评测程序会并发写入随机数据(key 8B、value 4KB),写入数据过程中进行任意次进程意外退出测试,引擎需要保证异常中止不影响已经写入的数据正确性。异常中止后,重启引擎,验证已经写入数据正确性和完整性,并继续写入数据,重复此过程直至数据写入完毕。只有通过此阶段测试才会进入下一阶段测试。性能评测随机写入:16 个线程并发随机写入,每个线程使用 Set 各写 400 万次随机数据(key 8B、value 4KB)顺序读取:16 个线程并发按照写入顺序逐一读取,每个线程各使用 Get 读取 400 万次随机数据热点读取:16 个线程并发读取,每个线程按照写入顺序热点分区,随机读取 400 万次数据,读取范围覆盖全部写入数据。热点的逻辑为:按照数据的写入顺序按 10MB 数据粒度分区,分区逆序推进,在每个 10MB 数据分区内随机读取。随机读取次数会增加约 10%。语言限定CPP & Java,一起排名3 赛题剖析初赛主要是文件 IO 和存储架构的设计,实现一个简单的本地KV存储引擎,如果对文件 IO 常识不太了解,可以先行阅读 《文件IO操作的一些最佳实践》。大赛的重头戏基本是在复赛网络通信的比拼上,在引入计算/存储分离架构后,计算节点无状态,计算节点和存储节点需要通过网络交互,网络将引入大于服务器内部的时延,因此,结合应用场景的良好架构和缓存设计,将是此类引擎设计的一个重点。3.1 架构设计计算节点只负责生成数据,在实际生产中计算节点还承担额外的计算开销,由于计算节点是无状态的,所以不能够聚合数据写入、落盘等操作,但可以在 Get 触发网络 IO 时一次读取大块数据用作缓存,减少网络 IO 次数。存储节点负责存储数据,考验了选手对磁盘 IO 和缓存的设计,可以一次使用缓存写入/读取大块数据,减少磁盘 IO 次数。所以选手们将会围绕网络 IO、磁盘 IO 和缓存设计来设计整体架构。3.2 正确性检测赛题明确表示会进行 kill -9 并验证数据的一致性,正确性检测主要影响的是写入阶段。存储节点负责存储数据,需要保证 kill -9 不丢失数据,但并不要求断电不丢失,这间接地阐释了一点:我们可以使用 PageCache 来做写入缓存;正确性检测对于计算节点与存储节点之间通信影响便是:每次写入操作都必须 ack,所以选手必须保证同步通信,类似于 ping/pong 模型。3.3 性能评测性能评测由随机写、顺序读、热点读(随机读取热点数据)三部分构成。随机写阶段与 PolarDB 的评测不同,TaurusDB 随机写入 key 的 16 个线程是隔离的,即 A 线程写入的数据只会由 A 线程读出,可以认为是彼此独立的 16 个实例在执行评测,这大大简化了我们的架构。顺序读阶段的描述也很容易理解,需要注意的是这里的顺序是按照写入顺序,而不是 Key 的字典序,所以随机写可以转化为顺序写,也方便了选手去设计顺序读的架构。热点读阶段有点故弄玄虚了,其实就是按照 10M 数据为一个分区进行逆序读,同时在 10M 数据范围内掺杂一些随机读,由于操作系统的预读机制只会顺序预读,无法逆序预读,PageCache 将会在这个环节会失效,考验了选手自己设计磁盘 IO 缓存的能力。4 架构详解4.1 全局架构计算存储分离架构自然会分成计算节点和存储节点两部分来介绍。计算节点会在内存维护数据的索引表;存储节点负责存储持久化数据,包括索引文件和数据文件;计算节点与存储节点之间的读写都会经过网络 IO。4.2 随机写架构随机写阶段,评测程序调用计算节点的 set 接口,发起网络 IO,存储节点接收到数据后不会立刻落盘,针对 data 和 index 的处理也会不同。针对 data 部分,会使用一块缓冲区(如图:Mmap Merge IO)承接数据,由于 Mmap 的特性,会形成 Merge File 文件,一个数据缓冲区可以聚合 16 个数据,当缓冲区满后,将缓冲区的数据追加到数据文件后,并清空 Merge File;针对 index 部分,使用 Mmap 直接追加到索引文件中。F: 1. data 部分为什么搞这么复杂,需要聚合 16 个数据再刷盘?Q: 针对此次比赛的数据盘,实测下来 16 个数据刷盘可以打满 IO。F: 2. 为什么使用 Mmap Merge IO 而不直接使用内存 Merge IO?Q: 正确性检测阶段,存储节点可能会被随机 kill,Mmap 做缓存的好处是操作系统会帮我们落盘,不会丢失数据F: 3. 为什么 index 部分直接使用 Mmap,而不和 data 部分一样处理?Q: 这需要追溯到 Mmap 的特点,Mmap 适合直接写索引这种小数据,所以不需要聚合。4.3 热点读&顺序读架构热点读取阶段 & 顺序读取阶段 ,这两个阶段其实可以认为是一种策略,只不过一个正序,一个逆序,这里以热点读为例介绍。我们采取了贪心的思想,一次读取操作本应该只会返回 4kb 的数据,但为了做预读缓存,我们决定会存储节点返回 10M 的数据,并缓存在计算节点中,模拟了一个操作系统预读的机制,同时为了能够让计算节点精确知道缓存是否命中,会同时返回索引数据,并在计算节点的内存中维护索引表,这样便减少了成吨的网络 IO 次数。4.4 存储设计站在每个线程的视角,可以发现在我们的架构中,每个线程都是独立的。评测程序会对每个线程写入 400w 数据,最终形成 16 * 16G 的数据文件和 16 * 32M 左右的索引文件。数据文件不停追加 MergeFile,相当于一次落盘单位是 64K(16 个数据),由于自行聚合了数据,所以可以采用 Direct IO,减少操作系统的 overhead。索引文件由小数据构成,所以采用 Mmap 方式直接追加写计算节点由于无状态的特性,只能在内存中维护索引结构。4.5 网络通信设我们都知道 Java 中有 BIO(阻塞 IO)和 NIO(非阻塞 IO)之分,并且大多数人可能会下意识觉得:NIO 就是比 BIO 快。而这次比赛恰恰是要告诉大家,这两种 IO 方式没有绝对的快慢之分,只有在合适的场景中选择合适的 IO 方式才能发挥出最佳性能。稍微分析下这次比赛的通信模型,写入阶段由于需要保证每次 set 不受 kill 的影响,所以需要等到同步返回后才能进行下一次 set,而 get 本身依赖于返回值进行数据校验,所以从通信模型上看只能是同步 ping/pong 模型;从线程数上来看,只有固定的 16 个线程进行收发消息。以上两个因素暗示了 BIO 将会非常契合这次比赛。在很多人的刻板印象中,阻塞就意味着慢,非阻塞就意味着快,这种理解是完全错误的,快慢取决于通信模型、系统架构、带宽、网卡等因素。我测试了 NIO + CountDownLatch 和 BIO 的差距,前者会比后者整体慢 100s ~ 130s。5 细节优化点5.1 最大化磁盘吞吐量但凡是涉及到磁盘 IO 的比赛,首先需要测试便是在 Direct IO 下,一次读写多大的块能够打满 IO,在此基础上,才能进行写入缓冲设计和读取缓存设计,否则在这种争分夺秒的性能挑战赛中不可能取得较好的名次。测试方法也很简单,如果能够买到对应的机器,直接使用 iostat 观察不同刷盘大小下的 iops 即可,如果比赛没有机器,只能祭出调参法,不停提交了,这次 TaurusDB 的盘实测下来 64k、128K 都可以获得最大的吞吐量。5.2 批量回传数据计算节点设计缓存是一个比较容易想到的优化点,按照常规的思路,索引应该是维护在存储节点,但这样做的话,计算节点在 get 数据时就无法判断是否命中缓存,所以在前文的架构介绍中,我们将索引维护在了计算节点之上,在第一次 get 时,顺便恢复索引。批量返回数据的优势在于增加了缓存命中率、降低总网络 IO 次数、减少上行网络 IO 数据量,是整个比赛中分量较重的一个优化点。5.3 流控在比赛中容易出现的一个问题,在批量返回 10M 数据时经常会出现网络卡死的情况,一时间无法定位到问题,以为是代码 BUG,但有时候又能跑出分数,不得以尝试过一次返回较少的数据量,就不会报错。最后还是机智的小迷妹定位到问题是 CPU 和 IO 速率不均等导致的,解决方案便是在一次 pong 共计返回 10M 的基础上,将报文拆分成 64k 的小块,中间代入额外的 CPU 操作,最终保证了程序稳定性的同时,也保障了最佳性能。额外的 CPU 操作例如:for(int i=0;i<700;i++),不要小看这个微不足道的一个 for 循环哦。流控其实也是计算存储分离架构一个常见设计点,存储节点与计算节点的写入速度需要做一个平衡,避免直接打垮存储节点,也有一种”滑动窗口“机制专门应对这种问题,不在此赘述了。5.4 预分配文件在 Cpp 中可以使用 fallocate 预先分配好文件大小,会使得写入速度提升 2s。在 Java 中没有 fallocate 机制,但是可以利用评测程序的漏洞,在 static 块中事先写好 16 * 16G 的文件,同样可以获得 fallocate 的效果。5.5 合理设计索引结构get 时需要根据 key 查询到文件偏移量,这显示是一个 Map 结构,在这个 Map 上也有几个点需要注意。以 Java 为例,使用 HashMap 是否可行呢?当然可以,但是缺点也很明显,其会占用比较大的内存,而且存取性能不好,可以使用 LongIntHashMap 来代替,看过我之前文章的朋友应该不会对这个数据结构感到陌生,它是专门为基础数据类型设计的 Map 容器。每个线程 400w 数据,每个线程独享一个索引 Map,为了避免出现扩容,需要合理的设置扩容引子和初始化容量:new LongIntHashMap(410_0000, 0.99)。5.6 Direct IO最终进入决赛的,有三支 Java 队伍,相比较 Cpp 得天独厚的对操作系统的灵活控制性,Java 选手更像是带着镣铐在舞蹈,因为有过参赛经验,我提前封装好了 Java 的 Direct IO 类库:https://github.com/lexburner/kdio,相比 FileChannel,它能够使得磁盘 IO 效率更高。得知有 Java 选手真的在比赛中使用了我的 Direct IO 类库,也是比赛中实实切切的乐趣之一。6 失败的优化点6.1 预读线程先行考虑到网络 IO 还是比本地磁盘 IO 要慢的,一个本以为可行的方案是单独使用预读线程进行存储节点的磁盘 IO,设计一个 RingBuffer,不断往前预读,直到环满,计算阶段 get 时会消费 RingBuffer 的一格缓存,从而使得网络 IO 和磁盘 IO 不会相互等待。实际测试下来,发现瓶颈主要还是在于网络 IO,这样的优化徒增了不少代码,不利于进行其他的优化尝试,最终放弃。6.2 计算节点聚合写入缓冲既然在 get 阶段时存储节点批量返回数据给计算节点可以提升性能,那 set 阶段聚合批量的数据再发送给存储节点按理来说也能提升性能吧?的确如此,如果不考虑正确性检测,这的确是一个不错的优化点,但由于 kill 的特性使得我们不得不每一次 set 都进行 ACK。但是可以将 4/8/16 个线程编为一组进行聚合,通过调整参数来确定该方案是否可行。然而事与愿违,该方案并没有取得成效。7 聊聊比赛吧之前此类工程性质的性能挑战赛只有阿里一家互联网公司承办过,作为热衷于中间件性能优化的参赛选手而言,非常高兴华为也能够举办这样性质的比赛。
  • [参赛经验分享] 2019华为云数据库TaurusDB性能挑战赛季军参赛总结
    赛题分析赛题要求一个无状态的计算节点和一个存储节点,并要求保证程序崩溃时的数据完整性,所以当计算节点写入时必须等待存储节点的 ack,而存储节点需快快确保数据写入到 page cache。赛题说明 16 个线程,每个线程写入 4 百万条记录,按写入顺序读取及热点区间读取,所以数据按写入线程分离存储。此外 Key 大小固定 8B,value 大小固定 4KB,所以需要批量写入才能打满带宽,并且索引只需要保存位置序号就可以,减小了索引的大小。整体架构针对赛题的要求,可以把问题分解成三个模块来看,分别是计算节点,存储节点和网络通信,因此我们设计了如下图所示的总体结构。在存储节点上,数据分为 16 组存储,按照写入线程分组,保证同一线程的数据写入到同一分组,这样在读取阶段不论是按写入顺序读取还是热点区间读取都可以一次从一个分组中读取一整块 cache,降低网络开销,另外这样并发管理也比较简单,因为一个线程只会对应到一个文件,所以读写的时候是不需要对分组加锁的。具体到到每个分组内部,key 和 value 是分离存储的,因为 key 和 value都是定长的,kv 分离以后恢复索引时只需要读取 key 文件就够了。最后存储节点会保证一旦写入成功数据就不会再丢失,也就是可以容忍 kill -9 退出。我们把索引放在计算节点,并且使用 TCP 进行节点间通信。由于并发数目不高,所以计算节点初始化时创建 16 条 tcp 连接,每个前台线程对应一条连接,在存储节点为每个 tcp 连接创建一个新线程。数据在写入时首先由计算节点发送写请求到存储节点,存储节点收到请求并确认数据成功写入不会丢失后,会把存储的位置回复给计算节点,然后计算节点把位置代入内存索引后返回。读取时计算节点首先根据内存索引判断数据在不在 cache pool 里,如果不在就去向存储节点读取一块新的 cache,然后从 cache 中读数据。存储节点之前我们也提到存储节点按写入线程分组,每个分组里包含四类文件,value data 文件保存 value,key data文件保存 key,两者各有一个 mmap buffer 文件,用来将写入 batch 到一起再刷盘。然后有一个全局的 mmap meta file,记录各个分组当前的数据长度,也就是各分组分别有多少个 kv 对,主要用于数据恢复和重建索引。数据写入时直接将key和value写入对应分组的mmap buffer,两者都写入成功后更新 meta file。只有当 mmap buffer 写满了以后才会 flush 到磁盘中,并且 flush 操作都是用 directIO 进行的。采用这种设计使得写入均是内存操作,将数据写入到 mmap 管理的 page cache 中即可返回,并且我们对mmap使用了mmap_lock标记使其一直锁定在内存中,只有当程序退出时才会刷盘。每次向data文件刷盘都是以一个 buffer 为单位,这样可以最大化利用 nvme 磁盘带宽,采用 directIO 的方式刷盘可以跳过 page cache,一方面减少了一次内存复制,另一方面降低了阶段切换时清空 page cache 的时间。而 mmap 的机制保障了即使进程意外退出,操作系统也会让 mmap buffer 中的数据安全落盘,不会引起数据丢失。我们实际为每个 key 和 data 文件维护了多个 mmap buffer,当一个 buffer 写满时转入后台 flush,接下来的写入会写进另一个 buffer。这是因为写入操作的开销是由网络传输开销和磁盘 IO 开销两部分组成的,单个buffer的情况下两者完全串行执行,在发生刷盘时写入操作需要消耗网络传输加上磁盘IO的时间。采用多个 buffer 以后相当于将磁盘 IO 与网络开销并行化了,产生的阻塞会减少很多。对于数据读取操作,读请求会将 offset 对齐到 cache 长度,也就是 10MB,然后存储节点直接以 directIO 方式从对齐后的 offset 处读出这一块数据返回即可。当存储节点意外关闭时,因为我们已经确保了所有数据都能安全落盘,唯一需要恢复的就是 mmap buffer 文件当前的写入位置,所以只需要从 meta file 中读取个分组的长度,对 buffer 长度取余便可以计算出各 buffer 的当前写入位置了。计算节点计算节点中主要包含了索引和 cache 两部分。索引部分,索引存储在 hash 表中,每个 entry 的格式为 (key, 分组编号+分组内偏移量)。因为 key 和 value 都是大小固定的,因此偏移量只需要保存它是分组内的第几个 kv 对,所以只需要 4 字节。因此每个 entry 的空间占用为 key 8字节加分组编号 4 字节加偏移量 4 字节,总共 16 字节,那么 6400 万个 entry 一共需要大约 1G 左右空间,因此可以完全保存在内存里。我们实现了一个原子的 hash 表。hash 表底层是一个大小为 8000 万左右的数组,以线性探测法处理 hash 冲突。说hash表的每一个 entry 由两个 64 位无符号整数组成,分别代表 key 与索引,并初始化为0。因为 key 本身可能是0,所以我们让分组编号从1开始,然后对索引部分的原子变量做 cas 操作来实现原子代入。代码如下:因为计算节点本身是无状态的,所以重启时需要恢复索引。我们把索引恢复的时机放在第一次 get 操作的时候,这样可以避免写入阶段计算节点请求恢复索引。索引恢复由 16 个线程并行执行,每一个线程向存储节点请求一整个 key 文件,因为 key 在 key 文件中的位置与 value 在 value 文件中的位置是一样的,所以遍历 key 文件就可以重建索引了。如果每次 get 都去存储节点读取,那么网络延迟开销太大,无法打满带宽。所以我们每次向存储节点请求数据时都读取一整块数据保存在内存 cache 里,大小为 10MB。由于我们不确定是不是完全按照 10MB 对齐的,因此我们为每个分组准备了两个 cache,这样当 cache miss 时,可以保证前一块 cache 的数据一定已经被读完了,可以被新的 cache 置换掉。此外我们还实现了 cache 预取机制。由于赛题要求顺序读取及热点区间读取,热点区间读取是按照数据的写入顺序以 10MB 数据粒度分区,分区逆序推进,在每个 10MB 数据分区内随机读取,所以当向存储节点请求一个新 cache 完成时,另一个线程会根据当前两个 cache 的 offset 之差向存储节点预取下一块 cache。在顺序读取阶段差为整数,因此会顺序预取,在热点区间读取阶段差为负数,因此会逆序预取。总结我们的最好成绩是 786 秒,其中写用了 505 秒,顺序读取用了 134 秒,热点读取用了 147 秒,最终排名第 5 名。此外各阶段分别跑出的最佳成绩为505/132/142秒,可惜我们对读操作的优化是最后一天完成的,但是最后一天的评测环境不太好,写性能一直上不去(我们的写入时间基本稳定在520秒以内,但是最后一天一直在560秒+)。在热点读阶段实际消耗在读取上的时间为133秒,但是恢复索引使用了9 秒,这里还有很大的改进空间。考虑到评测系统的带宽大约15Gbps,我们的读取性能已经基本跑满网络带宽了。第一次参加这种类型的比赛,我们学习和积累了很多经验,希望来年还有机会参加,取得更好的成绩。 
  • [参赛经验分享] 2019华为云数据库TaurusDB性能挑战赛优秀选手参赛总结
    1、前言华为云TaurusDB结束有一段时间了,这几天抽时间写一下参赛总结,我是从阿里第三届中间件比赛开始参加类似比赛的,TaurusDB这次是第三次,虽然有过两次参赛经验,但是数据库比赛还是第一次,报名也是无意中看到朋友在朋友圈的分享,正好想要学习一下数据库相关知识,于是报名参加了比赛,熬了无数个夜晚,很幸运最终以第10名的成绩擦边入围,主要还是cpp大佬和其他选手承让^_^。2、赛题回顾比赛分成了初赛和复赛两个部分,初赛要求实现一个简化、高效的本地 kv(为简化开发,K固定大小8B,V固定大小4KB)存储引擎,其中每个KVStore为一个实例,每个线程操作独立的KV实例,线程间互不影响,复赛在初赛的基础上增加了计算存储分离的架构,计算节点需要通过网络传输将数据递交给存储节点存储。程序主要提供三个接口:评测程序分为2个阶段正确性评测此阶段评测程序会并发写入随机数据(key 8B、value 4KB),写入数据过程中进行任意次进程意外退出测试,引擎需要保证异常中止不影响已经写入的数据正确性。异常中止后,重启引擎,验证已经写入数据正确性和完整性,并继续写入数据,重复此过程直至数据写入完毕。只有通过此阶段测试才会进入下一阶段测试。性能评测随机写入:16个线程并发随机写入,每个线程使用Set各写400万次随机数据(key 8B、value 4KB)。顺序读取:16个线程并发按照写入顺序逐一读取,每个线程各使用Get读取400万次随机数据。热点读取:16个线程并发读取,每个线程按照写入顺序热点分区,随机读取400万次数据,读取范围覆盖全部写入数据。热点的逻辑为:按照数据的写入顺序按10MB数据粒度分区,分区逆序推进,在每个10MB数据分区内随机读取,随机读取次数会增加约10%。评测环境计算节点:内存占用不得超过4G(CPP), 5G(JAVA),不得写入和读取磁盘空间。存储节点:内存占用不得超过2G(C++),3G(JAVA),磁盘占用不得超过320G。注:后台将CPU统一限制为16核。语言限定CPP & Java,一起排名3、赛题分析拿到赛题后首先我们对赛题已知条件做下分析:数据总量为4M*16(64M)条数据Key数据总量为64M*8(B),索引可以完全加载到内存定长Key(8B)和Value(4KB)极大简化索引构建和写入缓存设计读取分为顺序和逆序遍历(10M内随机)可以考虑使用LRU作为缓存策略kill -9保证数据不丢需使用mmap保证数据最终落盘因为我们比系统更了解程序的缓存策略读写考虑使用DirectIO+自管理缓存计算存储分离可以把存储节点当作一块磁盘对外提供read, write接口,把索引构建及索引查找放到计算节点因为DB是分布式的应考虑使用大块网络传输来减少rtt带来的性能损耗可以看出此次大赛的核心考察点是计算存储分离,因为计算量不大,存储介质性能又非常强悍,程序的瓶颈可能是在网络层面,如何高效利用网络是本次比赛重点思考内容。4、程序设计4.1 功能设计首先要考虑的是功能评测,即保证kill -9数据不丢,因为一个程序只有功能正确才能谈性能,保证kill -9数据不丢有两种方式,第一种是来一条数据写一次盘,每条数据都即时落盘,这个方式虽然可以保证数据不丢,但是性能堪忧,好在操作系统给我们提供了另一种方式mmap(memory mapping),通过mmap可以将文件直接映射到user内存区,user可以直接操作这块内存,程序可以通过主动(force)或者被动(程序结束或崩溃)方式将内存中的数据持久到磁盘,这个过程不经过kernel内存区,省去一次内存拷贝,同时也保证了数据安全。保证了存储节点数据不丢后下面要考虑在有网络传输的情况下数据不丢,如果允许数据丢失则可以使用异步io方式传输数据,但是要保证数据不丢则计算机点需要一直阻塞直到存储节点数据落盘并返回ack后计算节点set方法才能返回,这样网络模型为PING/PONG模型。4.2 文件分布设计因为程序是多实例数据库,实例之间互不干扰,这里没有对数据进行分片操作,其实换一个角度看我们可以把每个实例看作一个数据库分片,因为分片的目的是为了让分片之间互不干扰,提高程序并行能力,每个实例(分片)内的写操作都比较简单,采用追加写的方式。每个实例包含3个文件: MergeIO(mmap):merge io索引文件(mmap):Key实际存储文件数据文件:Value实际存储文件写入Value时先写入MergeIO文件,Merge满后批量写入数据文件,即使程序被kill,也可以从MergeIO文件恢复Value数据。这里感谢一下徐靖峰(岛风)同学开源的kdio(java操作DirectIO的库)4.3 索引设计数组二分查找:构建索引时需要排序,单点查询对cpu分支预测不友好,但是方便进行范围LongIntMap(开放寻址法):可以动态构建索引,单点查询可快速定位(key冲突量不大时),难以范围查询因为这里考虑只有单点get没有范围查询,所以用了LongIntMap 4.4 读取设计读取采用LRU算法对数据进行缓存读取,每个LRU Item包含4M Value数据(1K个Value,参数可调)每个实例包含14个LRU Item,包含4M(总消息数)/1K个空Item,比如说通过Key找到Index为1,对1取模得到缓存位置0,因为缓存已存在则直接使用item.get(),如果Index为1024,因为缓存不存在,则根据缓存最后访问时间找到需要失效的缓存,通过read方法从存储节点读取该缓存的内容,然后get出结果。4.5 网络传输设计存储节点:存储节点采用Epoll EventLoop模式,节点启动16条线程,计算节点与存储节点tcp连接均匀分布在16条线程上,后面数据交互均在固定线程完成,充分利用多核优势。计算节点:计算节点采用bio方式与存储节点建立连接,计算节点与存储节点交互均采用req/res阻塞模式交互。计算节点从存储节点read数据时,存储节点dio读取的数据直接使用ByteBuf.wrap,没有内存拷贝(程序层面),直接发送给计算节点。连接建立后开启tcp_nodelay以减少网络延迟。在比赛结束最后一天之前计算节点一直用的nio开发,写入耗时始终在719秒往上,因为一直觉得虽然nio在发送接收时与set/get线程有cpu切换,但是这些切换耗时与网络rtt相比应该不算什么,可事实总是在啪啪啪打脸,最后一天(其实也就写好两三天的样子,java环境最后几天才好,(/ □ \))把nio改写成bio传输,写入时间从725降到560左右(不确定是否是因为cpu切换导致),总结一下就是不能搞经验主义,一定要benchmark everything。5、可探索的改进一般情况下我们使用nio都是将其fd绑定到某个event loop上,该event loop监听该fd的事件,这里其实我们可以改变nio使用方式,在set/get当前线程监听fd事件来读写数据,有set/get线程充当event loop,可能会有一个不错的提升。6、一些感想第一次参加数据库相关的比赛,收获颇多,对数据库相关知识有了初步的了解,也学到了其他选手不错的分享,同时也非常感谢举办方举办这次比赛,给选手提供一个展示和学习的平台,预祝比赛越办越好。源码地址:https://github.com/wangkaish/hw_race2019_r2_kvstore
  • [技术干货] 近数据处理(NDP),为GaussDB(for MySQL)性能提升“加冕”
    在上一篇文章《首席科学家为您揭秘:我们介绍了GaussDB(for MySQL)的体系架构,这篇文章我们将重点介绍GaussDB(for MySQL)如何将查询处理卸载到存储层,我们将这一特性称之为近数据处理(Near Data Processing),简称NDP。NDP出现的契机在计算节点实例上执行查询操作首先需要将数据页面加载到InnoDB缓冲池(buffer pool)。相对传统数据库使用本地存储,云数据库需要通过网络获取数据,因此从存储节点读取页面数据的延迟要高得多。相比社区版MySQL,GaussDB(for MySQL)支持并行查询,可通过多线程并行将数据读取到缓冲池中,但当表数据量较大(包含数百万甚至更多的数据行),分析查询需要扫描大量数据时,将所需数据全部加载到缓冲池中,IO成本将变得非常高。因此,我们需要一种更优的方法来解决此问题。我们的解决方案是基于GaussDB(for MySQL) 计算节点与存储节点之间的紧密集成,将部分查询处理操作下推至靠近数据的分布式存储系统,数据库术语中称为算子下推。通过这种方式,我们可以利用多存储节点的总带宽。在云环境中,存储系统包含数百节点,我们希望充分利用存储系统的可扩展性,同时避免网络成为性能瓶颈点。NDP允许部分查询处理以大规模并行的方式在存储节点执行,并显著的减少网络IO。NDP有诸多好处,包括:利用多租户大规模分布式云存储系统,在多节点并行处理数据显著减少网络IO,只返回满足WHERE条件的行(过滤)和查询涉及的列(投影)或聚合操作的结果,而不是将完整的数据页面从存储节点返回至计算节点避免大数量扫描导致经常访问的数据页面从缓存池中移除那么存储层是如何处理的呢?算子下推通常适用于全表扫描、索引扫描、范围查询等场景。WHERE条件可下推至存储层,当前支持的数据类型包括:数值类型(numeric, integer, float, double)时间类型(date, time, timestamp)字符串类型(char, varchar)等算子下推可以与计算节点的并行查询完美结合,从概念上讲,一个查询首先在计算层(垂直扩展)拆分为多个worker线程并行处理,每个worker线程均可触发算子下推。由于分布式存储中数据分布的策略,每个worker线程的负载将分配至存储系统的多个节点上(水平扩展),每个存储节点都有线程池处理算子下推请求。查询是否启用算子下推,是在查询优化阶段,优化器根据统计信息和执行计划自动决策的。此外用户还可以使用 hint 来控制查询操作是否开启算子下推。算子下推可以很好地处理冷数据,然而,GaussDB(for MyQL)是一个OLTP系统,通常包含并发更新操作。当前计算下推实现,MVCC处理仅在计算节点进行,存储节点只处理可见的行,针对无法判断可见性的行,原样返回至计算节点,通过undo-log回放出对应的数据。 通过算子下推,我们将获得怎样的收益呢?以TPC-H标准测试集(scale factor: 100)为例,CPU:16核,内存: 128GB,计算节点数据库缓冲池大小设置为80GB,采用冷数据进行验证。下图展示了TPC-H Q6, Q12, Q14,  Q15  4 个Query的查询结果,均有20-40倍的性能提升。以Q12为例,只开启NDP,借助分布式存储算力和网络IO缩减,性能提升5倍,同时在计算节点开启并行查询,又获得7倍性能提升,总体提升约35倍,这个提升效果是非常显著的。本文中提到的这些功能都可在实际生产环境中使用,而这只是开始,随着我们将更多计算推送到存储层,更多的查询将从此优化中受益,我们可以期待更大的性能提升。如何启用NDP?开启NDP开关,对当前Session生效,优化器自动判断是否进行计算下推。mysql> show variables like 'ndp_mode'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | ndp_mode | ON | +---------------+-------+ 1 row in set (0.00 sec) mysql> explain select count(*) from lineitem; +----+-------------+----------+------------+-------+---------------+---------+---------+------+-----------+----------+-------------------------------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+----------+------------+-------+---------------+---------+---------+------+-----------+----------+-------------------------------------------------------------------+ | 1 | SIMPLE | lineitem | NULL | index | NULL | PRIMARY | 8 | NULL | 594000899 | 100.00 | Using pushed NDP columns; Using pushed NDP aggregate; Using index | +----+-------------+----------+------------+-------+---------------+---------+---------+------+-----------+----------+-------------------------------------------------------------------+ 1 row in set, 1 warning (0.00 sec)通过hint方式,使NDP对当前Query生效。mysql> show variables like 'ndp_mode'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | ndp_mode | OFF | +---------------+-------+ 1 row in set (0.00 sec) mysql> explain select count(*) from lineitem; +----+-------------+----------+------------+-------+---------------+---------+---------+------+-----------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+----------+------------+-------+---------------+---------+---------+------+-----------+----------+-------------+ | 1 | SIMPLE | lineitem | NULL | index | NULL | PRIMARY | 8 | NULL | 594000899 | 100.00 | Using index | +----+-------------+----------+------------+-------+---------------+---------+---------+------+-----------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) mysql> explain select/*+ ndp_pushdown() */ count(*) from lineitem; +----+-------------+----------+------------+-------+---------------+---------+---------+------+-----------+----------+-------------------------------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+----------+------------+-------+---------------+---------+---------+------+-----------+----------+-------------------------------------------------------------------+ | 1 | SIMPLE | lineitem | NULL | index | NULL | PRIMARY | 8 | NULL | 594000899 | 100.00 | Using pushed NDP columns; Using pushed NDP aggregate; Using index | +----+-------------+----------+------------+-------+---------------+---------+---------+------+-----------+----------+-------------------------------------------------------------------+ 1 row in set, 1 warning (0.00 sec)挑战与今后方向NDP有诸多好处,但它也有一些技术挑战需要我们解决。如分布式存储系统为多租户共享,为了避免不同租户对资源争抢使用,我们需要实现单租户级的资源管控。另外是优化器决策使用NDP的时机,需结合触发网络IO读取的数据量以及已缓存在缓冲池中的数据量综合考虑。GaussDB(for MySQL)是一款云原生数据库,该体系结构支持极其强大和灵活的NDP框架。未来,我们计划利用此框架不仅仅是做查询处理,还将进一步扩展存储层中的数据库功能,这些功能可以与查询下推结合使用。我们相信,云堆栈的深度集成是释放云数据库力量的关键,华为云在实现这一目标方面处于领先地位,正如GaussDB(for MySQL)所证明的那样。请大家保持关注,我们后续将会给大家带来更多精彩技术分享。也欢迎大家前往华为云官网,了解更多GaussDB(for MySQL)详情:https://www.huaweicloud.com/product/gaussdb_mysql.html
  • [版主精选] 连续两年入选Gartner®云数据库管理系统魔力象限™
    近日,国际研究机构Gartner发布2021年全球云数据库魔力象限报告《Magic Quadrant for Cloud DatabaseManagement Systems》华为云凭借GaussDB系列数据库产品入选魔力象限的特定领域者成为亚洲唯二入选的云厂商自2020年首次入选,华为云GaussDB已经连续两年入选 Gartner云数据库管理系统魔力象限。华为云GaussDB在行业实力、亚太市场影响力、云产品组合和生态广度方面十分具有优势,从技术到服务都充分满足了客户业务场景需求。 金融政企优选,市场影响力扩大得益于长期服务政企客户的经验与优势,华为云GaussDB目前已成功在1500+大客户规模商用,广泛应用于金融、泛政府、电信、能源、交通、医疗、物流、电商等领域,历经各种企业级严苛场景考验。在2021年6月Gartner发布的《Market Share **ysis: Database Management Systems, Worldwide, 2020》报告中,华为云凭借数据库在全球营收中排名第十,全球增速48.5%,在数据库市场取得了显著的成绩。持续创新与拥抱开源,让企业上云更轻松高效产品方面,华为云GaussDB围绕“金融级高可用、云栈垂直整合、企业级混合负载、云原生架构、密态数据库、AI-Native自治”等6大基础研究方向,紧密结合客户业务场景,不断进行产品完善和服务创新,积极打造面向客户全场景的一站式数据库服务。生态方面,一个开源开放并凝聚产学研用的良性循环的生态,是大势所趋。华为云积极拥抱并兼容业界主流的关系型数据库生态如MySQL及非关系型数据库MongoDB、Redis等生态。同时对外开源openGauss单机主备能力,积极推进openGauss开源社区“共建共享共治”。此外,还联合产业联盟与标准组织、高校、合作伙伴、开发者打造数据库开放生态,共同繁荣数据库产业。数字化创新之路还在继续,华为云GaussDB会将产品能力应用到更多商业实践,让客户“选型安心、迁移放心、管理省心”,做企业核心数据上云信赖之选。来源:1. Gartner,Magic Quadrant for Cloud Database Management Systems,Henry Cook等人,2021年12月14日2. Gartner,Market Share **ysis: Database Management Systems, Worldwide, 2020,Sharat Menon,2021年6月30日免责声明:Gartner不认可其研究出版物中描述的任何供应商、产品或服务,也不建议技术用户只选择评级最高或其他名称的供应商。Gartner研究出版物由Gartner研究组织的意见组成,不应解释为事实陈述。Gartner不承担与本研究有关的所有明示或暗示的保证,包括任何适销性或适用于特定目的的保证。Gartner和魔力象限是Gartner, Inc.和/或其附属公司在**和国际上的注册商标和服务标记,经许可在此使用。Gartner保留所有权利。
  • [行业资讯] 华为云数据库亮相2021PG中国技术大会并斩获4项大奖
    1月7日-9日,以“开源论道·数据驱动·共建数字化未来”为主题的第十一届PostgreSQL中国技术大会隆重举办。华为多位数据库专家出席并发表了重要演讲,分享了华为云数据库最新技术与实践,积极推动商业落地,使能企业智能升级。会上,华为云RDS for PostgreSQL荣获“数据库最具潜力产品奖”,华为流程IT DBA团队荣获“PostgreSQL中国最具价值团队奖”,华为数据库架构师陈华军和华为云数据库高级专家赵全明分别荣获“十周年卓越贡献特别奖”、“中国PostgreSQL最具价值专家MVP奖”。大会主会场,华为质量与流程IT数据库架构师陈华军分享了《华为集团IT PostgreSQL运用实践》主题演讲。他介绍到,流程IT作为服务华为公司19万员工的企业IT部门,支持华为公司全球业务、全球研发、全球协同,客户覆盖全球170多个国家、服务上亿消费者。为了应对日益增长的业务数据和海量并发问题,华为集团对交易库选择主要采用云数据库PostgreSQL去“O”,通过架构部署、参数调优、客户端配置、监控告警、性能诊断工具、闪回实现等能力,很好地解决了数据库兼容性、扩展性、数据一致性、性能等方面的问题。目前,华为集团IT去“O”和上云工作已完成一半。华为云数据库高级工程师刘志俊在分论坛分享了《Oracle迁移到PostgreSQL的挑战与突破》。他提到,近年来去“O”的呼声越来越大,大量的传统企业开始脱离“IOE”集中式架构,进行云端分布式改造。针对扩展性、技术不可控、高成本等去“O”难题,华为云GaussDB推出了数据库和应用迁移UGO+数据复制服务DRS专属组合解决方案,该方案从迁移评估、结构迁移、应用迁移、全量+增量数据迁移、数据一致性动态校验、流量回放等方面提供了一站式迁移上云方案,让客户上云更轻松、更高效。华为云数据库产品经理冯万里分享了《解锁华为云数据库PostgreSQL高速增长密码》。他表示,华为云数据库PostgreSQL连续3年保持5倍营收增长,持续为5000+客户创造了价值。取得这一重大成果的原因在于,华为云RDS for PostgreSQL具备卓越的高可靠、高安全、插件丰富、兼容开源、便捷上云、低成本等能力优势,并在国家地理信息服务平台天地图和中国一汽等企业中成功落地。华为云数据库高级工程师杨科伟在分论坛分享了《GaussDB(for Redis)的云原生存算分离架构实践》。他指出,存算分离的分布式架构是大势所趋,目前已经有越来越多企业选择将核心业务上云到该架构。华为云GaussDB(for Redis)基于该架构,完美避开了开源Redis的主从堆积、主从不一致、fork抖动、内存利用率只有50%等问题,构筑了强一致、高可用、冷热分离、弹性伸缩、高性能等极具竞争力的能力优势,极大促进了企业业务的发展。华为云数据库高级工程师党李飞分享了《华为云DDS数据库容灾关键技术》。他介绍到,华为云DDS是一款兼容MongoDB 3.4/4.0版本的文档数据库服务,目前支持分片集群、副本集和单节点三种部署架构。华为云DDS基于华为云数据复制服务DRS灾备技术,支持主备倒换,通过数据抓取和数据回放,保障数据一致性。通过优化原生Change Streams,华为云DDS支持更丰富的DDL语句,对于集合删除、数据库删除事件,日志拉取不中断,支撑近50000 ops,与社区版相比,性能得到大幅提升。技术不止步,服务更贴心,华为云数据库未来将会打造更优、更专业高效的数据库服务,赋能企业挖掘数据价值,推动业务革新,加速企业数字化转型。 错过直播不要怕,点击下面链接可直接回顾精彩:1月7日,华为数据库架构师陈华军演讲链接:https://live.csdn.net/room/postgresqlchina/1Ppndzfv?spm=1001.2014.3001.55011月8日,华为云数据库高级工程师刘志俊演讲链接:https://live.csdn.net/room/postgresqlchina/FS0reRwq?spm=1001.2014.3001.55011月9日,华为云数据库高级工程师杨科伟和党李飞、华为云数据库产品经理冯万里演讲链接:https://live.csdn.net/room/postgresqlchina/XB2Uc2AA?spm=1001.2014.3001.5501 【阅读原文】https://www.huaweicloud.com/product/dbs.html
  • [技术干货] 【云图说】第233期 云数据库RDS——跨区域备份
    云数据库 MySQL介绍页入口:详情请点击链接云数据库 PostgreSQL介绍页入口:详情请点击链接云数据库 SQL Server介绍页入口:详情请点击链接云数据库RDS 成长地图入口:详情请点击链接
  • [技术干货] 2020华为云数据库挑战赛-赛题解读
    观看链接:https://huawei.vhallyun.com/fe/watch/4607
  • [技术干货] 【云数据库知识】Cassandra--copy命令使用指南
    copy是cqlsh中的逻辑导入导出命令。包括两个命令COPY TO / COPY FROM.使用这组命令可以在Cassandra与其他RDBMS或Cassandra之间迁移数据。目前已经支持csv, json文件格式以及标准输出和输入。 1. 如何执行copy?    1. 执行copy时,首先要启动cqlsh. 启动cqlsh后,接着执行copy命令。如下11    ./cqlsh 127.0.0.1 9042 -u {user_name} -p {password}11COPY cycling.cyclist_name TO '/home/cas/copydata';2. 如果数据量很大,可以放在后台执行。使用cqlsh的-e 参数。-e 参数用来后台执行给定的语句,然后退出。命令如下11    ./cqlsh 127.0.0.1 9042 -u {user_name} -p {password} -e "COPY cycling.cyclist_name TO '/home/cas/copydata'";2. COPY TO 11    COPY <table name> [(<column>, ...)] TO <file name> WITH <copy option> [AND <copy option> ...]COPY TO 常见的参数有: NUMPROCESSES, RATEFILE, PAGESIZE, BEGINTOKEN, ENDTOKEN, MAXATTEMPTS, MAXOUTPUTSIZE; 新增的参数有: RESULTFILE, DATAFORMATS, WHERECONDITION.重点介绍常见和新增的参数,关于其他COPY TO的参数可以参考Cassandra官网文档:copy-to1. `file name` 导出时,可以指定文件名称为目录, 也可以指定文件名称为文件。默认导出到文件。如果指定导出文件为存在的目录时,将会按照range范围导出到目录下的不同的文件中,如果某一个range范围导出没有数据,则不会生成文件。如果指定的文件名是文件,那将会导出到指定的文件中。如果文件不存在,则新创建该文件。11    ./cqlsh 127.0.0.1 9042 -e "COPY cycling.cyclist_name to '/home/cas/copydata'"11    ./cqlsh 127.0.0.1 9042 -e "COPY cycling.cyclist_name to '/home/cas/copydata/cycling.cyclist_name'"2. `NUMPROCESSES` 导出的线程数。在导出时,会将range范围进行细分。导出的线程数越多,细分range的范围数也就越多。但当线程数太多的时候,容易对服务端造成压力,造成导出失败。所以要选择一个合适的线程数进行导出,默认的线程个数是(CPU核数 - 1)3.  `RATEFILE` 速率文件。指定文件路径后,会打印导出过程的瞬时速率,可以用来评价导出的性能。4.  `PAGESIZE` 在一次page查询中。获取的row数。 默认为 1000。 建议不要设的调小。设置太小会影响导出性能。5.  `BEGINTOKEN, ENDTOKEN` 执行要导出的range范围。默认是全部数据导出。6.  `MAXATTEMPTS` 每一个查询重试的次数。如果某次查询达到最大重试次数,那么导出将会直接失败。 7.  `MAXOUTPUTSIZE` 每一个导出文件中的最大的行数。如果导出数据大于这个值。将会轮转生成另一个文件。默认是不限制的。11    ./cqlsh 127.0.0.1 9042 -e "COPY cycling.cyclist_name to '/home/cas/copydata/cycling.cyclist_name' with MAXOUTPUTSIZE=1"8.  `RESULTFILE` 导出结果文件路径,如果不设置。默认生成在当前执行目录下。如果执行目录中存在之前的结果文件,将会重命名之前的结果文件。导出结果的内容主要包括:导出成功与否,总共导出的行数和速率,导出的range范围数,以及成功失败的range范围数,并展示每一个range范围的结果和导出的行数。9. `DATAFORMATS` 导出的数据格式。取值为csv, json。默认为csv格式。指定为json时,导出为json格式的数据。10. `WHERECONDITION` 导出的查询条件。支持查询条件的导出。对于非主键列,如果通过索引来查询,提高导出性能。         1. wherecondition 格式如下 `[key(operators)value,key(operators)value...]`        2. operators 支持 `[">=", "<=", ">", "<", "="]`,例如: `'keyspace_name=system,table_name>=local'`        3. 如果value中包含有特殊字符,比如保留字符 【" ,><=’】, 那么需要给字符加上双引号,例如:`'keyspace_name=system,table_name>="loc>=al"'`一个完整的COPY TO例子:11    nohup ./cqlsh 127.0.0.1 9042 --request-timeout=3600 --debug -e "COPY nihao.sz_user to '/home/cas/copydata' with WHERECONDITION='update_timestamp=1' NUMPROCESSES=12 AND RATEFILE='rate.txt' AND RESULTFILE='export_result' AND dataformats='json';"  >export.log 2>&1 &3. COPY FROM   11    COPY <table name> [(<column>, ...)] FROM <file name> WITH <copy option> [AND <copy option> ...]COPY FROM 常见的参数有: NUMPROCESSES, MAXROWS, INGESTRATE, ERRFILE, MAXBATCHSIZE, MINBATCHSIZE, CHUNKSIZE, MAXPARSEERRORS, MAXINSERTERRORS, SKIPROWS, SKIPCOLS;新增的参数有: DATAFORMATS.重点介绍常见和新增的参数,关于其他COPY FROM参数可以参考Cassandra官网文档: copy-from1. `file name` 导入数据时,指定导入的文件路径,可以是一个目录,或者是一个文件,或者是逗号分隔的文件名列表。如果是目录,则导入该目录下的所有文件。2. `NUMPROCESSES` 导入的线程数3. `MAXROWS` 导入的最大行数。默认不限制。4. `INGESTRATE` 每一秒导入的最大行数。默认为 1000005. `ERRFILE` 导入失败的列将放在这个文件中。6. `MAXBATCHSIZE` 每一次batch导入的最大行数。默认为207. `MINBATCHSIZE` 每一次batch导入的最小行数。默认为28. `CHUNKSIZE` 导入主线程给子线程每次传递的行数,默认为 10009. `MAXPARSEERRORS` 可以忽略的语法解析错误的最大行数。默认不限制10. `MAXINSERTERRORS` 可以忽略的写入失败的最大行数。默认为100011. `SKIPROWS` 导入时初始跳过的行数。默认为0,不跳过12. `SKIPCOLS` 导入时忽略的列名,以逗号分隔。默认不忽略。13. `DATAFORMATS` 导入的数据格式。取值为csv,json。默认为csv格式。数据为json格式时,必须指定为json。一个完整的COPY FROM例子:11    nohup ./cqlsh 127.0.0.1 9042 --request-timeout=3600 --debug -e "COPY nihao.sz_user FROM '/home/cas/copydata' with NUMPROCESSES=12 AND RATEFILE='rate.txt' AND dataformats='json';"  >import.log 2>&1 &
  • [技术干货] 【云数据库知识】数据库Cassandra --物化视图 MATERIALIZED VIEW
    物化视图:物化视图本质上是由数据库自动维护的标准CQL表。他自动维护符合条件的数据与原表数据的一致性。参考链接:opencredo.com/everything-need-know-cassandra-materialized-views/限制:1. 物化视图的primary key必须包含baseTable的所有 primary key;  不允许使用静态列。2. 视图中的primary key的所有列必须IS NOT NULL.3. 任何物化视图中必须将一个cql行从base表映射到物化视图的另一行.即view和baseTable之间的行一一对应。4. 创建物化视图时的select语句where条件中,不能对view的非primary key列进行限制,除过IS NOT NULL5. 静态列不支持,counter不支持, superColumn不支持,duration类型不支持源表:12345671    CREATE TABLE person (    2        id int,    3        name text,    4        addr text,    5        age int,    6        email text,    7        PRIMARY KEY (id, name));写入一条记录,并查询结果:11    insert into person(id, name, age, addr, email) values (0, 'ruby', 26, 'beijing', 'ruby@email.com');创建视图:1231    CREATE MATERIALIZED VIEW person_addr AS                    2        SELECT * from person WHERE id IS NOT NULL AND addr IS NOT NULL AND name IS NOT NULL    3        primary key (addr, id, name);system_schema.views记录了视图和源表的关联关系:不符合该条件的查询不显示eg:IS NOT NULL写入addr为null的记录11    insert into person(id, name, age, addr, email) values (1, 'mike', 30, null, 'mike@email.com');原表数据和物化视图数据:删除物化视图:
  • [精彩回顾] 以梦为码,为开发者代言 — 华为云TaurusDB性能挑战赛明星选手的故事
    2019年的夏天,华为云数据库携TaurusDB性能挑战赛与来自30+重点高校、20多个行业等近千名数据库爱好者进行了一场技术上的碰撞与思想上的交流,在为期近三个月的比赛中,收获了很多故事与满满的感动。近500支队伍在层层赛制激烈的角逐中,终于诞生出了决赛10强,而前六强席位颁奖则于9月18日在华为全联接大会举行。0xCC单枪匹马的王者0xCC是一支单人团队,也是本次大赛的冠军,选手口中的CC大神,拥有丰富的数据库、中间件比赛经历,并多次斩获大奖,知名度较高。CC毕业于南京理工大学,入职刚满一年,高中时期就很喜欢计算机编程并自行研究,本科生时期积极参加了很多大大小小的比赛,研究生时期也参加了许多国内比赛,凭着自己一腔热爱与对技术的执着勇敢走到了今天。华为云主要在大赛中起到一个基础平台的作用,参赛作品依托华为云弹性服务器、NVME和高性能网卡,实现了超高吞吐量的数据读写。只有借由这个平台,才能发挥作品的全部性能。关于大赛CC如是说道,并指出技术是以人为本的,希望通过技术让人们的生活更加美好。Watermelon三人组名校高材生这是一支集结了上海交通大学、浙江大学两所名校研究生的三人团队,三人目前均是研二在读。他们三人曾组队参加过两次比赛并闯入决赛,这是他们参加的第三个比赛,也是毕业前最后一个比赛,能够获奖他们感到十分幸运。源于对数据库的浓厚兴趣和狂热喜爱,他们一边实习一边利用空闲时间来提交比赛作品,凭借过硬的技术实力,在众多学生队伍中脱颖而出。华为云技术在两个方面给予了我们很大帮助。一方面,从评测环境的角度,华为云提供了高性能的服务器与磁盘,可以使我们在作品中的一些优化点充分的体现出来;另一方面,华为云在这次比赛中提供的一些技术资料,也对我们在作品中计算存储分离的设计,起到了很大的帮助。三人均认为华为云TaurusDB 的计算存储分离架构对于数据的存储、磁盘性能的提升还是很厉害的,对华为云技术予以肯定与支持。这是一支由资深码农和技术网红组成的两人组团队——这位“码农”是一个经验丰富的大神,有好几年的工作经验,技术很强,但为人低调。而他的搭档是一位喜欢分享技术和大赛心得的网络写手,同时也是技术大牛,比赛期间经常在选手交流群分享做题中遇到的一些坑,以此提醒其他选手,是一个暖心的95后技术网红。对于华为云最新一代高扩展海量存储分布式数据库TaurusDB,他们提到:在大数据存储的场景下,分布式数据库的优势越发凸显,可以解决传统数据库所面临的容量问题。华为云TaurusDB单实例扩容数据可达128T,容量十分强大。ADSL三队渴望成就自我的高校研究生这是一支两人组学生团队,两人均就读于中国科学技术大学,目前研一在读。他们表示此次参加华为云TaurusDB性能挑战赛是一个很不错的契机,可以借此检验自己的学习成果,因此对这次比赛格外用心。但由于时间问题,在作品呈现中有一些优化点没有完全实现,对此感到十分遗憾。虽有缺憾,但两人在比赛中依旧成绩斐然,摘下了季军宝冠。华为云给我们比赛提供了评测环境,并给了我们机会接触到一些领先的硬件设备,使我们能够在这上面实现自己的一些优化想法。他们十分感激华为云提供了这么一个技术交流平台,在比赛中见识了各类牛人大咖的风采,希望自己能够沿着这条路继续走下去,成就自我。Pilipala首次参赛的资深程序员Pilipala是一支三人组团队,其主创人员是一家公司的分布式存储团队负责人,工作多年,拥有丰富的数据库产品经验,一得知华为云TaurusDB比赛,立马组队积极参加,想与更多技术大咖进行技术碰撞及交流。由于是第一次参赛,且因为公司项目比较紧急,参赛精力有限,最终呈现的作品只是他们原先设想的一个子集,一些优化没有完全展现出来,因此希望明年华为云数据库还能举办这样的比赛,自己会全身心投入。这场比赛是基于华为云最新一代高扩展海量存储分布式数据库产品TaurusDB举办的。华为云TaurusDB采用计算与存储分离、日志即数据的架构设计,支持1写15读,完全兼容MySQL8.0,性能达到原生MySQL的7倍。此次大赛的一等奖得主是0xCC,二等奖得主为Watermelon和Rollbacked,三等奖得主共3名,分别是Kirito的技术分享、ADSL三队、Pilipala。这6支队伍在大赛中表现卓越,引人注目,近三个月的辛苦付出终换得如今的奖冠加身,荣耀时刻,光辉万里长。目前,华为云数据库正在积极开展开发者生态发展计划,华为云TaurusDB性能挑战赛只是其计划的一部分,希望通过这次大赛能携手更多数据库领域开发者共建一个开放、合作、共赢的数据库产业生态,共同创造智能未来。
  • [版主精选] 2021华为云GaussDB年度大盘点,感恩有你
    回首2021,我们探索数字化实践和前沿技术之路,深入产业发展与生态合作,勇攀一个个高峰;展望2022,我们怀抱更大的数字梦想,继续探索数字时代星辰大海。前行之路感谢相伴,华为云GaussDB 与您一起筑梦前行。https://www.huaweicloud.com/product/dbs.html
  • [优秀博文] 当MySQL执行XA事务时遭遇崩溃,且看华为云如何保障数据一致性
    注:本文如没有特殊说明,MySQL指社区版MySQL;binlog指MySQL server日志;redo Log指MySQL InnoDB日志 MySQL replication实时同步主库上执行的事务到备库,并且支持一般事务的崩溃恢复安全,这为一般事务的高可用提供了坚实的保障。如果没有此高可用保障,主库崩溃(不能正常恢复场景)后,数据库服务轻则中断几十分钟甚至几小时,重则丢失用户数据。 但是当前MySQL所有版本不支持分布式事务的崩溃恢复安全,这严重影响了分布式事务的高可用保障。华为云数据库(包括RDS (for MySQL) 和GaussDB (for MySQL))解决了这一痛点,支持分布式事务的崩溃恢复安全,极大地提升华为云数据库的可靠性和可用性。 接下来我们将逐个讨论MySQL在分布式事务崩溃恢复安全方面的几个常见问题,以及华为云数据库采取了什么解决方案来保证数据的一致性。(如需了解分布式事务,请参考这里:https://dev.mysql.com/doc/refman/8.0/en/xa.html) 问题一:如上图所示:如果崩溃发生在危险区间段内的任意一点,主库重启后,binlog中保存有准备阶段执行的事务,但是InnoDB回滚了准备阶段执行的事务。从而导致MySQL server和InnoDB数据不一致。准备阶段执行的事务会被回放到备库,它获得的所有事务处理过程中使用的锁永远不能被释放。最终导致备库回放需要获得相关锁的其它事务时锁超时失败,复制中断。 华为云数据库解决方案如上图流程所示:如果崩溃发生在阶段一,主库重启后,这个分布式事务准备阶段既不在MySQL server中,也不在InnoDB中;如果崩溃发生在阶段二,主库重启恢复过程中这个分布式事务准备阶段会被InnoDB回滚掉,最终这个分布式事务准备阶段既不在MySQL server中,也不在 InnoDB;如果崩溃发生在阶段三,主库重启后,这个分布式事务准备阶段既存在MySQL server中,也存在InnoDB中;所以,无论崩溃发生在上图中的哪一点,主库重启后,华为云数据库都能保证MySQL server和InnoDB数据的一致性。 问题二:如上图所示:如果崩溃发生在危险区间段内的任意一点,主库重启后,binlog保存有XA COMMIT xid, 但是MySQL InnoDB没有提交这个分布式事务。如果不重新提交,那么在准备阶段获得的所有事务处理过程中使用的锁永远不能被释放,最终导致主库执行需要获得相关锁的其它事务时锁超时失败;如果重新提交,XA COMMIT xid再次被持久化到binlog,备库在回放第二个XA COMMIT xid时抛出“Unknown XID”错误,导致复制中断。 华为云数据库解决方案主库在重启的过程中以binlog作为仲裁提交了这个分布式事务准备阶段执行的事务,保证了华为云数据库MySQL server和MySQL InnoDB数据的一致性。 问题三:如上图所示:如果崩溃发生在危险区间段内的任意一点,主库重启后, binlog保存有XA ROLLBACK xid,但是MySQL InnoDB没有回滚这个分布式事务。如果不重新回滚,这个分布式事务准备阶段获得的所有事务处理过程中使用的锁永远不能被释放,最终导致主库执行需要获得相关锁的其它事务时锁超时失败;如果重新回滚,XA ROLLBACK xid再次被持久化到binlog,备库在回放第二个XA ROLLBACK xid时抛出“Unknown XID”错误,导致复制中断。 华为云数据库解决方案主库在重启的过程中以binlog作为仲裁回滚了这个分布式事务准备阶段执行的事务,保证了华为云数据库MySQL server和MySQL InnoDB数据的一致性。 问题四:如上图所示:如果崩溃发生在危险区间段内的任意一点,主库重启后,binlog中保存有一阶段提交分布式事务,但是MySQL InnoDB回滚了这个一阶段提交分布式事务。从而导致MySQL server和MySQL InnoDB数据不一致。一阶段提交的分布式事务会被回放到备库,最终导致备库数据和主库数据的不一致。 华为云数据库解决方案如上图所示:如果崩溃发生在阶段一,主库重启后,这个一阶段提交分布式事务既不在MySQL server中,也不在MySQL InnoDB中;如果崩溃发生在阶段二,主库重启恢复过程中这个一阶段提交分布式事务会被MySQL InnoDB回滚掉,最终这个分布式事务既不在MySQL server中,也不在MySQL InnoDB中;如果崩溃发生在阶段三,主库重启后,这个一阶段提交分布式事务既存在MySQL server中,也存在MySQL InnoDB中;无论崩溃发生在上图中的哪一点,主库重启后,华为云数据库都能保证MySQL server和MySQL InnoDB数据的一致性。 华为云数据库很好地解决了分布式事务崩溃恢复安全的相关问题,极大地提升数据库的可靠性和可用性,提升了用户使用华为云数据库的体验。后续我们会持续在分布式事务方面做更多的优化和解决MySQL可能遇到的问题,也欢迎大家使用华为云数据库分布式事务,体验华为云数据库卓越的可靠性和可用性,期待您的反馈!https://www.huaweicloud.com/product/gaussdb_mysql.html
  • [版主精选] 华为云数据库赋能爆款IP斗罗手游,开启全新3D式冒险之旅
    “没有废物的武魂,只有废物的魂师!” “不流血,不痛苦,怎么走自己的路。” “史莱克学院,唐三参战!”如果有人对这些话耳熟能详,那一定是斗罗大陆的忠实粉丝。唐三,天生满魂力,双生武魂,外附魂骨,不夸张地说,这个名字承载了一代人的青春回忆。他,就是大型玄幻小说《斗罗大陆》中的主人公。“你我皆唐门,觉醒现世中”。在众多忠实粉丝的千呼万唤下,由小说正版授权改编的《斗罗大陆-斗神再临》真3D手游终于迎来了面世。《斗罗大陆-斗神再临》是全球化IP游戏生态公司——中手游打造的又一爆款IP游戏。作为一款魂兽猎杀、开放式冒险的真3D手游,它深度还原了小说中的斗罗世界,最大程度契合了IP受众对“抬手间即可出现武魂”的斗罗想象。华为云RDS for MySQL数据库保障游戏快速上线 在IP粉丝和游戏玩家的众望所归之下,游戏的上线取得了不俗的成绩,这并不代表就是一帆风顺的。初期,研发人员也在担心一些问题,例如面对超大的业务数据增长和并发量,数据库的响应越来越慢,系统的不稳定性越来越明显,游戏需要低时延的场景,批量游戏需要归档......这些问题将会直接影响玩家的体验感。为了让玩家感受到顺畅的画面和节奏,就必须要有一款高性能、高可靠的数据库。在这样的机遇下,促成了中手游和华为云的强强联合,华为云RDS for MySQL数据库为这些问题带来了突破口。和自建的社区版本相比,RDS for MySQL数据库的性能更高,在高并发的场景下,性能可提升3倍,同时应用读写分离的技术让业务访问更加稳定,并可实现在线分钟级弹性扩缩容;针对游戏需要的低时延场景,提供本地盘的方式,解决了通用云盘方案时延过大的问题。同时,它有完善的备份恢复机制,支持主备秒级切换、732天超长自动备份、以及游戏归档所必需的批量PITR技术。在RDS for MySQL的支撑下,《斗罗大陆-斗神再临》手游得到轻松部署。为了确保游戏顺利上线,华为云数据库专家随时待命,及时与业务开发人员进行远程会议,针对出现的问题实时排查原因并提供解决方案,使问题在最短时间内得到有效解决。值得一提的是,这也是华为云数据库首次支撑大规模上线的爆款IP游戏,刚上线就取得了亮眼的成果。在华为云数据库支撑该游戏的仅两个月内就完成了游戏内测至上线的全流程,业务上线流程缩短50%,并支撑海量游戏用户同时在线,达到了200万的用户预约量,上线首日流水破1000万。良好的开端是成功的一半。未来,华为云将继续联手中手游,共同探索云游戏、VR游戏等应用场景,发挥双方优势,展开更为深入的合作。
总条数:436 到第
上滑加载中