微软支持并发的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. GStreamer基础教程09 - Appsrc及Appsink

    摘要 在我们前面的文章中,我们的Pipline都是使用GStreamer自带的插件去产生/消费数据.在实际的情况中,我们的数据源可能没有相应的gstreamer插件,但我们又需要将数据发送到GStre ...

  2. 23种设计模式之原型模式(Prototype Pattern)

    原型模式 使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象 分析: 孙悟空:根据自己的形状复制(克隆)出多个身外身 软件开发:通过复制一个原型对象得到多个与原型对象一模一样的新对象 ...

  3. 利用threading模块开线程

    一多线程的概念介绍 threading模块介绍 threading模块和multiprocessing模块在使用层面,有很大的相似性. 二.开启多线程的两种方式 1.创建线程的开销比创建进程的开销小, ...

  4. YiShaAdmin,基于.NET Core Web开源的后台快速开发框架

    YiShaAdmin YiShaAdmin 基于.NET Core Web开发,借鉴了很多开源项目的优点,让你开发Web管理系统和移动端Api更简单,所以我也把她开源了. 她可以用于所有的Web应用程 ...

  5. ELK 学习笔记之 elasticsearch Shard和Segment概念

    Shard和segment概念: 转载: http://blog.csdn.net/likui1314159/article/details/53217750 Shard(分片) 一个Shard就是一 ...

  6. 微服务架构-利用Redis特性进行业务解耦

    背景:     接着上篇文章来,上篇文章讲的是如何利用ApplicationContext的事件机制来达到业务解耦,而且这只能作用在单体应用中.在当下这么盛行的微服务架构中,想要再利用此方案做业务解耦 ...

  7. Java-Thread00之多线程知识准备

    ------ ![](https://img2018.cnblogs.com/blog/1822322/201910/1822322-20191012170014292-1661101986.jpg) ...

  8. IoC 之加载 Bean:总结

    上文中我们将bean已经加载到了IOC容器中,接下来我们将把IOC加载Bean出来进行代码解析 备注:(有些解释是参考别个博客的相关解释 )一起探讨请加我QQ:1051980588 bean 的初始化 ...

  9. CRS-2674: Start of 'ora.cssd' on 'rac2' failed 引发的rac集群服务起不来问题

    问题背景:客户反馈Oracle rac集群节点宕机 1.首先查看宕机原因,归档日志满导致服务重启,查看归档日志路径是USE_DB_RECOVERY_FILE_DEST (默认路径), 安装的时候没有做 ...

  10. canvas实现平面迁徙图

    前言 最近在做自己维护的一个可视化工具的时候,在添加基于echart的雷达图的时候,按照echart官网案例写完发现在自己项目中无法正常运行,排查了一番发现是我项目中echart的版本太低.找到问题原 ...