热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

『每周译Go』YYDS!Go如何编写简单的内存键值数据库

从Postgres到Redis,再到Prometheus,我们都使用并从事过各种数据库的开发。我花了很多时间来阅读其中一些数据库的源代码,

4a835635d35f934aba3e565b577e5196.png

从 Postgres 到 Redis,再到 Prometheus,我们都使用并从事过各种数据库的开发。我花了很多时间来阅读其中一些数据库的源代码,对于那些像我一样好奇的少数人来说,他们有兴趣学习如何编写一个数据库。本书旨在记录这一过程。

GitHub-arriqaaq/flashdb:

FlashDB is an embeddable, in-memory key/value database in Go (with Redis like commands)

01

内存数据库 

传统数据库的数据主要保存在机械硬盘或者固态硬盘, 内存数据库则主要将数据保存在内存中,并通过消除对磁盘的访问来实现最小的响应时间。两者的不同主要体现在内存数据库是将数据保存在主存或者 RAM 中,而传统的数据库则是通过驱动磁盘来获取数据。

内存数据库相比传统数据库更不稳定,由于所有的数据都存储与管理在主存中,当计算机断电或 RAM 崩溃时,数据将会丢失。

内存数据库可以通过将每个操作存储在日志中或采取快照的方式在磁盘上持久化数据

02

目标 

我们的目标是用 Go 编写一个简单、快速、嵌入式和可持久化的键/值数据库,并且实现以下功能:

  • 支持类似 Redis 的数据结构string, hash, set, zset

  • 具有低延时和高吞吐量

  • 支持事务,ACID 语义

  • 仅可写入的持久化文件格式

  • 可以通过使用 TTL 来处理数据过期

03

开始

我们要建立的是一个非常简单的 KV(键/值)存储,以便让每个人都能轻松理解和实现。在 Go 中,有相当多的嵌入式键/值存储可用,以下是一些例子:

  • BadgerDB - BadgerDB 是一个完全用 Go 编写的嵌入式、可持久化、简单而快速的键值(KV)数据库。它旨在成为 RocksDB 等非基于 Go 实现的键值存储的高性能替代品

  • BoltDB - BoltDB 是一个基于 B+ 树的嵌入式 Go 键/值数据库

  • BuntDB - BuntDB 是一个应用于 Go 的嵌入式内存键/值数据库,具有自定义索引和地理空间支持

  • go-memdb - 基于不可变基数树的 Golang 内存数据库

  • nutsdb - 一个基于磁盘的键值存储

读起来容易做起来难。虽然我们可以通过阅读庞大的代码库来了解其内部结构,但这对很多人来说依旧是一个障碍。我们的初衷是为任何想学习关于如何编写一个简单的 ACID 数据库的新手提供桥梁。

NutsDB 是我在 2-3 年前读到的第一批简单易懂的代码之一。因此,我们选择由易于理解的组合库组成的FlashDB。

04

架构 

FlashDB 的架构很简单并且支持各种 Redis 命令。Redis 本质上不是一个普通的键值存储,而是一个数据结构服务器,支持不同种类的值。事实上,Redis 使用以下数据结构实现了各种类型。

27266d5c4869de8a0d97b51f492ee694.png

05

字符串

Redis 字符串类型是能与 Redis 键关联的最简单的值类型。由于 Redis 键是字符串,当我们把字符串类型也作为一个值时,实际上是把一个字符串映射到另一个字符串。这是用可变基数树(ART)实现的,这样可以很容易进行扫描。

  • String

 (https://github.com/arriqaaq/skiplist)

06

哈希

用哈希表示对象很方便,而实际上哈希中可放入的字段数量并没有实际限制(除了可用的内存),所以你可以在应用程序中以许多不同的方式使用哈希。这是用一个非常简单的 HashMap 数据结构实现的。

  • Hash

    (https://github.com/arriqaaq/hash)

07

集合 

Redis 集合是无序的字符串集合。我们可以对集合进行一些操作,比如检测某个元素是否已经存在,查找多个集合之间的交集、并集或差集等。这也是用一个简单的 HashMap 数据结构实现的。

  • Set

(https://github.com/arriqaaq/set)

08

有序集合 

有序集合是一种数据类型,类似于集合与哈希的混合体。和集合一样,有序集合也是由唯一的、不重复的字符串元素组成的。所以从某种意义上说,有序集合也是一个集合。

虽然集合内的元素并不是有序的,但有序集合中的每个元素都与一个浮点值相关,称为分数(该类型类似于哈希,因为每个元素都被映射到一个值)。

这是对用于字符串的跳表结构稍加修改实现的。

  • ZSet 

    (https://github.com/arriqaaq/zset)

09

持久化

虽然已经有了很多持久化机制,但我选择了一个简单的 append-only 日志设计方式,因为它比较容易实现和理解。

AOF(仅可写入的文件)记录了服务器收到的每一个写操作,这些操作将在服务器启动时再重放,重建原始数据集。命令的记录格式与 API 协议本身相同,以只写入的方式进行。当日志过大时,FlashDB 能够在后台分片处理日志。这是基于 wal 实现的。

  • Append Only Log

    (https://github.com/arriqaaq/aol)

总结

综上,FlashDB 仅依靠上述五个简单的库就完成了,具有事务与 ACID 支持,易于理解。但我希望这对任何有兴趣学习如何编写数据库的人来说都是一个有用的教程。

GitHub - arriqaaq/flashdb: 

FlashDB is an embeddable, in-memory key/value database in Go (with Redis like commands)

讲座

最近在 Golang meetup 上分享了这个项目,这是幻灯片的内容:

https://www.canva.com/design/DAE8sGRyC2o/ZCuCaezQ6dYA0Oq24QxjUQ/view?utm_content=DAE8sGRyC2o&utm_campaign=designshare&utm_medium=link&utm_source=publishsharelink

原文地址:

https://aly.arriqaaq.com/building-a-database-in-go

原文作者:Farhan Aly

本文永久链接:https://github.com/gocn/translator/blob/master/2022/w17_Writing_a_simple_in-memory_key-value_Database_in_Go.md

译者:张宇

校对:小超人

想要了解更多相关的内容,欢迎扫描下方👇 关注 公众号,回复关键词 [实战群]  ,就有机会进群和我们进行交流~

184dffc9c2e346e5bd0e4a7fc810ae6a.png

分享、在看与点赞,至少我要拥有一个叭~

add4ffbc9630b8ea10a4f443676fb76f.gif

511df96253cf3169783803c372e91595.gif


推荐阅读
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性
    Java并发编程实践目录并发编程01——ThreadLocal并发编程02——ConcurrentHashMap并发编程03——阻塞队列和生产者-消费者模式并发编程04——闭锁Co ... [详细]
  • 实用正则表达式有哪些
    小编给大家分享一下实用正则表达式有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下 ... [详细]
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
  • 历经三十年的开发,Mathematica 已成为技术计算领域的标杆,为全球的技术创新者、教育工作者、学生及其他用户提供了一个领先的计算平台。最新版本 Mathematica 12.3.1 增加了多项核心语言、数学计算、可视化和图形处理的新功能。 ... [详细]
  • 在 Android 开发中,通过 Intent 启动 Activity 或 Service 时,可以使用 putExtra 方法传递数据。接收方可以通过 getIntent().getExtras() 获取这些数据。本文将介绍如何使用 RoboGuice 框架简化这一过程,特别是 @InjectExtra 注解的使用。 ... [详细]
  • 本文详细介绍了 Java 中 org.geotools.data.shapefile.ShapefileDataStore 类的 getCurrentTypeName() 方法,并提供了多个代码示例,帮助开发者更好地理解和使用该方法。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 请看|间隔时间_Postgresql 主从复制 ... [详细]
  • Redis安全防护深入解析
    本文详细探讨了如何通过指令安全、端口管理和SSL代理等措施有效保护Redis服务的安全性。 ... [详细]
  • Docker 自定义网络配置详解
    本文详细介绍如何在 Docker 中自定义网络设置,包括网关和子网地址的配置。通过具体示例展示如何创建和管理自定义网络,以及容器间的通信方式。 ... [详细]
  • 本文将探讨从ASP.NET 1.1到2.0期间编译系统的重要变革。通过对比两个版本的即时编译模型,我们将揭示2.0版本中引入的新特性和改进之处。 ... [详细]
  • 本文探讨了SSDP(简单服务发现协议)和WSD(Web服务发现)协议,特别是SSDP如何通过固定多播地址239.255.255.250:1900实现局域网内的服务自发现功能。文中还详细介绍了SSDP协议的关键操作类型及其应用场景。 ... [详细]
  • 本文介绍了在CentOS 6.4系统中安装MySQL 5.5.37时遇到的启动失败和PID文件问题,并提供了详细的解决方案,包括日志分析、权限检查等步骤。 ... [详细]
  • 在Win10上利用VS2015构建Caffe2环境
    本文详细介绍如何在Windows 10操作系统上通过Visual Studio 2015编译Caffe2深度学习框架的过程。包括必要的软件安装、环境配置以及常见问题的解决方法。 ... [详细]
author-avatar
手机用户2602919091
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有