Task: Create a single-threaded, persistent key/value store server and client
with synchronous networking over a custom protocol.
任务:创建一个单线程、持久化的键/值存储服务器和客户端,通过自定义协议实现同步网络通信。
Goals: 目标:
- Create a client-server application
创建一个客户端-服务器应用程序 - Write a custom protocol with
std
networking APIs
使用std
网络 API 编写自定义协议 - Introduce logging to the server
为服务器引入日志记录功能 - Implement pluggable backends with traits
使用特质实现可插拔的后端 - Benchmark the hand-written backend against
sled
针对sled
对手写后端进行基准测试
Topics: std::net
, logging, traits, benchmarking.
主题: std::net
、日志记录、特质、基准测试。
- Introduction 简介
- Project spec 项目规范
- Project setup 项目设置
- Part 1: Command line parsing
第一部分:命令行解析 - Part 2: Logging 第二部分:日志记录
- Part 3: Client-server networking setup
第三部分:客户端-服务器网络设置 - Part 4: Implementing commands across the network
第四部分:跨网络实现命令 - Part 5: Pluggable storage engines
第五部分:可插拔存储引擎 - Part 6: Benchmarking 第六部分:性能基准测试
In this project you will create a simple key/value server and client. They will
communicate with a custom networking protocol of your design. You will emit logs
using standard logging crates, and handle errors correctly across the network
boundary. Once you have a working client-server architecture,
then you will abstract the storage engine behind traits, and compare
the performance of yours to the sled
engine.
在本项目中,你将创建一个简单的键/值服务器和客户端。它们将通过你设计的自定义网络协议进行通信。你将使用标准日志记录库发出日志,并正确处理跨网络边界的错误。一旦建立了可工作的客户端-服务器架构,你将通过特性抽象存储引擎,并将你的引擎性能与 sled
引擎进行比较。
The cargo project, kvs
, builds a command-line key-value store client called
kvs-client
, and a key-value store server called kvs-server
, both of which in
turn call into a library called kvs
. The client speaks to the server over
a custom protocol.
Cargo 项目 kvs
构建了一个名为 kvs-client
的命令行键值存储客户端,以及一个名为 kvs-server
的键值存储服务器,两者都调用一个名为 kvs
的库。客户端通过自定义协议与服务器通信。
The kvs-server
executable supports the following command line arguments:
kvs-server
可执行文件支持以下命令行参数:
-
kvs-server [--addr IP-PORT] [--engine ENGINE-NAME]
Start the server and begin listening for incoming connections.
--addr
accepts an IP address, either v4 or v6, and a port number, with the formatIP:PORT
. If--addr
is not specified then listen on127.0.0.1:4000
.
启动服务器并开始监听传入的连接。--addr
接受一个 IP 地址(IPv4 或 IPv6)和一个端口号,格式为IP:PORT
。如果未指定--addr
,则监听127.0.0.1:4000
。If
--engine
is specified, thenENGINE-NAME
must be either "kvs", in which case the built-in engine is used, or "sled", in which case sled is used. If this is the first run (there is no data previously persisted) then the default value is "kvs"; if there is previously persisted data then the default is the engine already in use. If data was previously persisted with a different engine than selected, print an error and exit with a non-zero exit code.
如果指定了--engine
,则ENGINE-NAME
必须为“kvs”(此时使用内置引擎)或“sled”(此时使用 sled 引擎)。若是首次运行(无先前持久化数据),默认值为“kvs”;若存在先前持久化数据,则默认使用当前正在使用的引擎。若先前持久化数据使用的引擎与所选引擎不同,则打印错误信息并以非零退出码退出。Print an error and return a non-zero exit code on failure to bind a socket, if
ENGINE-NAME
is invalid, ifIP-PORT
does not parse as an address.
在以下情况下打印错误并返回非零退出码:绑定套接字失败、ENGINE-NAME
无效、IP-PORT
无法解析为地址。 -
kvs-server -V
Print the version. 打印版本信息。
The kvs-client
executable supports the following command line arguments:
kvs-client
可执行文件支持以下命令行参数:
-
kvs-client set <KEY> <VALUE> [--addr IP-PORT]
Set the value of a string key to a string.
将字符串键的值设置为字符串。--addr
accepts an IP address, either v4 or v6, and a port number, with the formatIP:PORT
. If--addr
is not specified then connect on127.0.0.1:4000
.
--addr
接受一个 IP 地址,可以是 v4 或 v6 版本,以及一个端口号,格式为IP:PORT
。如果未指定--addr
,则默认连接127.0.0.1:4000
。Print an error and return a non-zero exit code on server error, or if
IP-PORT
does not parse as an address.
在服务器错误或IP-PORT
无法解析为地址时,打印错误并返回非零退出码。 -
kvs-client get <KEY> [--addr IP-PORT]
Get the string value of a given string key.
获取给定字符串键的字符串值。--addr
accepts an IP address, either v4 or v6, and a port number, with the formatIP:PORT
. If--addr
is not specified then connect on127.0.0.1:4000
.
--addr
接受一个 IP 地址,可以是 v4 或 v6 版本,以及一个端口号,格式为IP:PORT
。如果未指定--addr
,则默认连接127.0.0.1:4000
。Print an error and return a non-zero exit code on server error, or if
IP-PORT
does not parse as an address.
在服务器错误或IP-PORT
无法解析为地址时,打印错误并返回非零退出码。 -
kvs-client rm <KEY> [--addr IP-PORT]
Remove a given string key.
移除指定的字符串键。--addr
accepts an IP address, either v4 or v6, and a port number, with the formatIP:PORT
. If--addr
is not specified then connect on127.0.0.1:4000
.
--addr
接受一个 IP 地址,可以是 v4 或 v6,以及一个端口号,格式为IP:PORT
。如果未指定--addr
,则连接到127.0.0.1:4000
。Print an error and return a non-zero exit code on server error, or if
IP-PORT
does not parse as an address. A "key not found" is also treated as an error in the "rm" command.
在服务器错误或IP-PORT
无法解析为地址时,打印错误并返回非零退出码。在“rm”命令中,“未找到键”也被视为错误。 -
kvs-client -V
Print the version. 打印版本信息。
All error messages should be printed to stderr.
所有错误信息应输出至标准错误流(stderr)。
The kvs
library contains four types:
kvs
库包含四种类型:
KvsClient
- implements the functionality required forkvs-client
to speak tokvs-server
KvsClient
- 实现kvs-client
与kvs-server
通信所需的功能KvsServer
- implements the functionality to serve responses tokvs-client
fromkvs-server
KvsServer
- 实现向来自kvs-server
的kvs-client
提供响应的功能KvsEngine
trait - defines the storage interface called byKvsServer
KvsEngine
trait - 定义由KvsServer
调用的存储接口KvStore
- implements by hand theKvsEngine
trait
KvStore
- 手动实现KvsEngine
traitSledKvsEngine
- implementsKvsEngine
for thesled
storage engine.
SledKvsEngine
- 为sled
存储引擎实现KvsEngine
The design of KvsClient
and KvsServer
are up to you, and will be informed by
the design of your network protocol. The test suite does not directly use either
type, but only exercises them via the CLI.
KvsClient
和 KvsServer
的设计由您决定,并将根据您的网络协议设计来指导。测试套件不会直接使用任一类型,而是仅通过 CLI 来测试它们。
The KvsEngine
trait supports the following methods:
KvsEngine
特性支持以下方法:
-
KvsEngine::set(&mut self, key: String, value: String) -> Result<()>
Set the value of a string key to a string.
将字符串键的值设置为字符串。Return an error if the value is not written successfully.
如果值未成功写入,则返回错误。 -
KvsEngine::get(&mut self, key: String) -> Result<Option<String>>
Get the string value of a string key. If the key does not exist, return
None
.
获取字符串键的字符串值。如果键不存在,返回None
。Return an error if the value is not read successfully.
如果值未成功读取,则返回错误。 -
KvsEngine::remove(&mut self, key: String) -> Result<()>
Remove a given string key.
移除指定的字符串键。Return an error if the key does not exit or value is not read successfully.
如果键不存在或值未成功读取,则返回错误。
When setting a key to a value, KvStore
writes the set
command to disk in
a sequential log. When removing a key, KvStore
writes the rm
command to
the log. On startup, the commands in the log are re-evaluated and the
log pointer (file offset) of the last command to set each key recorded in the
in-memory index.
当设置键值时, KvStore
将 set
命令顺序写入磁盘日志中。删除键时, KvStore
将 rm
命令写入日志。启动时,日志中的命令会被重新执行,并且最后一个设置每个键的命令的日志指针(文件偏移量)会被记录在内存索引中。
When retrieving a value for a key with the get
command, it searches the index,
and if found then loads from the log, and evaluates, the command at the
corresponding log pointer.
使用 get
命令检索键的值时,它会搜索索引,如果找到则从日志中加载并评估对应日志指针处的命令。
When the size of the uncompacted log entries reach a given threshold, KvStore
compacts it into a new log, removing redundant entries to reclaim disk space.
当未压缩的日志条目大小达到给定阈值时, KvStore
会将其压缩为一个新日志,删除冗余条目以回收磁盘空间。
Continuing from your previous project, delete your previous tests
directory and
copy this project's tests
directory into its place. This project should
contain a library named kvs
, and two executables, kvs-server
and
kvs-client
.
继续你之前的项目,删除之前的 tests
目录,并将此项目的 tests
目录复制到其位置。此项目应包含一个名为 kvs
的库,以及两个可执行文件 kvs-server
和 kvs-client
。
You need the following dev-dependencies in your Cargo.toml
:
您的 Cargo.toml
需要以下开发依赖项:
[dev-dependencies]
assert_cmd = "0.11"
criterion = "0.3"
predicates = "1.0.0"
rand = "0.6.5"
tempfile = "3.0.7"
walkdir = "2.2.7"
As with previous projects, add enough definitions that the test suite builds.
与之前的项目一样,添加足够的定义以使测试套件能够构建。
There's little new about the command line parsing in this project compared to
previous projects. The kvs-client
binary accepts the same command line
arguments as in previous projects. And now kvs-server
has its own set of
command line arguments to handle, as described previously in the spec.
与之前的项目相比,本项目在命令行解析方面并无太多新内容。 kvs-client
二进制文件接受的命令行参数与之前项目相同。而现在 kvs-server
也有自己的一套命令行参数需要处理,正如规范中先前所述。
Stub out the kvs-server
command line handling.
暂存 kvs-server
的命令行处理逻辑。
Production server applications tend to have robust and configurable logging. So
now we're going to add logging to kvs-server
, and as we continue will look
for useful information to log. During development it is common to use logging
at the debug!
and trace!
levels for "println debugging".
生产环境服务器应用通常具备强大且可配置的日志功能。因此,我们现在将为 kvs-server
添加日志记录,并随着开发进程寻找有用的信息进行记录。在开发过程中,常使用 debug!
和 trace!
级别的日志进行“println 调试”。
There are two prominent logging systems in Rust: log
and slog
. Both
export similar macros for logging at different levels, like error!
, info!
etc. Both are extensible, supporting different backends, for logging to the
console, logging to file, logging to the system log, etc.
Rust 中有两大主流日志系统: log
和 slog
。两者都提供了不同级别的日志宏,如 error!
、 info!
等。两者均具有可扩展性,支持多种后端,如控制台日志、文件日志、系统日志等。
The major difference is that log
is fairly simple, logging only formatted
strings; slog
is feature-rich, and supports "structured logging", where log
entries are typed and serialized in easily-parsed formats.
主要区别在于, log
较为简单,仅记录格式化字符串;而 slog
功能丰富,支持“结构化日志”,即日志条目带有类型并以易于解析的格式序列化。
log
dates from the very earliest days of Rust, where it was part of the
compiler, then part of the standard library, and finally released as its own
crate. It is maintained by the Rust Project. slog
is newer and maintained
independently. Both are widely used.
log
可追溯至 Rust 的早期阶段,最初作为编译器的一部分,后纳入标准库,最终独立发布为一个 crate。它由 Rust 项目维护。 slog
则较新且由独立团队维护。两者均被广泛使用。
For both systems, one needs to select a "sink" crate, one that the logger
sends logs to for display or storage.
对于这两个系统,都需要选择一个“接收器”crate,即日志器将日志发送至此处以显示或存储。
Read about both of them, choose the one that appeals to you, add them as
dependencies, then modify kvs-server
to initialize logging on startup, prior
to command-line parsing. Set it up to output to stderr (sending the logs
elsewhere additionally is fine, but they must go to stderr to pass the tests in
this project).
阅读两者的介绍,选择你偏好的那个,将其添加为依赖项,然后修改 kvs-server
以在启动时初始化日志记录,这应在命令行解析之前完成。设置其输出至 stderr(额外将日志发送至其他地方也可以,但必须确保日志能输出到 stderr 以通过本项目的测试)。
On startup log the server's version number. Also log the configuration. For now
that means the IP address and port, and the name of the storage engine.
启动时记录服务器的版本号。同时记录配置信息。目前这包括 IP 地址和端口,以及存储引擎的名称。
Next we're going to set up the networking. For this project you are going to be
using the basic TCP/IP networking APIs in std::net
: TcpListener
and
TcpStream
.
接下来我们将配置网络。在这个项目中,你将使用 std::net
中的基础 TCP/IP 网络 API: TcpListener
和 TcpStream
。
For this project, the server is synchronous and single-threaded. That means that
you will listen on a socket, then accept connections, and execute and respond to
commands one at a time. In the future we will re-visit this decision multiple
times on our journey toward an asynchronous, multi-threaded, and
high-performance database.
本项目中的服务器是同步且单线程的。这意味着你将监听一个套接字,然后接受连接,并逐一执行和响应命令。未来,在我们迈向异步、多线程及高性能数据库的旅程中,我们将多次重新审视这一决策。
Think about your manual testing workflow. Now that there are two executables to
deal with, you'll need a way to run them both at the same time. If you are like
many, you will use two terminals, running cargo run --bin kvs-server
in
one, where it runs until you press CTRL-D, and cargo run --bin kvs-client
in the other.
考虑一下你的手动测试流程。现在需要处理两个可执行文件,你需要一种同时运行它们的方法。如果你和许多人一样,会使用两个终端,在一个终端中运行 cargo run --bin kvs-server
(它会一直运行直到你按下 CTRL-D),在另一个终端中运行 cargo run --bin kvs-client
。
This is a good opportunity to use the logging macros for debugging. Go ahead and
log information about every accepted connection.
这是使用日志宏进行调试的好机会。继续记录每个接受的连接信息。
Before thinking about the protocol, modify kvs-server
to listen
for and accept connections, and kvs-client
to initiate connections.
在考虑协议之前,修改 kvs-server
以监听并接受连接,修改 kvs-client
以发起连接。
In the last project you defined the commands your database accepts, and learned
how to serialize and deserialize them to and from the log with serde
.
在上一个项目中,你定义了数据库接受的命令,并学习了如何使用 serde
将它们序列化到日志及从日志反序列化。
Now it's time to implement the key/value store over the network, remotely
executing commands that until now have been implemented within a single process.
As with the file I/O you worked on in the last project to create the log, you
will be serializing and streaming commands with the Read
and Write
traits.
现在是时候通过网络实现键值存储,远程执行那些迄今为止仅在单个进程内实现的命令了。正如你在上一个项目中为创建日志而处理的文件 I/O 一样,你将使用 Read
和 Write
特性来序列化和流式传输命令。
You are going to design a network protocol. There are a number of ways to get
data in and out of a TCP stream, and a number of decisions to make. Is it a
text-based protocol, binary? How is the data translated from its format in
memory to its format byte-stream format? Is there a single request per
connection, or many?
你将设计一个网络协议。有多种方法可以在 TCP 流中传输数据,也有多个决策需要做出。它是基于文本的协议还是二进制协议?数据如何从内存中的格式转换为字节流格式?每个连接是单一请求还是多个请求?
Keep in mind that it must support successful results and errors, and there are
two kinds of errors now: the ones generated by your storage engine, as well as
network errors.
请记住,它必须支持成功结果和错误处理,目前有两种错误类型:一种由您的存储引擎生成,另一种是网络错误。
All the details of the protocol are up to you. The test suite does not care at
all how the data gets from one end to the other, just that the results are
correct.
协议的所有细节由您决定。测试套件完全不关心数据如何从一端传输到另一端,只关注结果是否正确。
Write your network protocol.
编写您的网络协议。
Your database has a storage engine, KvStore
, implemented by you.
Now you are going to add a second storage engine.
您的数据库已有一个由您实现的存储引擎 KvStore
。现在,您将添加第二个存储引擎。
There are multiple reasons to do so:
这样做有多种原因:
-
Different workloads require different performance characteristics. Some storage engines may work better than other based on the workload.
不同的工作负载需要不同的性能特征。根据工作负载的不同,某些存储引擎可能比其他引擎表现更优。 -
It creates a familiar framework for comparing different backends.
这为比较不同的后端创建了一个熟悉的框架。 -
It gives us an excuse to create and work with traits.
这给了我们一个创建和使用特性的理由。 -
It gives us an excuse to write some comparative benchmarks!
这给了我们编写一些对比基准测试的借口!
So you are going to extract a new trait, KvsEngine
, from the KvStore
interface. This is a classic refactoring, where existing code is transformed
into a new form incrementally. When refactoring you will generally want to break
the work up into the smallest changes that will continue to build and work.
所以你打算从 KvStore
接口中提取一个新的特性 KvsEngine
。这是一个经典的重构过程,现有代码会逐步转变为新的形式。进行重构时,通常需要将工作分解为能持续构建和运行的最小变更单元。
Here is the API you need to end up with:
这是您最终需要的 API:
-
trait KvsEngine
hasget
,set
andremove
methods with the same signatures asKvStore
.
trait KvsEngine
拥有与KvStore
相同签名的get
、set
和remove
方法。 -
KvStore
implementsKvsEngine
, and no longer hasget
,set
andremove
methods of its own.
KvStore
实现了KvsEngine
,并且不再拥有自己的get
、set
和remove
方法。 -
There is a new implementation of
KvsEngine
,SledKvsEngine
. You need to fill itsget
andset
methods using thesled
library later.
有一个新的KvsEngine
实现,即SledKvsEngine
。您稍后需要使用sled
库来填充其get
和set
方法。
It's likely that you have already stubbed out the definitions for these if your
tests are building. Now is the time to fill them in. Break down your
refactoring into an intentional sequence of changes, and make sure the project
continues to build and pass previously-passing tests before continuing.
如果你的测试正在构建中,很可能你已经为这些定义打好了桩。现在是时候填充它们了。将你的重构分解为一系列有意的变更步骤,并确保项目在继续之前能够持续构建并通过之前通过的测试。
As one final step, you need to consider what happens when kvs-server
is
started with one engine, is killed, then restarted with a different engine. This
case can only result in an error, and you need to figure out how to detect the
case to report the error. The test cli_wrong_engine
reflects this scenario.
作为最后一步,你需要考虑当 kvs-server
以一个引擎启动后被终止,随后又以不同引擎重启时会发生什么。这种情况只会导致错误,你需要找出如何检测这种情况以报告错误。测试 cli_wrong_engine
反映了这一场景。
As the course progresses we will increasingly concern ourselves with the
performance of the database, exploring the impact of different architectures.
You are encouraged to go beyond the model described herein and experiment with
your own optimizations.
随着课程的深入,我们将越来越多地关注数据库的性能,探索不同架构的影响。鼓励您超越本文描述的模型,尝试自己的优化方案。
Performance work requires benchmarking, so now we're going to get started
on that. There are many ways to benchmark databases, with standard test
suites like ycsb and sysbench. In Rust benchmarking starts with
the builtin tooling, so we will start there.
性能工作需要基准测试,因此我们现在就要着手进行。数据库基准测试有多种方法,包括使用 ycsb 和 sysbench 等标准测试套件。在 Rust 中,基准测试始于内置工具,我们将从这里开始。
Cargo supports benchmarking with cargo bench
. The benchmarks may either be
written using Rust's built in benchmark harness, or an external one.
Cargo 支持通过 cargo bench
进行基准测试。基准测试可以使用 Rust 内置的测试框架编写,也可以使用外部框架。
The built-in harness creates benchmarks from functions with the #[bench]
attribute. It cannot be used on the Rust stable channel though, and is only
documented briefly in the unstable book and the test
crate docs.
It is though widely used throughout the Rust ecosystem — crates that use
it, even if they compile with stable releases, do benchmarking with nightly
releases.
内置框架通过带有 #[bench]
属性的函数创建基准测试。不过,它不能在 Rust 稳定版通道中使用,仅在《不稳定手册》和 test
crate 文档中有简要说明。尽管如此,它在 Rust 生态系统中被广泛使用——即使使用稳定版编译的 crate,也会在 nightly 版本中进行基准测试。
That system though is effectively deprecated — it is not being updated and
will seemingly never be promoted to the stable release channel.
然而,该系统实际上已被弃用——它不再更新,似乎也永远不会被提升到稳定发布通道。
There are better benchmark harnesses for Rust anyway. The one you will use is
criterion. And you will use it to satisfy your curiosity about the
performance of your kvs
engine compared to the sled
engine.
无论如何,Rust 有更好的基准测试工具。你将使用的是 criterion。你会用它来满足你对 kvs
引擎与 sled
引擎性能比较的好奇心。
These benchmarking tools work by defining a benchmarking function, and within
that function iterating through a loop that performs the operation to be
benchmarking. The benchmarking tool will iterate as many times as it needs to in
order to know the duration of the operation with statistical significance.
这些基准测试工具的工作原理是定义一个基准测试函数,在该函数中循环执行待测操作。基准测试工具会根据需要多次迭代,以统计显著性确定操作的持续时间。
See this basic example from the criterion guide:
参见 criterion 指南中的这个基础示例:
fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("fib 20", |b| {
b.iter(|| {
fibonacci(20)
});
});
}
The call to bench_function
defines the benchmark, and the call to iter
defines the code that is run for the benchmark. Code before and after the call
to iter
is not timed.
调用 bench_function
定义基准测试,调用 iter
定义用于基准测试运行的代码。在调用 iter
之前和之后的代码不计时。
Prepare for writing benchmarks by creating a file called benches/benches.rs
.
Like tests/tests.rs
, cargo will automatically find this file and compile it as
a benchmark.
通过创建一个名为 benches/benches.rs
的文件来准备编写基准测试。类似于 tests/tests.rs
,cargo 会自动找到此文件并将其编译为基准测试。
Start by writing the following benchmarks:
从编写以下基准测试开始:
-
kvs_write
- With the kvs engine, write 100 values with random keys of length 1-100000 bytes and random values of length 1-100000 bytes.
kvs_write
- 使用 kvs 引擎,写入 100 个值,键为 1-100000 字节的随机长度,值为 1-100000 字节的随机长度。 -
sled_write
- With the sled engine, write 100 values with random keys of length 1-100000 bytes and random values of length 1-100000 bytes.
sled_write
- 使用 sled 引擎,写入 100 个键值对,键的长度为 1-100000 字节随机,值的长度也为 1-100000 字节随机。 -
kvs_read
- With the kvs engine, read 1000 values from previously written keys, with keys and values of random length.
kvs_read
- 使用 kvs 引擎,从之前写入的键中读取 1000 个值,键和值的长度随机。 -
sled_read
- With the sled engine, read 1000 values from previously written keys, with keys and values of random length.
sled_read
- 使用 sled 引擎,从之前写入的键中读取 1000 个值,键和值的长度随机。
(As an alternative to writing 4 benchmarks, you may also choose to write 2
benchmarks parameterized over the engine, as described in the criterion
manual).
(作为编写 4 个基准测试的替代方案,您也可以选择编写 2 个参数化引擎的基准测试,如 criterion 手册中所述)。
These are underspecified, and there's a fair bit of nuance to implementing them
in a useful way. We need to consider at least three factors:
这些定义不够明确,且在实际应用中实现它们时存在不少细微差别。我们至少需要考虑三个因素:
-
What code should be timed (and be written inside the benchmark loop), and what code should not (and be written outside the benchmark loop)?
哪些代码应该被计时(并写入基准测试循环内部),哪些代码不应该(并写在基准测试循环外部)? -
How to make the loop run identically for each iteration, despite using "random" numbers.
尽管使用了“随机”数字,如何使每次迭代的循环运行保持一致。 -
In the "read" benchmarks, how to read from the same set of "random" keys that were written previously.
在“读取”基准测试中,如何从先前写入的同一组“随机”键中读取数据。
These are all inter-related: some code needs to be carefully selected as
un-timed setup code, and the seed values for random number generators need
to be re-used appropriately.
这些都是相互关联的:需要精心选择一些代码作为不计时的设置代码,并且需要适当重用随机数生成器的种子值。
In all cases, operations that may return errors should assert (with assert!
)
that they did not return an error; and in the read case, "get" operations should
assert that the key was found.
在所有情况下,可能返回错误的操作应断言(使用 assert!
)它们未返回错误;而在读取情况下,“获取”操作应断言已找到该键。
Random numbers can be generated with the rand
crate.
可以使用 rand
crate 生成随机数。
Once you have your benchmarks, run them with cargo bench
.
一旦你有了基准测试,使用 cargo bench
运行它们。
Write the above benchmarks, and compare the results between kvs
and sled
.
编写上述基准测试,并比较 kvs
和 sled
之间的结果。
Note: please run the benchmarks on an otherwise unloaded machine. Benchmark
results are very sensitive to the environment they are run in, and while the
criterion library does its best to compensate for "noise", benchmarks are best
done on a clean machine without other active processes. If you have a spare
machine just for development, use that. If not, an AWS or other cloud instance
may produce more consistent results than your local desktop.
注意:请在无其他负载的机器上运行基准测试。基准测试结果对运行环境非常敏感,尽管 criterion 库尽力补偿“噪音”,但最好在没有其他活动进程的干净机器上进行基准测试。如果你有一台专门用于开发的备用机器,请使用它。如果没有,AWS 或其他云实例可能比本地桌面产生更一致的结果。
Nice coding, friend. Enjoy a nice break.
代码写得不错,朋友。好好休息一下吧。