微软支持并发的Key-Value 存储库有C++与C#两个版本。号称迄今为止最快的并发键值存储。下面是C#版本翻译:

FASTER C#可在.NET Framework和.NET Core中运行,并且可以在单线程和并发设置中使用。经过测试,可以在Windows和Linux上使用。它公开了一种API,该API可以执行读取,盲更新(Upserts)和读取-修改-写入(RMW)操作的混合。它支持大于内存的数据,并接受IDevice将日志存储在文件中的实现。提供了IDevice本地文件系统的实现,也可以写入远程文件系统。或者将远程存储映射到本地文件系统中。FASTER可以用作传统并发数据结构类似ConcurrentDictionary的高性能替代品,并且还支持大于内存的数据。它支持增量或非增量数据结构类型的检查点。

FASTER支持三种基本操作:

  1. Read:从键值存储中读取数据
  2. Upsert:将值盲目向上插入到存储中(不检查先前的值)
  3. Read-Modify-Write:更新存储区中的值,用于实现“求和”和“计数”之类的操作。

构建

在实例化FASTER之前,您需要创建FASTER将使用的存储设备。如果使用的是可移植类型(byte、int、double)类型,则仅需要混合日志设备。如果使用对象,则需要创建一个单独的对象日志设备。

IDevice log = Devices.CreateLogDevice("C:\\Temp\\hybridlog_native.log");

然后,按如下方式创建一个FASTER实例:

fht = new FasterKV<Key, Value, Input, Output, Empty, Functions>

(1L << 20, new Functions(), new LogSettings { LogDevice = log });

构造函数的类型参数

有六个基本概念,在实例化FASTER时作为通用类型参数提供:

  1. Key:这是键的类型,例如long。
  2. Value:这是存储在FASTER中的值的类型。
  3. Input:这是调用Read或RMW时提供给FASTER的输入类型。它可以被视为读取或RMW操作的参数。例如,对于RMW,可是增量累加到值。
  4. Output:这是读操作的输出类型,将值的相关部分复制到输出。
  5. Context:操作的用户定义上下文,如果没有必要使用Empty。
  6. Functions:需要回调时,使用IFunctions<>调用。

回调函数

用户提供一个实例化IFunctions<>。此类型封装了所有回调,下面将对其进行介绍:

  1. SingleReader和并发读ConcurrentReader:这些用于读取存储值并将它们复制到Output。单个读取器可以假定没有并发操作。
  2. SingleWriter和ConcurrentWriter:这些用于将值从源值写入存储。
  3. Completion callbacks完成回调:各种操作完成时调用。
  4. RMWUpdaters:用户指定了三个更新器,InitialUpdater,InPlaceUpdater和CopyUpdater。它们一起用于实现RMW操作。
  5. Hash Table Siz哈希表大小:这是分配给FASTER的存储行数,其中每个行为64字节。
  6. LogSettings 日志设置:这些设置与日志的大小、设备。
  7. Checkpoint设置:这些是与检查相关的设置,例如检查类型和文件夹。
  8. Serialization序列化设置:用于为键和值类型提供自定义序列化程序。序列化程序实现IObjectSerializer<Key>键和IObjectSerializer<Value>值。只有C#类对象非可移植类型才需要这些。
  9. Key比较器:用于为key提供更好的比较器IFasterEqualityComparer<Key>。

构造函数参数

FASTER的总内存占用量由以下参数控制:

  1. 哈希表大小:此参数(第一个构造函数参数)乘以64是内存中哈希表的大小(以字节为单位)。
  2. 日志大小:logSettings.MemorySizeBits表示混合日志的内存部分的大小(以位为单位)。换句话说对于参数设置B,日志的大小为2 ^ B字节。如果日志指向类对象,则此大小不包括对象的大小,因为FASTER无法访问此信息。日志的较旧部分溢出到存储中。

Sessions (Threads)会话(线程)

实例化FASTER之后,线程可以使用Session来使用FASTER

fht.StartSession();

fht.StopSession();

当所有线程都在FASTER上完成操作后,您最终销毁FASTER实例:

fht.Dispose();

示例

以下是一个简单示例,其中所有数据都在内存中,因此我们不必担心挂起的I / O操作。在此示例中也没有检查点。

public static void Test()

{

var log = Devices.CreateLogDevice("C:\\Temp\\hlog.log");

var fht = new FasterKV<long, long, long, long, Empty, Funcs>

(1L << 20, new Funcs(), new LogSettings { LogDevice = log });

fht.StartSession();

long key = 1, value = 1, input = 10, output = 0;

fht.Upsert(ref key, ref value, Empty.Default, 0);

fht.Read(ref key, ref input, ref output, Empty.Default, 0);

Debug.Assert(output == value);

fht.RMW(ref key, ref input, Empty.Default, 0);

fht.RMW(ref key, ref input, Empty.Default, 0);

fht.Read(ref key, ref input, ref output, Empty.Default, 0);

Debug.Assert(output == value + 20);

fht.StopSession();

fht.Dispose();

log.Close();

}

此示例的函数:

public class Funcs : IFunctions<long, long, long, long, Empty>

{

public void SingleReader(ref long key, ref long input, ref long value, ref long dst) => dst = value;

public void SingleWriter(ref long key, ref long src, ref long dst) => dst = src;

public void ConcurrentReader(ref long key, ref long input, ref long value, ref long dst) => dst = value;

public void ConcurrentWriter(ref long key, ref long src, ref long dst) => dst = src;

public void InitialUpdater(ref long key, ref long input, ref long value) => value = input;

public void CopyUpdater(ref long key, ref long input, ref long oldv, ref long newv) => newv = oldv + input;

public void InPlaceUpdater(ref long key, ref long input, ref long value) => value += input;

public void UpsertCompletionCallback(ref long key, ref long value, Empty ctx) { }

public void ReadCompletionCallback(ref long key, ref long input, ref long output, Empty ctx, Status s) { }

public void RMWCompletionCallback(ref long key, ref long input, Empty ctx, Status s) { }

public void CheckpointCompletionCallback(Guid sessionId, long serialNum) { }

}

更多例子

检查点和恢复

FASTER支持基于检查点的恢复。每个新的检查点都会保留(或使之持久)其他用户操作(读取,更新或RMW)。FASTER允许客户端线程跟踪已持久的操作和未使用基于会话的API的操作。

回想一下,每个FASTER线程都会启动一个与唯一的Guid相关联的会话。所有FASTER线程操作(读取,Upsert,RMW)都带有单调序列号。在任何时间点,都可以调用Checkpoint以启动FASTER的异步检查点。在调用之后Checkpoint,(最终)向每个FASTER线程通知一个序列号,这样可以确保直到该序列号之前的所有操作以及在该序列号之后没有任何操作被保留为该检查点的一部分。FASTER线程可以使用此序列号来清除等待执行的操作的任何内存缓冲区。

在恢复期间,线程可以使用继续使用相同的Guid进行会话ContinueSession。该函数返回线程本地序列号,直到恢复该会话哈希为止。从那时起,新线程可以使用此信息来重播所有未提交的操作。

下面一个单线程的简单恢复示例。

public class PersistenceExample

{

private FasterKV<long, long, long, long, Empty, Funcs> fht;

private IDevice log;

public PersistenceExample()

{

log = Devices.CreateLogDevice("C:\\Temp\\hlog.log");

fht = new FasterKV<long, long, long, long, Empty, Funcs>

(1L << 20, new Funcs(), new LogSettings { LogDevice = log });

}

public void Run()

{

IssuePeriodicCheckpoints();

RunSession();

}

public void Continue()

{

fht.Recover();

IssuePeriodicCheckpoints();

ContinueSession();

}

/* Helper Functions */

private void RunSession()

{

Guid guid = fht.StartSession();

System.IO.File.WriteAllText(@"C:\\Temp\\session1.txt", guid.ToString());

long seq = 0; // sequence identifier

long key = 1, input = 10;

while(true)

{

key = (seq % 1L << 20);

fht.RMW(ref key, ref input, Empty.Default, seq);

seq++;

}

// fht.StopSession() - outside infinite loop

}

private void ContinueSession()

{

string guidText = System.IO.File.ReadAllText(@"C:\\Temp\session1.txt");

Guid sessionGuid = Guid.Parse(guidText);

long seq = fht.ContinueSession(sessionGuid); // recovered seq identifier

seq++;

long key = 1, input = 10;

while(true)

{

key = (seq % 1L << 20);

fht.RMW(ref key, ref input, Empty.Default, seq);

seq++;

}

}

private void IssuePeriodicCheckpoints()

{

var t = new Thread(() =>

{

while(true)

{

Thread.Sleep(10000);

fht.StartSession();

fht.TakeCheckpoint(out Guid token);

fht.CompleteCheckpoint(token, true);

fht.StopSession();

}

});

t.Start();

}

}

FASTER支持两种检查点概念:“快照”和“折叠”。前者是将内存中的完整快照复制到一个单独的快照文件中,而后者是自上一个检查点以来更改的增量检查点。折叠有效地将混合日志的只读标记移到尾部,因此所有数据都作为同一混合日志的一部分保留(没有单独的快照文件)。所有后续更新均写入新的混合日志尾部位置,这使Fold-Over具有增量性质。

项目路径:

https://github.com/Microsoft/FASTER/tree/master/cs

微软并发Key-Value存储库FASTER介绍的更多相关文章

  1. 每秒高达1.6亿次操作的并发键值存储库 FASTER 诞生

    FASTER 在过去十年中,云中的数据密集型应用程序和服务有了巨大的增长.数据在各种边设施(例如,设备,浏览器和服务器)上创建,并由云应用程序处理用来获得数据价值或做出决策.应用程序和服务可以处理收集 ...

  2. 微软开放技术发布开源 Jenkins 插件以将 Windows Azure Blob 服务用的开作存储库

     发布于 2014-02-10 作者 陈 忠岳 持续集成 (CI) 的历史源远流长, 其宗旨在于软件团队在敏捷环境中不断将他们的工作整合为持续构建.管理 CI 进程的工具已存在一段时间.过去几年中 ...

  3. 94、存储库之MongoDB、mysql

    本篇导航: 简介 MongoDB基础知识 安装 基本数据类型 CRUD操作 其它 存储库之mysql   一.简介 MongoDB是一款强大.灵活.且易于扩展的通用型数据库1.易用性 MongoDB是 ...

  4. 存储库之MongoDB、mysql

    本篇导航: 简介 MongoDB基础知识 安装 基本数据类型 CRUD操作 其它 存储库之mysql   一.简介 MongoDB是一款强大.灵活.且易于扩展的通用型数据库1.易用性 MongoDB是 ...

  5. android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码

    Android精选源码 android模仿支付宝app"记账本"模块源码 android一个超轻量级剪贴板历史记录管理软件源码 android模仿QQ拖动红点消失动画效果源码 展示 ...

  6. 结合实体框架(代码优先)、工作单元测试、Web API、ASP. net等,以存储库设计模式开发示例项目。NET MVC 5和引导

    介绍 这篇文章将帮助你理解在库模式.实体框架.Web API.SQL Server 2012.ASP中的工作单元测试的帮助下设计一个项目.净MVC应用程序.我们正在开发一个图书实体和作者专用的样例图书 ...

  7. git-secret:在 Git 存储库中加密和存储密钥(上)

    当涉及处理机密信息(如密码.令牌.密钥文件等)等,以下问题值得考虑: 安全性十分重要,但高安全性往往伴随着高度的不便. 在团队中,共享某些密钥有时无法避免(因此现在我们需要考虑在多人之间分发和更新密钥 ...

  8. g4e基础篇#4 了解Git存储库(Repo)

    章节目录 前言 1. 基础篇: 为什么要使用版本控制系统 Git 分布式版本控制系统的优势 Git 安装和设置 了解Git存储库(Repo) 起步 1 – 创建分支和保存代码 起步 2 – 了解Git ...

  9. 2.1、CDH 搭建Hadoop在安装(为Cloudera Manager配置存储库)

    步骤1:为Cloudera Manager配置存储库 使用包管理工具安装Cloudera Manager yum 对于RHEL兼容系统, zypper对于SLES,和 apt-get对于Ubuntu. ...

随机推荐

  1. spring5 源码深度解析----- AOP的使用及AOP自定义标签

    我们知道在面向对象OOP编程存在一些弊端,当需要为多个不具有继承关系的对象引入同一个公共行为时,例如日志,安全检测等,我们只有在每个对象里引入公共行为,这样程序中就产生了大量的重复代码,所以有了面向对 ...

  2. 简单python爬虫案例(爬取慕课网全部实战课程信息)

    技术选型 下载器是Requests 解析使用的是正则表达式 效果图: 准备好各个包 # -*- coding: utf-8 -*- import requests #第三方下载器 import re ...

  3. 织梦cms列表页获取标签

    <!-- 标签 --> [field:id runphp='yes'] global $cfg_cmspath; $tags = GetTags(@me); $revalue = ''; ...

  4. git 查看日志记录

    1.git log 如果日志特别多的话,在git bash中,按向下键来查看更多,按q键退出查看日志. 2.git show 查看最近一次commit内容,也可以后面加commit号,单独查看此次版本 ...

  5. Scala 多继承顺序

    Trait多继承顺序: 准则: 如果有超类,则先调用超类的函数. 如果混入的trait有父trait,它会按照继承层次先调用父trait的构造函数. 如果有多个父trait,则按顺序从左到右执行. 所 ...

  6. 快学Scala 第十四课 (读取行,读取字符, 控制台读取)

    读取行: import scala.io.Source object FileReader { def main(args: Array[String]): Unit = { val source = ...

  7. Eclipse的Debug(一)

    本文链接:https://blog.csdn.net/u011781521/article/details/55000066    http://blog.csdn.net/u010075335/ar ...

  8. Spring Boot WebFlux 快速入门实践

    02:WebFlux 快速入门实践 Spring Boot 2.0 spring.io 官网有句醒目的话是: BUILD ANYTHING WITH SPRING BOOT Spring Boot ( ...

  9. sql获取各种时间格式的方法

    ),)--月/日/年 ),)--年.月.日 (常用) ),)--日/月/年 ),)--日.月.年 ),)--日-月-年 ),)--日 月 年

  10. C语言-查找一个元素在数组中的位置

    #include<stdio.h> #include <stdlib.h> #include <time.h> int search(int key, int a[ ...