# RocksDB
# Hướng dẫn cài đặt RocksDB trên RHEL/Centos 7
Hướng dẫn cài đặt CSDL RocksDB trên môi trường hệ điều hành Redhat/Centos 7
[![rocksdb.png](https://laptrinh.vn/uploads/images/gallery/2020-05/scaled-1680-/rocksdb.png)](https://laptrinh.vn/uploads/images/gallery/2020-05/rocksdb.png)
#### Yêu cầu:
- **Java**: [OpenJDK 1.7+](https://adoptopenjdk.net/) (required only for RocksJava)
- Tools:
- curl (recommended; required only for RocksJava)
- Libraries:
- [gflags](https://gflags.github.io/gflags/) 2.0+ (required for testing and benchmark code)
- [zlib](http://www.zlib.net/) 1.2.8+ (optional)
- [bzip2](http://www.bzip.org/) 1.0.6+ (optional)
- [lz4](https://github.com/lz4/lz4) r131+ (optional)
- [snappy](http://google.github.io/snappy/) 1.1.3+ (optional)
- [zstandard](http://www.zstd.net) 0.5.1+ (optional)
- **Architecture**: x86 / x86\_64 / arm64 / ppc64le / s390x
- **C/C++ Compiler**: GCC 4.8+ or Clang
- Tools:
- GNU Make or [CMake](https://cmake.org/download/) 3.14.5+
#### Hướng dẫn cài đặt
##### -Cài gói gcc4.8:
```shell
yum install gcc48-c++
```
##### - Cài gói gflags:
```shell
cd /tmp/
git clone https://github.com/gflags/gflags.git
cd gflags
git checkout v2.0
./configure && make && sudo make install
```
##### - Thiết lập path:
```shell
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
```
##### - Cài gói snappy:
```shell
sudo yum install snappy snappy-devel
```
##### - Cài gói zlib:
```shell
sudo yum install zlib zlib-devel
```
##### - Cài gói bzip2:
```shell
sudo yum install bzip2 bzip2-devel
```
##### - Cài gói lz4:
```shell
sudo yum install lz4-devel
```
##### - Cài gói ASAN (optional for debugging):
```shell
sudo yum install libasan
```
##### - Cài gói zstandard:
```shell
cd /tmp/
wget https://github.com/facebook/zstd/archive/v1.1.3.tar.gz
mv v1.1.3.tar.gz zstd-1.1.3.tar.gz
tar zxvf zstd-1.1.3.tar.gz
cd zstd-1.1.3
make && sudo make install
```
##### - Cài đặt RocksDB:
```shell
cd /tmp/
git clone https://github.com/facebook/rocksdb.git
cd rocksdb
make static_lib
```
#### Tham khảo
\[1\] https://github.com/facebook/rocksdb/blob/master/INSTALL.md
# RocksDB - Open database
Để mở một database trong RocksDB, bạn có thể sử dụng command `rocksdb::DB::Open`. Dưới đây là một ví dụ về cách mở một database:
```java
import org.rocksdb.*;
public class RocksDBExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
// Thực hiện các thao tác trên database ở đây
} catch (RocksDBException e) {
// Xử lý lỗi khi mở database không thành công
}
}
}
```
Trong ví dụ trên, `options.setCreateIfMissing(true)` được sử dụng để tạo một database mới nếu database chưa tồn tại.
Đây chỉ là một số command và ví dụ cơ bản về cách mở database trong RocksDB bằng Java. RocksDB cung cấp nhiều command và tùy chọn khác nhau để quản lý và truy xuất dữ liệu.
Ví dụ C++:
```C++
#include "rocksdb/db.h"
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (!status.ok()) {
// Xử lý lỗi khi mở database không thành công
} else {
// Mở database thành công, bạn có thể thực hiện các thao tác khác trên database ở đây
}
```
# RocksDB - Iterator
Trong RocksDB, iterator được sử dụng để duyệt qua toàn bộ RocksDB và truy xuất dữ liệu. Iterator cho phép bạn lấy giá trị của các key trong RocksDB theo thứ tự tuần tự.
Dưới đây là một ví dụ về cách sử dụng iterator trong RocksDB bằng Java:
```java
import org.rocksdb.*;
public class RocksDBIteratorExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
try (final RocksIterator iterator = db.newIterator()) {
for (iterator.seekToFirst(); iterator.isValid(); iterator.next()) {
byte[] key = iterator.key();
byte[] value = iterator.value();
System.out.println("Key: " + new String(key) + ", Value: " + new String(value));
}
}
} catch (RocksDBException e) {
// Xử lý lỗi khi mở database không thành công
}
}
}
```
Trong ví dụ trên, chúng ta sử dụng `db.newIterator()` để tạo một iterator mới cho RocksDB. Với mỗi phần tử trong RocksDB, chúng ta sử dụng `iterator.key()` và `iterator.value()` để lấy giá trị của key và value tương ứng. Tiếp theo, chúng ta có thể thực hiện các thao tác xử lý với key và value như mong muốn.
## Iterator trong RocksDB với C++
Đối với C++, RocksDB cung cấp một API tương tự để sử dụng iterator. Dưới đây là một ví dụ về cách sử dụng iterator trong RocksDB bằng C++:
```C++
#include "rocksdb/db.h"
#include "rocksdb/iterator.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
rocksdb::Iterator* it = db->NewIterator(rocksdb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
rocksdb::Slice key = it->key();
rocksdb::Slice value = it->value();
std::cout << "Key: " << key.ToString() << ", Value: " << value.ToString() << std::endl;
}
delete it;
} else {
// Xử lý lỗi khi mở database không thành công
}
delete db;
return 0;
}
```
Trong ví dụ trên, chúng ta sử dụng `db->NewIterator(rocksdb::ReadOptions())` để tạo một iterator mới cho RocksDB. Với mỗi phần tử trong RocksDB, chúng ta sử dụng `it->key()` và `it->value()` để lấy giá trị của key và value tương ứng. Tiếp theo, chúng ta có thể thực hiện các thao tác xử lý với key và value như mong muốn.
# RocksDB - Put data
Trong RocksDB, `Put` được sử dụng để thêm một cặp key-value vào RocksDB. Dưới đây là các ví dụ về cách sử dụng `Put` trong RocksDB bằng Java và C++.
**Java:**
```java
import org.rocksdb.*;
public class RocksDBPutExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
byte[] key = "myKey".getBytes();
byte[] value = "myValue".getBytes();
db.put(key, value);
} catch (RocksDBException e) {
// Xử lý lỗi khi thêm key-value không thành công
}
}
}
```
**C++:**
```C++
#include "rocksdb/db.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
rocksdb::WriteOptions writeOptions;
rocksdb::Slice key = "myKey";
rocksdb::Slice value = "myValue";
db->Put(writeOptions, key, value);
} else {
// Xử lý lỗi khi thêm key-value không thành công
}
delete db;
return 0;
}
```
Trong cả hai ví dụ trên, chúng ta tạo một RocksDB database và sau đó sử dụng `Put` để thêm một cặp key-value vào database. Đường dẫn đến database và giá trị key-value có thể được tùy chỉnh theo nhu cầu của bạn.
Lưu ý rằng trong RocksDB, `Put` là một thao tác ghi đồng bộ, điều này có nghĩa là thao tác `Put` sẽ chờ cho đến khi dữ liệu thực sự được ghi vào ổ đĩa trước khi trả về. Điều này đảm bảo tính toàn vẹn của dữ liệu.
Đó là một số thông tin cơ bản về cách sử dụng `Put` trong RocksDB. Bạn có thể tìm hiểu thêm về các tùy chọn và tính năng khác của RocksDB trong tài liệu chi tiết của nó.
# RocksDB - Get data
Trong RocksDB, `Get` được sử dụng để truy vấn giá trị của một key trong database. Dưới đây là các ví dụ về cách sử dụng `Get` trong RocksDB bằng Java và C++.
**Java:**
```java
import org.rocksdb.*;
public class RocksDBGetExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
byte[] key = "myKey".getBytes();
byte[] value = db.get(key);
if (value != null) {
System.out.println("Value: " + new String(value));
} else {
System.out.println("Key not found");
}
} catch (RocksDBException e) {
// Xử lý lỗi khi truy vấn dữ liệu không thành công
}
}
}
```
**C++:**
```C++
#include "rocksdb/db.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
rocksdb::ReadOptions readOptions;
rocksdb::Slice key = "myKey";
std::string value;
rocksdb::Status get_status = db->Get(readOptions, key, &value);
if (get_status.ok()) {
std::cout << "Value: " << value << std::endl;
} else if (get_status.IsNotFound()) {
std::cout << "Key not found" << std::endl;
} else {
// Xử lý lỗi khi truy vấn dữ liệu không thành công
}
} else {
// Xử lý lỗi khi mở database không thành công
}
delete db;
return 0;
}
```
Trong cả hai ví dụ trên, chúng ta tạo một RocksDB database và sau đó sử dụng `Get` để truy vấn giá trị của một key trong database. Đường dẫn đến database và giá trị key có thể được tùy chỉnh theo nhu cầu của bạn.
Lưu ý rằng `Get` là một thao tác đồng bộ trong RocksDB. Điều này có nghĩa là thao tác `Get` sẽ chờ cho đến khi dữ liệu thực sự được đọc từ ổ đĩa trước khi trả về.
Đó là một số thông tin cơ bản về cách sử dụng `Get` trong RocksDB. Bạn có thể tìm hiểu thêm về các tùy chọn và tính năng khác của RocksDB trong tài liệu chi tiết của nó.
# RocksDB - Delete data
Trong RocksDB, `Delete` được sử dụng để xóa một key và giá trị tương ứng khỏi RocksDB. Dưới đây là các ví dụ về cách sử dụng `Delete` trong RocksDB bằng Java và C++.
**Java:**
```java
import org.rocksdb.*;
public class RocksDBDeleteExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
byte[] key = "myKey".getBytes();
db.delete(key);
} catch (RocksDBException e) {
// Xử lý lỗi khi xóa key không thành công
}
}
}
```
**C++:**
```C++
#include "rocksdb/db.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
rocksdb::WriteOptions writeOptions;
rocksdb::Slice key = "myKey";
rocksdb::Status delete_status = db->Delete(writeOptions, key);
if (!delete_status.ok()) {
// Xử lý lỗi khi xóa key không thành công
}
} else {
// Xử lý lỗi khi mở database không thành công
}
delete db;
return 0;
}
```
Trong cả hai ví dụ trên, chúng ta tạo một RocksDB database và sau đó sử dụng `Delete` để xóa một key và giá trị tương ứng khỏi database. Đường dẫn đến database và giá trị key có thể được tùy chỉnh theo nhu cầu của bạn.
Lưu ý rằng `Delete` là một thao tác ghi đồng bộ trong RocksDB. Điều này có nghĩa là thao tác `Delete` sẽ chờ cho đến khi dữ liệu xóa thực sự được ghi vào ổ đĩa trước khi trả về.
Đó là một số thông tin cơ bản về cách sử dụng `Delete` trong RocksDB. Bạn có thể tìm hiểu thêm về các tùy chọn và tính năng khác của RocksDB trong tài liệu chi tiết của nó.
# RocksDB - Merge data
Trong RocksDB, `Merge` được sử dụng để thực hiện phép gộp (merge) các giá trị tương ứng với một key trong RocksDB. Phép gộp này sẽ cộng giá trị mới vào giá trị hiện có của key đó, hoặc tạo giá trị mới nếu key chưa tồn tại trong RocksDB.
Dưới đây là một ví dụ về cách sử dụng `Merge` trong RocksDB bằng C++:
```C++
#include "rocksdb/db.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
rocksdb::WriteOptions writeOptions;
rocksdb::Slice key = "myKey";
rocksdb::Slice value = "myValue";
db->Merge(writeOptions, key, value);
} else {
// Xử lý lỗi khi thực hiện merge không thành công
}
delete db;
return 0;
}
```
Trong ví dụ trên, chúng ta tạo một RocksDB database và sau đó sử dụng `Merge` để thực hiện phép gộp các giá trị tương ứng với key "myKey". Nếu key đã tồn tại trong RocksDB, giá trị mới sẽ được cộng vào giá trị hiện có của key đó. Nếu key chưa tồn tại, RocksDB sẽ tạo một giá trị mới với giá trị được gán là "myValue".
Lưu ý rằng `Merge` là một thao tác ghi đồng bộ trong RocksDB, điều này có nghĩa là thao tác `Merge` sẽ chờ cho đến khi dữ liệu thực sự được ghi vào ổ đĩa trước khi trả về.
Đó là một số thông tin cơ bản về cách sử dụng `Merge` trong RocksDB. Bạn có thể tìm hiểu thêm về các tùy chọn và tính năng khác của RocksDB trong tài liệu chi tiết của nó.
# RocksDB - Write batch
`WriteBatch` trong RocksDB được sử dụng để thực hiện nhiều thao tác ghi (put, delete, merge) cùng một lúc, giúp tăng hiệu suất ghi dữ liệu. Điều này có thể đặc biệt hữu ích khi bạn muốn thực hiện nhiều thao tác ghi một cách liên tục mà không muốn mỗi thao tác phải chờ cho đến khi dữ liệu được ghi vào ổ đĩa trước khi thực hiện thao tác tiếp theo.
Dưới đây là một ví dụ về cách sử dụng `WriteBatch` trong RocksDB bằng C++:
```C++
#include "rocksdb/db.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
rocksdb::WriteBatch batch;
batch.Put("key1", "value1");
batch.Delete("key2");
batch.Merge("key3", "value3");
rocksdb::WriteOptions writeOptions;
rocksdb::Status write_status = db->Write(writeOptions, &batch);
if (write_status.ok()) {
// Thực hiện thành công
} else {
// Xử lý lỗi khi thực hiện ghi không thành công
}
} else {
// Xử lý lỗi khi mở database không thành công
}
delete db;
return 0;
}
```
**Java:**
```java
import org.rocksdb.*;
public class RocksDBWriteBatchExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
try (final WriteBatch batch = new WriteBatch()) {
byte[] key1 = "key1".getBytes();
byte[] value1 = "value1".getBytes();
batch.put(key1, value1);
byte[] key2 = "key2".getBytes();
batch.delete(key2);
byte[] key3 = "key3".getBytes();
byte[] value3 = "value3".getBytes();
batch.merge(key3, value3);
WriteOptions writeOptions = new WriteOptions();
db.write(writeOptions, batch);
} catch (RocksDBException e) {
// Xử lý lỗi khi thực hiện ghi không thành công
}
} catch (RocksDBException e) {
// Xử lý lỗi khi mở database không thành công
}
}
}
```
Trong ví dụ trên, chúng ta tạo một RocksDB database và sau đó sử dụng `WriteBatch` để thực hiện các thao tác ghi (put, delete, merge) trên các key tương ứng. Sau khi thêm các thao tác ghi vào `WriteBatch`, chúng ta sử dụng phương thức `Write` của RocksDB để thực hiện ghi tất cả các thao tác trong `WriteBatch` cùng một lúc.
Lưu ý rằng `WriteBatch` là một thao tác ghi đồng bộ trong RocksDB. Điều này có nghĩa là thao tác `Write` sẽ chờ cho đến khi tất cả các thao tác ghi trong `WriteBatch` được ghi vào ổ đĩa trước khi trả về.
Đó là một số thông tin cơ bản về cách sử dụng `WriteBatch` trong RocksDB. Bạn có thể tìm hiểu thêm về các tùy chọn và tính năng khác của RocksDB trong tài liệu chi tiết của nó.
# RocksDB - Rate Limiter
Rate Limiter trong RocksDB được sử dụng để giới hạn tốc độ đọc/ghi dữ liệu vào RocksDB. Điều này có thể hữu ích trong trường hợp đọc/ghi dữ liệu đang gây ảnh hưởng đến hoạt động của hệ thống khác.
Ví dụ sau đây minh họa cách sử dụng Rate Limiter trong RocksDB:
```
rocksdb::Options options;
options.rate_limiter = rocksdb::NewGenericRateLimiter(1000000, 10000, 10);
rocksdb::DB* db;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/db", &db);
if (status.ok()) {
// read/write data to db
}
```
Trong ví dụ này, chúng tôi tạo một Rate Limiter với tốc độ tối đa là 1MB/giây, tối đa 10.000 yêu cầu và giới hạn là 10MB. Sau đó, chúng tôi sử dụng Rate Limiter này khi mở RocksDB bằng cách đặt nó trong tùy chọn của RocksDB.
Một khi Rate Limiter đã được đặt, RocksDB sẽ tự động điều chỉnh tốc độ đọc/ghi dữ liệu vào RocksDB để đảm bảo không vượt quá giới hạn được xác định bởi Rate Limiter.
Đó là ví dụ cơ bản về việc sử dụng Rate Limiter trong RocksDB. Việc sử dụng Rate Limiter có thể giúp tối ưu hoá hiệu suất của RocksDB trong một số trường hợp cụ thể.
Ngoài ra, bạn cũng có thể sử dụng Rate Limiter trong RocksDB khi sử dụng Java bằng cách sử dụng các API của RocksJava. Dưới đây là một ví dụ về cách sử dụng Rate Limiter trong RocksJava:
```
Options options = new Options();
options.setCreateIfMissing(true);
RateLimiter rateLimiter = new GenericRateLimiter(1000000, 10000, 10);
options.setRateLimiter(rateLimiter);
try (RocksDB db = RocksDB.open(options, "/path/to/db")) {
// read/write data to db
}
```
Trong ví dụ này, chúng tôi tạo một Rate Limiter với tốc độ tối đa là 1MB/giây, tối đa 10.000 yêu cầu và giới hạn là 10MB. Sau đó, chúng tôi sử dụng Rate Limiter này khi mở RocksDB bằng cách đặt nó trong tùy chọn của RocksDB.
Một khi Rate Limiter đã được đặt, RocksDB sẽ tự động điều chỉnh tốc độ đọc/ghi dữ liệu vào RocksDB để đảm bảo không vượt quá giới hạn được xác định bởi Rate Limiter.
Đó là cách sử dụng Rate Limiter trong RocksJava. Việc sử dụng Rate Limiter có thể giúp tối ưu hoá hiệu suất của RocksDB trong một số trường hợp cụ thể.
# RocksDB - Prefix Seek
`Prefix Seek` trong RocksDB được sử dụng để tìm kiếm các key bắt đầu bằng một tiền tố cụ thể trong database. Phương thức `Prefix Seek` trả về iterator trỏ đến vị trí đầu tiên của key có tiền tố được chỉ định.
Dưới đây là một ví dụ về cách sử dụng `Prefix Seek` trong RocksDB bằng C++:
```C++
#include "rocksdb/db.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
rocksdb::ReadOptions readOptions;
rocksdb::Iterator* iterator = db->NewIterator(readOptions);
rocksdb::Slice prefix = "myPrefix";
iterator->Seek(prefix);
while (iterator->Valid() && iterator->key().starts_with(prefix)) {
// Xử lý key tương ứng
iterator->Next();
}
delete iterator;
} else {
// Xử lý lỗi khi mở database không thành công
}
delete db;
return 0;
}
```
Trong ví dụ trên, chúng ta tạo một RocksDB database và sử dụng `Prefix Seek` để tìm kiếm các key bắt đầu bằng tiền tố "myPrefix". Iterator trả về sẽ trỏ đến vị trí đầu tiên của key tương ứng. Tiếp theo, chúng ta sử dụng vòng lặp để duyệt qua các key có tiền tố "myPrefix". Khi iterator không còn hợp lệ hoặc key không còn bắt đầu bằng tiền tố "myPrefix", vòng lặp sẽ kết thúc.
Lưu ý rằng `Prefix Seek` không trả về các key theo thứ tự sắp xếp. Nếu bạn muốn lấy các key theo thứ tự sắp xếp, bạn cần thực hiện sắp xếp trong vòng lặp hoặc sử dụng các phương thức khác như `Prefix Enumerate` trong RocksDB.
Đó là một số thông tin cơ bản về cách sử dụng `Prefix Seek` trong RocksDB bằng C++. Bạn có thể tìm hiểu thêm về các tùy chọn và tính năng khác của RocksDB trong tài liệu chi tiết của nó.
# RocksDB - Compaction Filter
Compaction Filter trong RocksDB là một cơ chế cho phép bạn thực hiện các thay đổi tùy chỉnh trên dữ liệu khi RocksDB thực hiện quá trình Compaction. Quá trình Compaction là quá trình tối ưu hóa dữ liệu trong RocksDB bằng cách ghép các file SST thành file mới để tiết kiệm không gian lưu trữ và tăng hiệu suất truy vấn.
Với Compaction Filter, bạn có thể thay đổi giá trị của key hoặc loại bỏ key khỏi RocksDB trong quá trình Compaction. Điều này rất hữu ích khi bạn muốn áp dụng các quy tắc tùy chỉnh cho dữ liệu trong quá trình Compaction.
Dưới đây là một ví dụ về việc sử dụng Compaction Filter trong RocksDB bằng Java:
```Java
import org.rocksdb.*;
public class RocksDBCompactionFilterExample {
public static class MyCompactionFilter extends AbstractCompactionFilter {
@Override
public boolean filter(
int level, byte[] key, byte[] existingValue, byte[] value) {
// Kiểm tra điều kiện tùy chỉnh và quyết định có loại bỏ key hay không
// Trả về true nếu muốn loại bỏ key, ngược lại trả về false
return false;
}
}
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
final ColumnFamilyHandle cfHandle = db.getDefaultColumnFamily();
db.addCompactionFilter(cfHandle, new MyCompactionFilter());
} catch (RocksDBException e) {
// Xử lý lỗi khi thêm Compaction Filter không thành công
}
}
}
```
**C++:**
```C++
#include "rocksdb/db.h"
class MyCompactionFilter : public rocksdb::CompactionFilter {
public:
bool Filter(int level,
const rocksdb::Slice& key,
const rocksdb::Slice& existing_value,
std::string* new_value,
bool* value_changed) const override {
// Kiểm tra điều kiện tùy chỉnh và quyết định có loại bỏ key hay không
// Trả về true nếu muốn loại bỏ key, ngược lại tr
```
Trong ví dụ trên, chúng ta tạo một class MyCompactionFilter kế thừa từ AbstractCompactionFilter và ghi đè phương thức filter(). Trong phương thức filter(), chúng ta có thể kiểm tra các điều kiện tùy chỉnh và quyết định xem có loại bỏ key hay không. Nếu muốn loại bỏ key, chúng ta trả về true, ngược lại trả về false.
Sau đó, chúng ta thêm Compaction Filter vào RocksDB bằng cách sử dụng phương thức addCompactionFilter(). Trong trường hợp này, chúng ta sử dụng getDefaultColumnFamily() để lấy handle của column family mặc định trong RocksDB.
# RocksDB - Column Families
Column Families trong RocksDB là một tính năng cho phép bạn tổ chức và quản lý dữ liệu theo các nhóm được đặt tên. Mỗi Column Family có thể có các tùy chọn và cấu hình riêng, cho phép bạn tuỳ chỉnh và tối ưu hóa cách RocksDB lưu trữ và truy xuất dữ liệu.
Dưới đây là một ví dụ về cách sử dụng Column Families trong RocksDB bằng Java:
```java
import org.rocksdb.*;
public class RocksDBColumnFamiliesExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
try (final ColumnFamilyHandle cfHandle = db.createColumnFamily(new ColumnFamilyDescriptor("myColumnFamily".getBytes()))) {
byte[] key = "myKey".getBytes();
byte[] value = "myValue".getBytes();
db.put(cfHandle, key, value);
byte[] retrievedValue = db.get(cfHandle, key);
System.out.println("Retrieved value: " + new String(retrievedValue));
} catch (RocksDBException e) {
// Xử lý lỗi khi tạo Column Family không thành công
}
} catch (RocksDBException e) {
// Xử lý lỗi khi mở database không thành công
}
}
}
```
Trong ví dụ trên, chúng ta tạo một RocksDB database và sử dụng `createColumnFamily()` để tạo một Column Family mới với tên "myColumnFamily". Sau đó, chúng ta sử dụng `put()` để lưu trữ một cặp key-value trong Column Family. Cuối cùng, chúng ta sử dụng `get()` để lấy giá trị tương ứng với một key từ Column Family.
Lưu ý rằng chúng ta sử dụng `try-with-resources` để đảm bảo rằng các resources của RocksDB được đóng một cách chính xác sau khi sử dụng xong.
Đó là một ví dụ về cách sử dụng Column Families trong RocksDB bằng Java.
**C++:**
```C++
#include "rocksdb/db.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
rocksdb::ColumnFamilyHandle* cfHandle;
rocksdb::ColumnFamilyOptions cfOptions;
rocksdb::Status cfStatus = db->CreateColumnFamily(cfOptions, "myColumnFamily", &cfHandle);
if (cfStatus.ok()) {
rocksdb::WriteOptions writeOptions;
rocksdb::Slice key = "myKey";
rocksdb::Slice value = "myValue";
db->Put(writeOptions, cfHandle, key, value);
std::string retrievedValue;
rocksdb::ReadOptions readOptions;
rocksdb::Status retrieveStatus = db->Get(readOptions, cfHandle, key, &retrievedValue);
if (retrieveStatus.ok()) {
std::cout << "Retrieved value: " << retrievedValue << std::endl;
} else {
// Xử lý lỗi khi lấy giá trị không thành công
}
} else
```
# RocksDB - Low Priority Write
Low Priority Write là một tính năng trong RocksDB cho phép bạn ghi dữ liệu vào RocksDB với mức độ ưu tiên thấp hơn so với các ghi viết thông thường. Khi sử dụng Low Priority Write, RocksDB sẽ ưu tiên ghi các ghi chép (write-ahead log) và các ghi viết quan trọng hơn trước, giúp tăng hiệu suất ghi dữ liệu và giảm thời gian đáp ứng của RocksDB.
Dưới đây là một ví dụ về việc sử dụng Low Priority Write trong RocksDB bằng Java:
```java
import org.rocksdb.*;
public class RocksDBLowPriorityWriteExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
final WriteOptions writeOptions = new WriteOptions().setLowPriority(true);
byte[] key = "myKey".getBytes();
byte[] value = "myValue".getBytes();
db.put(writeOptions, key, value);
} catch (RocksDBException e) {
// Xử lý lỗi khi ghi dữ liệu không thành công
}
}
}
```
Trong ví dụ trên, chúng ta sử dụng `setLowPriority(true)` để đặt mức độ ưu tiên của ghi dữ liệu là thấp (Low Priority). Sau đó, chúng ta sử dụng `put()` để ghi một cặp key-value vào RocksDB với mức độ ưu tiên thấp.
Đó là một ví dụ về việc sử dụng Low Priority Write trong RocksDB bằng Java.
**C++:**
```C++
#include "rocksdb/db.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
rocksdb::WriteOptions writeOptions;
writeOptions.low_priority = true;
rocksdb::Slice key = "myKey";
rocksdb::Slice value = "myValue";
rocksdb::Status writeStatus = db->Put(writeOptions, key, value);
if (!writeStatus.ok()) {
// Xử lý lỗi khi ghi dữ liệu không thành công
}
} else {
// Xử lý lỗi khi mở database không thành công
}
delete db;
return 0;
}
```
Trong ví dụ trên, chúng ta sử dụng `writeOptions.low_priority = true` để đặt mức độ ưu tiên của ghi dữ liệu là thấp (Low Priority). Sau đó, chúng ta sử dụng `Put()` để ghi một cặp key-value vào RocksDB với mức độ ưu tiên thấp.
Đó là một ví dụ về việc sử dụng Low Priority Write trong RocksDB bằng C++.
# RocksDB - Time To Live
TTL (Time-to-Live) là một tính năng trong RocksDB cho phép bạn đặt thời gian sống cho một cặp key-value. Khi giá trị TTL hết hạn, RocksDB tự động xóa key-value tương ứng khỏi cơ sở dữ liệu.
Dưới đây là một ví dụ về việc sử dụng TTL trong RocksDB bằng Java:
```java
import org.rocksdb.*;
public class RocksDBTTLExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
final ColumnFamilyHandle cfHandle = db.getDefaultColumnFamily();
byte[] key = "myKey".getBytes();
byte[] value = "myValue".getBytes();
int ttl = 3600; // TTL in seconds
db.put(cfHandle, key, value, ttl);
} catch (RocksDBException e) {
// Xử lý lỗi khi ghi dữ liệu không thành công
}
}
}
```
Trong ví dụ trên, chúng ta sử dụng `put()` để ghi một cặp key-value vào RocksDB với một giá trị TTL (Time-to-Live) được đặt là 3600 giây (1 giờ). Khi giá trị TTL hết hạn, RocksDB tự động xóa key-value tương ứng.
Đối với việc sử dụng TTL trong RocksDB bằng C++, dưới đây là một ví dụ:
```C++
#include "rocksdb/db.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
rocksdb::WriteOptions writeOptions;
rocksdb::Slice key = "myKey";
rocksdb::Slice value = "myValue";
int ttl = 3600; // TTL in seconds
rocksdb::Status writeStatus = db->Put(writeOptions, key, value, rocksdb::WriteTTL(ttl));
if (!writeStatus.ok()) {
// Xử lý lỗi khi ghi dữ liệu không thành công
}
} else {
// Xử lý lỗi khi mở cơ sở dữ liệu không thành công
}
delete db;
return 0;
}
```
Trong ví dụ trên, chúng ta sử dụng `Put()` để ghi một cặp key-value vào RocksDB với một giá trị TTL (Time-to-Live) được đặt là 3600 giây (1 giờ). Khi giá trị TTL hết hạn, RocksDB tự động xóa key-value tương ứng.
Đó là một ví dụ về việc sử dụng TTL trong RocksDB bằng Java và C++.
# RocksDB - Transaction
Transactions (giao dịch) là một tính năng quan trọng trong RocksDB cho phép bạn thực hiện các thao tác đọc và ghi dữ liệu theo cách an toàn và nhất quán. Khi bạn thực hiện các thao tác trong một giao dịch, RocksDB đảm bảo rằng các thay đổi chỉ được áp dụng hoàn toàn hoặc không áp dụng.
Dưới đây là một ví dụ về việc sử dụng Transactions trong RocksDB bằng Java:
```java
import org.rocksdb.*;
public class RocksDBTransactionsExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
try (final TransactionDB transactionDb = TransactionDB.open(options, "/path/to/transaction_database")) {
// Bắt đầu một giao dịch
try (final Transaction transaction = transactionDb.beginTransaction(new WriteOptions())) {
byte[] key1 = "key1".getBytes();
byte[] key2 = "key2".getBytes();
byte[] value1 = "value1".getBytes();
byte[] value2 = "value2".getBytes();
// Thực hiện các thao tác ghi dữ liệu trong giao dịch
db.put(transaction, key1, value1);
db.put(transaction, key2, value2);
// Xác nhận giao dịch thành công
transaction.commit();
} catch (RocksDBException e) {
// Xử lý lỗi khi giao dịch không thành công
}
} catch (RocksDBException e) {
// Xử lý lỗi khi mở transaction database không thành công
}
} catch (RocksDBException e) {
// Xử lý lỗi khi mở database không thành công
}
}
}
```
Trong ví dụ trên, chúng ta sử dụng `TransactionDB.open()` để mở một transaction database. Sau đó, chúng ta bắt đầu một giao dịch bằng cách sử dụng `beginTransaction()`. Trong giao dịch, chúng ta thực hiện các thao tác ghi dữ liệu bằng `put()`. Cuối cùng, chúng ta xác nhận giao dịch thành công bằng `commit()`. Nếu có lỗi xảy ra, chúng ta có thể sử dụng `rollback()` để hủy bỏ giao dịch.
Đây là một ví dụ về việc sử dụng Transactions trong RocksDB bằng Java.
**C++:**
```C++
#include "rocksdb/db.h"
#include "rocksdb/utilities/transaction.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
rocksdb::TransactionDBOptions txdbOptions;
txdbOptions.create_if_missing = true;
rocksdb::TransactionDB* transactionDb;
rocksdb::TransactionDB::Open(txdbOptions, "/path/to/transaction_database", &transactionDb);
// Bắt đầu một giao dịch
rocksdb::WriteOptions writeOptions;
rocksdb
```
# RocksDB - Snapshot data
Snapshot là một tính năng trong RocksDB cho phép bạn tạo bản sao dữ liệu hiện tại để đọc theo một thời điểm cụ thể. Khi bạn tạo một snapshot, RocksDB đảm bảo rằng dữ liệu trong snapshot không bị ảnh hưởng bởi các thay đổi sau đó. Điều này rất hữu ích khi bạn muốn đọc dữ liệu trong một trạng thái nhất định và tránh bị ảnh hưởng bởi các giao dịch hoặc thay đổi dữ liệu khác.
Dưới đây là một ví dụ về việc sử dụng Snapshot trong RocksDB bằng Java:
```java
import org.rocksdb.*;
public class RocksDBSnapshotExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
try (final Snapshot snapshot = db.getSnapshot()) {
// Đọc dữ liệu từ snapshot
try (final ReadOptions readOptions = new ReadOptions().setSnapshot(snapshot)) {
byte[] key = "myKey".getBytes();
byte[] value = db.get(readOptions, key);
if (value != null) {
System.out.println("Value for key 'myKey': " + new String(value));
} else {
System.out.println("Value not found for key 'myKey'");
}
}
}
} catch (RocksDBException e) {
// Xử lý lỗi khi mở database không thành công
}
}
}
```
Trong ví dụ trên, chúng ta sử dụng `getSnapshot()` để tạo một snapshot của RocksDB. Sau đó, chúng ta sử dụng `setSnapshot()` để thiết lập snapshot cho các thao tác đọc dữ liệu. Bằng cách này, RocksDB đảm bảo rằng các thay đổi sau snapshot không ảnh hưởng đến dữ liệu được đọc từ snapshot. Trong ví dụ, chúng ta đọc giá trị của key "myKey" từ snapshot.
Đó là một ví dụ về việc sử dụng Snapshot trong RocksDB bằng Java.
**C++:**
```C++
#include "rocksdb/db.h"
#include "rocksdb/utilities/transaction_db.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
rocksdb::TransactionDBOptions txdbOptions;
txdbOptions.create_if_missing = true;
rocksdb::TransactionDB* transactionDb;
rocksdb::TransactionDB::Open(txdbOptions, "/path/to/transaction_database", &transactionDb);
// Bắt đầu một giao dịch
rocksdb::WriteOptions writeOptions;
rocksdb::TransactionOptions txnOptions;
rocksdb::Transaction* txn = transactionDb->BeginTransaction(writeOptions, txnOptions);
// Tạo một snapshot
const rocksdb::Snapshot* snapshot = txn->GetSnapshot();
// Đọc dữ liệu từ snapshot
rocksdb::ReadOptions readOptions;
readOptions.snapshot = snapshot;
std::string value;
txn->Get(readOptions, "myKey",
```
# RocksDB - Delete Range
Trong RocksDB, `DeleteRange()` là một hàm dùng để xóa một phạm vi dữ liệu trong cơ sở dữ liệu RocksDB. Nó cho phép bạn xóa tất cả các key-value có key nằm trong một khoảng key được chỉ định.
Dưới đây là một ví dụ về việc sử dụng `DeleteRange()` trong RocksDB bằng Java:
```java
import org.rocksdb.*;
public class RocksDBDeleteRangeExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
byte[] startKey = "startKey".getBytes();
byte[] endKey = "endKey".getBytes();
WriteOptions writeOptions = new WriteOptions();
db.deleteRange(writeOptions, startKey, endKey);
} catch (RocksDBException e) {
// Xử lý lỗi khi xóa dữ liệu không thành công
}
}
}
```
Trong ví dụ trên, chúng ta sử dụng `deleteRange()` để xóa tất cả các key-value có key trong khoảng từ "startKey" đến "endKey" trong RocksDB.
Đây là một ví dụ về việc sử dụng `DeleteRange()` trong RocksDB bằng Java.
**C++:**
```C++
#include "rocksdb/db.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
rocksdb::WriteOptions writeOptions;
rocksdb::Slice startKey = "startKey";
rocksdb::Slice endKey = "endKey";
rocksdb::Status deleteStatus = db->DeleteRange(writeOptions, &startKey, &endKey);
if (!deleteStatus.ok()) {
// Xử lý lỗi khi xóa dữ liệu không thành công
}
} else {
// Xử lý lỗi khi mở cơ sở dữ liệu không thành công
}
delete db;
return 0;
}
```
Trong ví dụ trên, chúng ta sử dụng `DeleteRange()` để xóa tất cả các key-value có key trong khoảng từ "startKey" đến "endKey" trong RocksDB.
Đó là một ví dụ về việc sử dụng `DeleteRange()` trong RocksDB bằng Java và C++.
# RocksDB - Atomic Flush
Atomic Flush là một tính năng trong RocksDB cho phép bạn đảm bảo rằng tất cả các thay đổi dữ liệu đã được ghi vào bộ nhớ đệm sẽ được ghi xuống đĩa cùng một lúc. Điều này đảm bảo tính nhất quán của dữ liệu và tránh mất mát dữ liệu do quá trình ghi bị hỏng.
Trong RocksDB, bạn có thể kích hoạt Atomic Flush bằng cách sử dụng `SetAtomicFlush()` trong `Options`.
Dưới đây là một ví dụ về việc sử dụng Atomic Flush trong RocksDB bằng Java:
```java
import org.rocksdb.*;
public class RocksDBAtomicFlushExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true)) {
options.setAtomicFlush(true);
try (final RocksDB db = RocksDB.open(options, "/path/to/database")) {
// Thực hiện các thao tác ghi dữ liệu
byte[] key = "myKey".getBytes();
byte[] value = "myValue".getBytes();
db.put(key, value);
// Kích hoạt Atomic Flush
db.flush(new FlushOptions().setWaitForFlush(true));
} catch (RocksDBException e) {
// Xử lý lỗi khi mở database không thành công
}
}
}
}
```
Trong ví dụ trên, chúng ta sử dụng `setAtomicFlush(true)` để kích hoạt Atomic Flush trong RocksDB. Sau đó, chúng ta thực hiện các thao tác ghi dữ liệu và sử dụng `flush()` để ghi xuống đĩa. Bằng cách sử dụng `setWaitForFlush(true)`, RocksDB đảm bảo rằng tất cả các thay đổi đã được ghi xuống đĩa trước khi tiếp tục thực thi chương trình.
Đây là một ví dụ về việc sử dụng Atomic Flush trong RocksDB bằng Java.
**C++:**
```C++
#include "rocksdb/db.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
options.atomic_flush = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
// Thực hiện các thao tác ghi dữ liệu
rocksdb::WriteOptions writeOptions;
rocksdb::Slice key = "myKey";
rocksdb::Slice value = "myValue";
rocksdb::Status putStatus = db->Put(writeOptions, key, value);
if (putStatus.ok()) {
// Kích hoạt Atomic Flush
rocksdb::FlushOptions flushOptions;
flushOptions.wait = true;
rocksdb::Status flushStatus = db->Flush(flushOptions);
if (!flushStatus.ok()) {
// Xử lý lỗi khi ghi xuống đĩa không thành công
}
} else {
// Xử lý lỗi khi ghi dữ liệu không thành công
}
} else {
// Xử lý lỗi khi mở cơ sở dữ liệu không thành công
}
delete db;
return
```
# RocksDB - Read only và Secondary instances
## Các trường hợp sử dụng Read-Only Instances
Read-Only Instances trong RocksDB được sử dụng để đảm bảo tính nhất quán và hiệu suất đọc trong môi trường có nhiều tiến trình đọc. Dưới đây là một số trường hợp sử dụng Read-Only Instances:
- **Đọc phân tán**: Khi bạn cần đọc dữ liệu từ nhiều tiến trình đọc đồng thời, bạn có thể tạo nhiều Read-Only Instances để mỗi tiến trình có thể đọc dữ liệu một cách độc lập.
- **Đọc dự phòng**: Khi bạn cần tạo các bản sao dự phòng của cơ sở dữ liệu để đảm bảo sẵn sàng và độ tin cậy cao, bạn có thể sử dụng Read-Only Instances để thực hiện các thao tác đọc từ các bản sao này.
- **Đọc-phân tán-dự phòng**: Khi bạn cần đảm bảo tính nhất quán và hiệu suất đọc cao trong môi trường phân tán và dự phòng, bạn có thể kết hợp sử dụng Read-Only Instances và Secondary Instances. Read-Only Instances sẽ xử lý các yêu cầu đọc từ các tiến trình đọc, trong khi Secondary Instances sẽ đảm nhận việc sao chép dữ liệu và đồng bộ hóa với Primary Instance.
## Cách sử dụng Secondary Instances
Secondary Instances trong RocksDB được sử dụng để tạo các bản sao dự phòng của cơ sở dữ liệu và đồng bộ hóa dữ liệu với Primary Instance. Dưới đây là một số bước để sử dụng Secondary Instances:
1. **Cấu hình Primary Instance**: Đầu tiên, bạn cần cấu hình và khởi tạo Primary Instance theo các bước thông thường.
2. **Cấu hình Secondary Instance**: Tiếp theo, bạn cần cấu hình và khởi tạo Secondary Instance bằng cách sử dụng các tùy chọn và thiết lập đồng bộ hóa dữ liệu với Primary Instance. Đảm bảo rằng bạn đã thiết lập đúng địa chỉ và cổng của Primary Instance để Secondary Instance có thể kết nối và đồng bộ dữ liệu.
3. **Khởi động Secondary Instance**: Sau khi cấu hình, bạn có thể khởi động Secondary Instance để nó bắt đầu sao chép dữ liệu từ Primary Instance và duy trì đồng bộ hóa dữ liệu.
4. **Đọc dữ liệu từ Secondary Instances**: Bây giờ, bạn có thể thực hiện các thao tác đọc dữ liệu từ Secondary Instances một cách an toàn và tin cậy.
Lưu ý rằng Secondary Instances chỉ hỗ trợ đọc dữ liệu và không hỗ trợ ghi. Ghi dữ liệu vẫn phải được thực hiện qua Primary Instance.
Đó là một số chi tiết về Read-Only và Secondary Instances trong RocksDB.
# RocksDB - Wide Columns
Wide Columns là một tính năng trong RocksDB cho phép lưu trữ và truy xuất dữ liệu trong các cột rộng. Điều này cho phép bạn lưu trữ các giá trị có cấu trúc phức tạp, như mảng, đối tượng hoặc bất kỳ kiểu dữ liệu tùy chỉnh nào, dưới dạng một cột duy nhất.
Để sử dụng Wide Columns trong RocksDB, bạn cần sử dụng các hàm API để đọc và ghi dữ liệu cho các cột rộng. Dưới đây là một ví dụ về việc sử dụng Wide Columns trong RocksDB bằng Java:
```java
import org.rocksdb.*;
public class RocksDBWideColumnsExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
// Ghi dữ liệu vào Wide Columns
byte[] columnFamilyName = "myColumnFamily".getBytes();
ColumnFamilyHandle columnFamilyHandle = db.createColumnFamily(new ColumnFamilyDescriptor(columnFamilyName));
byte[] key = "myKey".getBytes();
byte[] value = "myValue".getBytes();
db.put(columnFamilyHandle, key, value);
// Đọc dữ liệu từ Wide Columns
byte[] readValue = db.get(columnFamilyHandle, key);
System.out.println("Value: " + new String(readValue));
} catch (RocksDBException e) {
// Xử lý lỗi khi thao tác với cơ sở dữ liệu không thành công
}
}
}
```
Trong ví dụ trên, chúng ta sử dụng `createColumnFamily()` để tạo một Column Family mới cho Wide Columns. Sau đó, chúng ta sử dụng `put()` để ghi dữ liệu vào cột rộng và `get()` để đọc dữ liệu từ cột rộng.
Dưới đây là một ví dụ về việc sử dụng Wide Columns trong RocksDB bằng C++:
```C++
#include "rocksdb/db.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
// Ghi dữ liệu vào Wide Columns
rocksdb::ColumnFamilyHandle* columnFamilyHandle;
rocksdb::ColumnFamilyOptions cfOptions;
rocksdb::Status createCfStatus = db->CreateColumnFamily(cfOptions, "myColumnFamily", &columnFamilyHandle);
if (createCfStatus.ok()) {
rocksdb::WriteOptions writeOptions;
rocksdb::Slice key = "myKey";
rocksdb::Slice value = "myValue";
rocksdb::Status putStatus = db->Put(writeOptions, columnFamilyHandle, key, value);
if (!putStatus.ok()) {
// Xử lý lỗi khi ghi dữ liệu không thành công
}
} else {
// Xử lý lỗi khi tạo Column Family không thành công
}
// Đọc dữ liệu từ Wide Columns
rocksdb::ReadOptions readOptions;
rocksdb::PinnableSlice readValue;
rocksdb::Status getStatus = db->Get(readOptions, columnFamilyHandle, key, &readValue
```
# RocksDB - BlobDB
BlobDB là một mô-đun bổ sung cho RocksDB, được thiết kế đặc biệt để lưu trữ và quản lý dữ liệu lớn không cấu trúc như văn bản, hình ảnh, âm thanh, video và các đối tượng nhị phân khác. Nó cung cấp khả năng lưu trữ hiệu quả dữ liệu lớn và quản lý metadata liên quan đến dữ liệu.
BlobDB sử dụng một cấu trúc dữ liệu gọi là "blob" để lưu trữ dữ liệu không cấu trúc. Mỗi blob là một đơn vị lưu trữ độc lập, có thể chứa một hoặc nhiều đối tượng nhị phân. BlobDB sử dụng RocksDB để lưu trữ metadata của các blob, bao gồm thông tin như kích thước, thời gian tạo và các thuộc tính tùy chỉnh khác.
BlobDB cung cấp các API để thêm, truy xuất và xóa blob, cho phép bạn làm việc với dữ liệu không cấu trúc một cách dễ dàng và hiệu quả. Dưới đây là một ví dụ về việc sử dụng BlobDB trong RocksDB bằng Java:
```java
import org.rocksdb.*;
public class RocksDBBlobDBExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
// Khởi tạo BlobDB
try (final BlobDB blobDB = BlobDB.open(db)) {
// Thêm dữ liệu vào BlobDB
byte[] blobId = blobDB.put("Hello, BlobDB!".getBytes());
System.out.println("Blob ID: " + new String(blobId));
// Truy xuất dữ liệu từ BlobDB
byte[] data = blobDB.get(blobId);
System.out.println("Data: " + new String(data));
// Xóa dữ liệu từ BlobDB
blobDB.delete(blobId);
} catch (RocksDBException e) {
// Xử lý lỗi khi thao tác với BlobDB không thành công
}
} catch (RocksDBException e) {
// Xử lý lỗi khi thao tác với cơ sở dữ liệu RocksDB không thành công
}
}
}
```
Trong ví dụ trên, chúng ta sử dụng `BlobDB.open()` để khởi tạo một phiên làm việc với BlobDB. Sau đó, chúng ta có thể sử dụng `put()` để thêm dữ liệu vào BlobDB, `get()` để truy xuất dữ liệu từ BlobDB và `delete()` để xóa dữ liệu từ BlobDB.
Đây là một ví dụ về việc sử dụng BlobDB trong RocksDB bằng C++:
```C++
#include "rocksdb/db.h"
#include "rocksdb/blob_db.h"
int main() {
rocksdb::DB* db;
rocksdb::Options options;
options.create_if_missing = true;
rocksdb::Status status = rocksdb::DB::Open(options, "/path/to/database", &db);
if (status.ok()) {
// Khởi tạo BlobDB
rocksdb::BlobDB* blobDB;
rocksdb::BlobDBOptions blobDBOptions;
rocksdb::Status blobDBStatus = rocksdb::BlobDB::Open(blobDBOptions, db, &blobDB);
if (blobDBStatus.ok()) {
// Thêm dữ liệu vào BlobDB
rocksdb::BlobDB::PutOptions putOptions;
rocksdb::Slice data = "Hello, BlobDB!";
rocksdb::BlobIndex blobIndex;
rocksdb::Status putStatus = blobDB->Put(putOptions, data, &blobIndex);
if (putStatus.ok()) {
std::cout << "Blob ID: " << blobIndex.blob_handle.ToString() << std::endl;
// Truy xuất dữ liệu từ BlobDB
rocksdb::BlobDB::GetOptions getOptions;
rocksdb::PinnableSlice readValue;
rocksdb::Status getStatus = blobDB->Get(getOptions, blobIndex.blob_handle, &readValue);
if (getStatus.ok()) {
std::cout << "Data: " << readValue.ToString() << std::endl;
// Xóa dữ liệu từ BlobDB
rocksdb::BlobDB::DeleteOptions deleteOptions;
rocksdb::Status deleteStatus = blobDB->Delete(deleteOptions, blobIndex.blob_handle);
if (!deleteStatus.ok()) {
// Xử lý lỗi khi xóa dữ liệu không thành công
}
} else {
// Xử lý lỗi khi truy xuất dữ liệu không thành công
}
} else {
// Xử lý lỗi khi thêm dữ liệu không thành công
}
} else {
// Xử lý lỗi khi khởi tạo BlobDB không thành công
}
} else {
// Xử lý lỗi khi khởi tạo RocksDB không thành công
}
return 0;
}
```
# RocksDB - MemTable
Trong RocksDB, Memtable là một thành phần quan trọng trong cơ sở dữ liệu. Nó là một bộ nhớ đệm được sử dụng để lưu trữ dữ liệu mới và sắp xếp theo thứ tự khóa. Memtable giúp tăng tốc độ ghi dữ liệu bằng cách tránh việc truy xuất đĩa cứng.
Khi dữ liệu được ghi vào RocksDB, nó sẽ được ghi vào Memtable trước. Memtable sẽ duy trì dữ liệu trong bộ nhớ và sắp xếp theo thứ tự khóa để tối ưu hóa việc truy xuất dữ liệu. Khi Memtable trở nên quá lớn, RocksDB sẽ chuyển đổi dữ liệu từ Memtable vào các tệp SSTable để giải phóng bộ nhớ.
Memtable trong RocksDB có thể được cấu hình để đáp ứng yêu cầu của ứng dụng. Bạn có thể thiết lập kích thước tối đa của Memtable, số lượng Memtable và các thiết lập khác để điều chỉnh hiệu suất và sử dụng bộ nhớ.
Sử dụng Memtable trong RocksDB giúp tăng tốc độ ghi dữ liệu và cải thiện hiệu suất của ứng dụng. Tuy nhiên, điều quan trọng là phải cân nhắc và cấu hình Memtable phù hợp với yêu cầu của ứng dụng để đảm bảo rằng nó không gây ra vấn đề về bộ nhớ hoặc hiệu suất.
Đây là một ví dụ về cách cấu hình Memtable trong RocksDB bằng Java:
```java
import org.rocksdb.*;
public class RocksDBMemtableExample {
public static void main(String[] args) {
RocksDB.loadLibrary();
try (final Options options = new Options().setCreateIfMissing(true);
final RocksDB db = RocksDB.open(options, "/path/to/database")) {
// Cấu hình Memtable
final BlockBasedTableConfig tableConfig = new BlockBasedTableConfig();
tableConfig.setBlockCacheSize(64 * 1024 * 1024L);
options.setTableFormatConfig(tableConfig);
// Ghi dữ liệu vào RocksDB
byte[] key = "myKey".getBytes();
byte[] value = "myValue".getBytes();
db.put(key, value);
// Đọc dữ liệu từ RocksDB
byte[] readValue = db.get(key);
System.out.println("Value: " + new String(readValue));
} catch (RocksDBException e) {
// Xử lý lỗi khi thao tác với cơ sở dữ liệu không thành công
}
}
}
```
Trong ví dụ trên, chúng ta sử dụng `BlockBasedTableConfig` để cấu hình Memtable và bộ nhớ cache. Chúng ta có thể thiết lập kích thước bộ nhớ cache bằng cách sử dụng `setBlockCacheSize()`.
Trong RocksDB, có hai loại Memtable chính là SkipListMemtable và VectorMemtable.
- **SkipListMemtable**: SkipListMemtable là một loại Memtable được triển khai bằng cách sử dụng danh sách liên kết nhảy (skip list). Skip list là một cấu trúc dữ liệu tương tự như danh sách liên kết, nhưng nó cung cấp khả năng truy cập nhanh hơn. SkipListMemtable được sử dụng mặc định trong RocksDB và được khuyến nghị cho hầu hết các ứng dụng.
- **VectorMemtable**: VectorMemtable là một loại Memtable được triển khai bằng cách sử dụng vector (mảng động). VectorMemtable cung cấp hiệu suất cao hơn SkipListMemtable trong một số trường hợp đặc biệt, nhưng nó sử dụng nhiều bộ nhớ hơn. Để sử dụng VectorMemtable, bạn cần cấu hình RocksDB để sử dụng loại Memtable này.
Để cấu hình RocksDB để sử dụng VectorMemtable, bạn có thể sử dụng `Options::setMemTableFactoryVector()` trong RocksDB C++ API hoặc `Options.setMemTableFactoryVector()` trong RocksDB Java API.
Việc lựa chọn loại Memtable phù hợp phụ thuộc vào yêu cầu và tải công việc của ứng dụng của bạn. SkipListMemtable là loại Memtable được sử dụng rộng rãi và phổ biến nhất trong RocksDB, và nó thường đáp ứng tốt cho hầu hết các ứng dụng. Tuy nhiên, nếu ứng dụng của bạn đòi hỏi hiệu suất cao hơn hoặc có quy mô dữ liệu lớn, bạn có thể xem xét sử dụng VectorMemtable, mặc dù điều này có thể làm tăng sử dụng bộ nhớ.
# RocksDB - Leveled Compaction
Trong RocksDB, Leveled Compaction là một cơ chế quan trọng để quản lý và tổ chức dữ liệu trong cơ sở dữ liệu. Nó được sử dụng để tối ưu hóa việc đọc và ghi dữ liệu bằng cách chia dữ liệu thành các cấp độ (levels) và thực hiện compaction (tái cấu trúc) dữ liệu giữa các cấp độ.
Một cấp độ (level) trong Leveled Compaction bao gồm một tập hợp các tệp SSTable (Sorted String Table) được sắp xếp theo thứ tự khóa. Các cấp độ có kích thước khác nhau và được sắp xếp theo mức độ độc lập với nhau. Cấp độ cao hơn chứa các tệp SSTable lớn hơn và cung cấp tốc độ đọc tốt hơn, trong khi cấp độ thấp hơn có kích thước nhỏ hơn và cung cấp tốc độ ghi tốt hơn.
Khi dữ liệu được ghi vào RocksDB, nó sẽ được ghi vào Memtable trước. Khi Memtable trở nên quá lớn, RocksDB sẽ chuyển đổi dữ liệu từ Memtable vào một cấp độ (level) thấp nhất. Khi một cấp độ (level) trở nên quá lớn, RocksDB sẽ thực hiện quá trình compaction để tái cấu trúc dữ liệu và giảm kích thước của cấp độ đó.
Quá trình compaction trong Leveled Compaction bao gồm hai giai đoạn chính: minor compaction và major compaction.
- **Minor compaction**: Trong minor compaction, RocksDB sẽ chọn một số tệp SSTable từ cấp độ thấp hơn và hợp nhất chúng thành một tệp SSTable mới ở cấp độ cao hơn. Quá trình này giúp giảm số lượng tệp SSTable và tăng tốc độ đọc dữ liệu. Minor compaction thường được thực hiện thường xuyên để duy trì cân bằng kích thước của các cấp độ.
- **Major compaction**: Trong major compaction, RocksDB sẽ hợp nhất tất cả các tệp SSTable từ một cấp độ thành một tệp SSTable duy nhất ở cấp độ cao nhất. Quá trình này giúp giảm tải công việc đọc và tăng tốc độ truy vấn dữ liệu. Major compaction thường được thực hiện ít thường xuyên hơn và yêu cầu nhiều tài nguyên hơn so với minor compaction.
Leveled Compaction giúp tăng hiệu suất đọc và ghi dữ liệu trong RocksDB bằng cách tối ưu hóa cấu trúc dữ liệu. Nó cũng giúp giảm kích thước của dữ liệu và sử dụng bộ nhớ hiệu quả. Tuy nhiên, việc lựa chọn loại Memtable phù hợp cũng là một yếu tố quan trọng, phụ thuộc vào loại dữ liệu, kích thước bộ nhớ và yêu cầu của ứng dụng cụ thể.
# RocksDB - Universal compaction style
Trong RocksDB, Universal Compaction Style là một chiến lược tái cấu trúc dữ liệu được sử dụng để quản lý và tối ưu hóa việc đọc và ghi dữ liệu. Universal Compaction Style cho phép tái cấu trúc dữ liệu giữa các cấp độ (levels) và loại bỏ các tệp SSTable không cần thiết.
Universal Compaction Style sử dụng một loại tệp SSTable đặc biệt gọi là tệp SSTable đa cấp (multi-level SSTable) để lưu trữ dữ liệu. Mỗi tệp SSTable đa cấp bao gồm một hoặc nhiều cấp độ (levels) và sắp xếp dữ liệu theo thứ tự khóa. Các tệp SSTable đa cấp có thể được nén lại và tối ưu hóa để giảm kích thước và tăng hiệu suất đọc dữ liệu.
Khi dữ liệu được ghi vào RocksDB, nó sẽ được ghi vào Memtable trước. Khi Memtable trở nên quá lớn, RocksDB sẽ chuyển đổi dữ liệu từ Memtable vào tệp SSTable đa cấp tại cấp độ thấp nhất. Khi một tệp SSTable đa cấp trở nên quá lớn, RocksDB sẽ thực hiện quá trình compaction để tái cấu trúc dữ liệu và loại bỏ các tệp SSTable không cần thiết.
Quá trình compaction trong Universal Compaction Style cũng bao gồm hai giai đoạn chính: minor compaction và major compaction.
- **Minor compaction**: Trong minor compaction, RocksDB sẽ chọn một số tệp SSTable đa cấp từ cấp độ thấp hơn và hợp nhất chúng thành một tệp SSTable mới ở cấp độ cao hơn. Quá trình này giúp giảm số lượng tệp SSTable và tối ưu hóa việc đọc dữ liệu. Minor compaction thường được thực hiện thường xuyên để duy trì cân bằng kích thước của các cấp độ.
- **Major compaction**: Trong major compaction, RocksDB sẽ hợp nhất tất cả các tệp SSTable đa cấp từ một cấp độ thành một tệp SSTable đa cấp duy nhất ở cấp độ cao nhất. Quá trình này giúp giảm tải công việc đọc và tối ưu hóa hiệu suất truy vấn dữ liệu. Major compaction thường được thực hiện ít thường xuyên hơn và yêu cầu nhiều tài nguyên hơn so với minor compaction.
Universal Compaction Style giúp giảm kích thước của dữ liệu và tối ưu hóa hiệu suất đọc và ghi dữ liệu trong RocksDB.
# RocksDB - FIFO compaction style
<markdown>
# Chi tiết FIFO Compaction Style
Trong RocksDB, FIFO (First-In-First-Out) Compaction Style là một chiến lược tái cấu trúc dữ liệu được sử dụng để quản lý và tối ưu hóa việc đọc và ghi dữ liệu. FIFO Compaction Style tập trung vào việc duy trì thứ tự của các tệp SSTable (Sorted String Table) dựa trên thời gian đến và thời gian sử dụng.
FIFO Compaction Style sử dụng một tệp SSTable đặc biệt gọi là tệp SSTable FIFO để lưu trữ dữ liệu. Tệp SSTable FIFO duy trì thứ tự của các tệp SSTable dựa trên thời gian tạo và thời gian sử dụng. Khi RocksDB nhận một yêu cầu ghi, nó sẽ tạo một tệp SSTable mới và ghi dữ liệu vào đó. Các tệp SSTable sẽ được tổ chức theo thứ tự thời gian, với tệp mới nhất đứng đầu và các tệp cũ hơn đứng sau.
Mục tiêu của FIFO Compaction Style là duy trì sự tuân thủ theo thứ tự của các tệp SSTable. Khi một tệp SSTable cũ đã đạt đến một ngưỡng kích thước hoặc thời gian sử dụng, nó sẽ được xóa hoặc lưu trữ trong một tệp SSTable lưu trữ cố định. Điều này giúp giảm kích thước của RocksDB và làm cho việc truy xuất dữ liệu hiệu quả hơn.
Khi số lượng tệp SSTable trong RocksDB vượt quá một ngưỡng được cấu hình trước, RocksDB sẽ thực hiện quá trình compaction để tái cấu trúc dữ liệu và giảm kích thước của RocksDB. Trong quá trình compaction, RocksDB sẽ chọn một số tệp SSTable và hợp nhất chúng thành một tệp SSTable mới. Quá trình này giúp giảm số lượng tệp SSTable và tối ưu hóa việc đọc dữ liệu.
Tuy nhiên, FIFO Compaction Style không tập trung vào việc tối ưu hóa việc đọc dữ liệu như các chiến lược compaction khác. Thay vào đó, nó tập trung vào việc duy trì thứ tự và xử lý các yêu cầu ghi một cách hiệu quả. Việc lựa chọn chiến lược compaction phù hợp vẫn phụ thuộc vào yếu tố khác như loại dữ liệu, kích thước bộ nhớ và yêu cầu của ứng dụng cụ thể.
Với FIFO Compaction Style, RocksDB có thể cung cấp sự ổn định và đáng tin cậy trong việc lưu trữ và truy xuất dữ liệu. Các tệp SSTable được tổ chức theo thứ tự thời gian, giúp duy trì tính tuần tự và tiện lợi cho các ứng dụng yêu cầu dữ liệu tuần tự. Tuy nhiên, việc lựa chọn chiến lược compaction phù hợp là quan trọng để đảm bảo hiệu suất và tối ưu hóa việc truy cập dữ liệu trong môi trường RocksDB.
# RocksDB - SST
Trong RocksDB, SST (Sorted String Table) là định dạng tệp được sử dụng để lưu trữ và quản lý dữ liệu. SST là một tệp nhị phân không chỉ chứa khóa và giá trị, mà còn chứa các thông tin bổ sung như chỉ mục và các thông số khác.
Mỗi tệp SST được chia thành các khoảng giá trị (range) và mỗi khoảng giá trị lại chứa một số lượng khóa và giá trị. Các khoảng giá trị trong tệp SST được sắp xếp theo thứ tự tăng dần của khóa. Khi thực hiện truy vấn dữ liệu, RocksDB sẽ sử dụng các chỉ mục trong tệp SST để tìm kiếm và truy xuất dữ liệu một cách hiệu quả.
Một tệp SST có thể được chia thành các cấp độ (levels) trong các chiến lược compaction khác nhau như Leveled Compaction, Universal Compaction Style, hoặc FIFO Compaction Style. Các tệp SST trong cùng một cấp độ có kích thước tương tự nhau và được sắp xếp theo thứ tự tăng dần của khóa.
SST trong RocksDB cung cấp nhiều lợi ích. Đầu tiên, nó giúp tăng tốc độ truy xuất dữ liệu bằng cách sử dụng chỉ mục và các cấu trúc dữ liệu tối ưu hóa. Thứ hai, nó giúp giảm kích thước của dữ liệu bằng cách nén và lưu trữ dữ liệu một cách hiệu quả. Cuối cùng, nó cung cấp tính bảo mật và độ tin cậy cao cho dữ liệu, vì các tệp SST thường được xử lý và bảo vệ bằng các cơ chế kiểm soát lỗi và sai sót.
Tuy nhiên, việc lựa chọn chiến lược compaction và cấu trúc SST phù hợp là quan trọng để đảm bảo hiệu suất và tối ưu hóa việc truy cập dữ liệu trong môi trường RocksDB. Nên cân nhắc các yếu tố như loại dữ liệu, kích thước bộ nhớ và yêu cầu của ứng dụng cụ thể để chọn phương pháp phù hợp cho việc sử dụng SST trong RocksDB.
# RocksDB - Delete Stale Files
Trong RocksDB, Delete Stale Files là một chức năng quan trọng để quản lý và giải phóng tệp SSTable không còn cần thiết. Khi RocksDB thực hiện quá trình compaction và tái cấu trúc dữ liệu, các tệp SSTable cũ và không còn được sử dụng nữa sẽ được xóa để giảm kích thước của RocksDB.
Delete Stale Files hoạt động dựa trên các chỉ mục và thông tin Metadata của RocksDB. Khi RocksDB xác định rằng một tệp SSTable đã không còn sử dụng nữa, nó sẽ đánh dấu tệp đó là "stale" (không còn cần thiết) và thực hiện quá trình xóa.
Ví dụ:
Giả sử bạn có ba tệp SSTable là A, B, và C. Khi RocksDB thực hiện quá trình compaction và tạo ra một tệp mới là D, các tệp cũ A, B, và C sẽ được đánh dấu là stale. Khi RocksDB xác định rằng không có yêu cầu truy vấn dữ liệu nào sử dụng các tệp stale này, nó sẽ thực hiện quá trình Delete Stale Files và xóa các tệp A, B, và C khỏi RocksDB.
Delete Stale Files giúp giảm kích thước của RocksDB và làm cho việc truy cập dữ liệu hiệu quả hơn. Nó đảm bảo rằng chỉ các tệp SSTable cần thiết và được sử dụng mới được giữ lại trong RocksDB.
Ví dụ:
```
Before Delete Stale Files:
- Tệp SSTable A (stale)
- Tệp SSTable B (stale)
- Tệp SSTable C (stale)
- Tệp SSTable D (active)
After Delete Stale Files:
- Tệp SSTable D (active)
```
Trong ví dụ trên, sau khi thực hiện Delete Stale Files, chỉ tệp SSTable D còn lại trong RocksDB, trong khi các tệp stale A, B, và C đã được xóa.
# RocksDB - Partitioned Index/Filters
Trong RocksDB, Partitioned Index/Filters là một tính năng quan trọng giúp tăng tốc độ truy vấn dữ liệu bằng cách sử dụng các chỉ mục và bộ lọc được chia thành các phân đoạn (partition).
Khi RocksDB tạo ra một tệp SSTable mới, nó sẽ tạo các chỉ mục và bộ lọc tương ứng cho phân đoạn của tệp SSTable đó. Mỗi phân đoạn sẽ có một chỉ mục và bộ lọc riêng, được sắp xếp theo thứ tự tăng dần của khóa.
Khi thực hiện truy vấn dữ liệu, RocksDB sẽ sử dụng các chỉ mục và bộ lọc để xác định phân đoạn chứa khóa cần truy vấn. Việc này giúp giảm số lượng dữ liệu cần xem xét và tăng tốc độ truy xuất dữ liệu.
Ví dụ:
Giả sử bạn có một tệp SSTable với các phân đoạn như sau:
- Phân đoạn 1: Khóa từ A đến F
- Phân đoạn 2: Khóa từ G đến M
- Phân đoạn 3: Khóa từ N đến Z
Khi thực hiện truy vấn dữ liệu với khóa X, RocksDB sẽ sử dụng chỉ mục và bộ lọc để xác định rằng phân đoạn 3 chứa khóa X. Vì vậy, RocksDB chỉ cần xem xét dữ liệu trong phân đoạn 3 để tìm kiếm khóa X, giảm bớt thời gian truy xuất dữ liệu.
Partitioned Index/Filters giúp tăng tốc độ truy vấn dữ liệu bằng cách giảm số lượng dữ liệu cần xem xét. Nó cung cấp một cơ chế tối ưu để xác định vị trí của dữ liệu trong RocksDB và tìm kiếm nhanh chóng các khóa cần truy vấn.
Ví dụ:
Giả sử bạn có một RocksDB với các tệp SSTable và phân đoạn như sau:
- Tệp SSTable 1:
- Phân đoạn 1: Khóa từ A đến F
- Phân đoạn 2: Khóa từ G đến M
- Tệp SSTable 2:
- Phân đoạn 1: Khóa từ N đến T
- Phân đoạn 2: Khóa từ U đến Z
Khi thực hiện truy vấn dữ liệu với khóa X, RocksDB sẽ sử dụng chỉ mục và bộ lọc của các tệp SSTable để xác định rằng phân đoạn 2 của tệp SSTable 2 chứa khóa X. Vì vậy, RocksDB chỉ cần xem xét dữ liệu trong phân đoạn 2 của tệp SSTable 2 để tìm kiếm khóa X, giảm bớt thời gian
# RocksDB - Repairer
Trong RocksDB, RocksDB Repairer là một công cụ được cung cấp để kiểm tra và sửa chữa các tệp SSTable bị hỏng hoặc không hợp lệ trong cơ sở dữ liệu RocksDB. RocksDB Repairer có thể được sử dụng để khắc phục các vấn đề như tệp SSTable bị mất hoặc bị hỏng, chỉ mục không chính xác, hoặc lỗi dữ liệu.
Khi chạy RocksDB Repairer, công cụ sẽ kiểm tra tất cả các tệp SSTable trong RocksDB và xác định các tệp bị hỏng hoặc không hợp lệ. Sau đó, RocksDB Repairer sẽ cố gắng sửa chữa các tệp bị hỏng hoặc không hợp lệ bằng cách sử dụng các thông tin có sẵn trong RocksDB hoặc sử dụng các thông tin phục hồi từ các tệp SSTable khác.
Ví dụ:
Giả sử bạn có một RocksDB với hai tệp SSTable như sau:
- Tệp SSTable 1: Hoàn chỉnh và không bị hỏng
- Tệp SSTable 2: Bị hỏng hoặc không hợp lệ
Khi chạy RocksDB Repairer trên RocksDB này, công cụ sẽ xác định rằng tệp SSTable 2 bị hỏng hoặc không hợp lệ và cố gắng sửa chữa tệp này bằng cách sử dụng các thông tin phục hồi từ tệp SSTable 1 hoàn chỉnh và các thông tin khác có sẵn trong RocksDB.
RocksDB Repairer là một công cụ hữu ích để khắc phục các vấn đề về tệp SSTable trong RocksDB. Nó giúp đảm bảo tính toàn vẹn và độ tin cậy của dữ liệu trong RocksDB và cung cấp khả năng phục hồi dữ liệu trong trường hợp xảy ra sự cố.
Ví dụ:
```
Trước khi chạy RocksDB Repairer:
- Tệp SSTable 1 (hoàn chỉnh)
- Tệp SSTable 2 (bị hỏng)
Sau khi chạy RocksDB Repairer:
- Tệp SSTable 1 (hoàn chỉnh)
- Tệp SSTable 2 (đã được sửa chữa)
```
Trong ví dụ trên, sau khi chạy RocksDB Repairer, tệp SSTable 2 đã được sửa chữa và trở lại trạng thái hoàn chỉnh.
Với RocksDB Repairer, bạn có thể tăng tính toàn vẹn và độ tin cậy của dữ liệu trong RocksDB và xử lý các vấn đề về tệp SSTable một cách hiệu quả.
# RocksDB - Write Batch With Index
Trong RocksDB, Write Batch With Index là một tính năng quan trọng để thực hiện các thay đổi vào cơ sở dữ liệu và duy trì chỉ mục của dữ liệu một cách hiệu quả.
Khi thực hiện các thay đổi vào RocksDB, như thêm, cập nhật hoặc xóa dữ liệu, bạn có thể sử dụng Write Batch With Index để nhóm các thay đổi này lại thành một lô (batch). Điều này giúp tăng hiệu suất ghi vào RocksDB bằng cách tránh việc ghi từng thay đổi một cách độc lập.
Write Batch With Index cũng duy trì một chỉ mục để nhanh chóng xác định vị trí của các thay đổi trong lô. Chỉ mục này cho phép RocksDB tìm kiếm và truy xuất dữ liệu một cách hiệu quả ngay cả khi các thay đổi chưa được áp dụng vào cơ sở dữ liệu chính thức.
Ví dụ:
Giả sử bạn muốn thêm hai bản ghi vào RocksDB: (key1, value1) và (key2, value2). Thay vì thực hiện hai lần ghi riêng biệt, bạn có thể sử dụng Write Batch With Index để nhóm hai thay đổi này lại thành một lô (batch).
Khi sử dụng Write Batch With Index, bạn có thể thêm (key1, value1) và (key2, value2) vào bộ nhớ đệm của lô mà không cần thực hiện ghi ngay lập tức. Chỉ khi bạn muốn áp dụng các thay đổi này vào RocksDB, bạn sẽ gọi hàm write() để thực hiện ghi lô (batch) vào RocksDB.
Việc sử dụng Write Batch With Index giúp tăng hiệu suất ghi vào RocksDB bằng cách giảm số lần ghi và tối ưu hóa việc cập nhật chỉ mục của dữ liệu.
Ví dụ:
```python
# Khởi tạo Write Batch With Index
write_batch = rocksdb.WriteBatchWithIndex()
# Thêm các thay đổi vào lô
write_batch.put(b'key1', b'value1')
write_batch.put(b'key2', b'value2')
# Áp dụng lô vào RocksDB
rocksdb.write(write_batch)
```
Trong ví dụ trên, chúng ta sử dụng Write Batch With Index để nhóm hai thay đổi (key1, value1) và (key2, value2) lại thành một lô. Sau đó, chúng ta áp dụng lô này vào RocksDB bằng cách gọi hàm write().
Write Batch With Index là một tính năng mạnh mẽ trong RocksDB để tăng hiệu suất ghi và duy trì chỉ mục của dữ liệu một cách hiệu quả.
# RocksDB - Performance Benchmarks
Kết quả đo tải của RocksDB. Chi tiết: https://github.com/facebook/rocksdb/wiki/Performance-Benchmarks
# Setup
All of the benchmarks are run on the same AWS instance. Here are the details of the test setup:
- **Instance type:** m5d.2xlarge 8 CPU, 32 GB Memory, 1 x 300 NVMe SSD.
- **Kernel version:** Linux 4.14.177-139.253.amzn2.x86\_64
- **File System:** XFS with discard enabled
To understand the performance of the SSD card, we ran an [fio](https://fio.readthedocs.io/en/latest/) test and observed 117K IOPS of 4KB reads (See Performance Benchmarks#fio test results for outputs).
All tests were executed against by executing benchmark.sh with the following parameters (unless otherwise specified):
- NUM\_KEYS=900000000
- CACHE\_SIZE=6442450944
- For long-running tests, the tests were executed with a duration of 5400 seconds (DURATION=5400)
Unless explicitly specified, the remaining tests used default parameters. DIO tests were executed with the options `--use_direct_io_for_flush_and_compaction --use_direct_reads`.
All other parameters used the default values, unless explicitly mentioned here. Tests were executed sequentially against the same database instance. The `db_bench` tool was generated via `make release`.
The following tests were executed in sequence:
# Test 1. Bulk Load of keys in Random Order (benchmark.sh bulkload)
NUM\_KEYS=900000000 CACHE\_SIZE=6442450944 benchmark.sh bulkload
Measure performance to load 900 million keys into the database. The keys are inserted in random order. The database is empty at the beginning of this benchmark run and gradually fills up. No data is being read when the data load is in progress.
Version
Opts
Time
ops/sec
mb/sec
usec/op
p50
p75
p99
p99.9
p99.99
Stall-time
Stall%
du -s -k
7.2.2
None
4021
1003732
402.0
1.0
0.5
0.8
2
7
22
00:00:52.558
6.3
101406408
7.2.2
DIO
3976
1021386
409.1
1.0
0.5
0.8
2
3
32
00:00:41.215
4.9
101404476
7.1.1
None
3951
1028135
411.8
1.0
0.5
0.8
2
3
21
00:00:42.580
5.1
101407124
7.1.1
DIO
3920
1046129
419.0
1.0
0.5
0.8
2
3
20
00:00:33.023
3.9
101407876
7.0.3
None
3934
1040089
416.6
1.0
0.5
0.8
2
3
22
00:01:02.307
7.4
101406288
7.0.3
DIO
3879
1060242
424.7
0.9
0.5
0.8
2
3
21
00:00:50.523
6.0
101405820
6.29.1
None
3898
1045486
418.8
1.0
0.5
0.8
2
3
55
00:01:17.876
9.3
101405948
6.29.1
DIO
3819
1065706
426.9
0.9
0.5
0.8
2
3
25
00:01:09.405
8.3
101404236
6.29.0
None
3899
1047693
419.6
1.0
0.5
0.8
2
3
108
00:01:25.637
10.2
101407032
6.29.0
DIO
3828
1061703
425.3
0.9
0.5
0.8
2
3
21
00:00:56.298
6.7
101405356
6.28.0
None
3924
1050028
420.6
1.0
0.5
0.8
2
3
60
00:01:17.288
9.2
101406260
6.28.0
DIO
3819
1072892
429.7
0.9
0.5
0.8
2
3
29
00:01:01.648
7.9
101405916
6.27.0
None
3898
1052489
421.6
0.9
0.5
0.8
2
3
22
00:01:07.776
8.1
101406796
6.27.0
DIO
3826
1066941
427.4
0.9
0.5
0.8
2
3
21
00:00:58.306
6.9
101405580
6.26.0
None
3892
1043630
418.0
1.0
0.5
0.8
2
3
54
00:01:17.288
9.2
101407528
6.26.0
DIO
3899
1060561
424.8
0.9
0.5
0.8
2
3
22
00:01:04.536
7.7
101402764
6.25.0
None
3989
1032155
413.4
1.0
0.5
0.8
2
3
102
00:01:23.783
10.0
101407140
6.25.0
DIO
3899
1048824
420.1
1.0
0.5
0.8
2
3
22
00:01:04.747
7.7
101402764
6.24.0
None
3983
1025562
410.8
1.0
0.5
0.8
2
3
32
00:01:12.296
8.6
101406524
6.24.0
DIO
3880
1052049
421.4
1.0
0.5
0.8
2
3
22
00:01:05.862
7.8
101405064
6.23.0
None
4175
1015722
406.8
1.0
0.5
0.8
2
3
69
00:01:17.541
9.2
101405292
6.23.0
DIO
3885
1055232
422.7
0.9
0.5
0.8
2
3
21
00:00:52.360
6.2
101402116
6.22.1
None
4143
1013002
405.8
1.0
0.5
0.8
2
3
224
00:01:26.032
10.2
101405804
6.22.1
DIO
4058
1031703
413.2
1.0
0.5
0.8
2
3
125
00:01:23.019
9.9
101403424
6.21.2
None
4141
1017259
407.5
0.9
0.5
0.8
2
3
556
00:01:32.279
11.0
101406320
6.15.5
None
4068
1045195
418.6
1.0
0.5
0.8
1
3
980
00:02:08.223
15.3
101401808
6.10.4
None
4002
1062310
425.5
0.9
0.5
0.8
1
3
1013
00:02:24.652
17.2
101402936
# Test 2. Random Read (benchmark.sh readrandom)
NUM\_KEYS=900000000 CACHE\_SIZE=6442450944 DURATION=5400 benchmark.sh readrandom
Measure performance to randomly read existing keys. The database after bulkload was used as the starting point.
Version
Opts
ops/sec
mb/sec
usec/op
p50
p75
p99
p99.9
p99.99
7.2.2
None
136915
34.7
467.4
615.5
772.8
1270
1801
2840
7.2.2
DIO
189236
47.9
338.2
419.6
539.1
1022
1693
2297
7.1.1
None
145490
36.8
439.9
599.7
753.7
1252
1809
2813
7.1.1
DIO
189242
47.9
338.2
419.0
539.1
1037
1696
2294
7.0.3
None
145540
36.8
439.7
599.8
753.3
1251
1803
2803
7.0.3
DIO
189243
47.9
338.2
419.2
539.2
1029
1691
2246
6.29.1
None
145577
36.9
439.6
606.3
751.0
1204
1292
2091
6.29.1
DIO
189243
47.9
338.2
430.0
540.9
854
969
1291
6.29.0
None
145590
36.9
439.6
606.2
751.0
1204
1292
1936
6.29.0
DIO
189241
47.9
338.2
430.0
540.8
854
932
1289
6.28.0
None
146980
37.2
435.4
604.3
748.9
1195
1291
1984
6.28.0
DIO
189232
47.9
338.2
430.0
540.9
854
991
1293
6.27.0
None
146921
37.2
435.6
604.4
748.8
1194
1291
1980
6.27.0
DIO
189250
47.9
338.2
430.1
540.8
854
902
1287
6.26.0
None
128341
32.5
498.7
639.6
805.7
1272
1298
2156
6.26.0
DIO
189244
47.9
338.2
430.1
540.8
854
894
1287
6.25.0
None
128517
32.5
498.0
639.0
804.6
1272
1298
2220
6.25.0
DIO
189245
47.9
338.2
430.1
540.8
854
897
1289
6.24.0
None
130852
33.1
489.1
632.6
791.4
1266
1297
2152
6.24.0
DIO
189240
47.9
338.2
430.0
540.7
854
930
1292
6.23.0
None
137664
34.9
464.9
618.4
766.5
1244
1295
2557
6.23.0
DIO
189252
47.9
338.2
430.0
540.7
854
926
1296
6.22.1
None
138623
35.1
461.7
616.8
763.9
1239
1295
2663
6.22.1
DIO
189237
47.9
338.2
430.0
540.7
854
960
1291
6.21.2
None
138633
35.1
461.6
616.8
764.1
1240
1295
2461
6.15.5
None
138513
35.1
462.0
616.9
764.2
1240
1295
3083
6.10.4
None
138496
35.1
462.1
617.1
764.3
1240
1295
2484
# Test 3. Multi-Random Read (benchmark.sh multireadrandom)
NUM\_KEYS=900000000 CACHE\_SIZE=6442450944 DURATION=5400 benchmark.sh multireadrandom --multiread\_batched
Measure performance to randomly multi-get existing keys. The database after bulkload was used as the starting point.
Version
Opts
ops/sec
p50
p75
p99
p99.9
p99.99
7.2.2
None
136928
4657.7
5774.9
9416
9873
18001
7.2.2
DIO
189216
3415.8
4064.2
6422
6586
8602
7.1.1
None
145548
4387.8
5568.6
8899
9831
16943
7.1.1
DIO
189213
3413.7
4064.2
6422
6586
8630
7.0.3
None
145587
4386.7
5567.1
8886
9829
16789
7.0.3
DIO
189230
3413.5
4063.8
6422
6586
8590
6.29.1
None
145652
4376.9
5549.2
8702
9813
15243
6.29.1
DIO
189233
3410.8
4048.6
6406
6583
7498
6.29.0
None
145660
4376.7
5549.1
8701
9811
15305
6.29.0
DIO
189231
3410.3
4048.0
6406
6583
7310
6.28.0
None
147022
4345.6
5523.9
8584
9804
14594
6.28.0
DIO
189228
3410.5
4048.4
6406
6583
7679
6.27.0
None
146989
4346.2
5524.0
8579
9806
15833
6.27.0
DIO
189227
3409.6
4047.2
6405
6583
7332
6.26.0
None
128366
4933.4
6093.6
9672
9884
13845
6.26.0
DIO
189229
3409.0
4046.8
6405
6583
7282
6.25.0
None
128523
4927.2
6087.8
9670
9883
13727
6.25.0
DIO
189241
3408.7
4046.6
6404
6583
7525
6.24.0
None
130859
4836.9
5995.1
9630
9880
14169
6.24.0
DIO
189234
3409.0
4047.2
6406
6584
7996
6.23.0
None
137638
4607.1
5736.4
9360
9869
17172
6.23.0
DIO
189237
3409.0
4047.0
6406
6584
8125
6.22.1
None
138660
461.6
4576.1
5706.3
9294
9867
6.22.1
DIO
189235
338.2
3410.7
4047.7
6406
6583
6.21.2
None
138623
461.7
4577.4
5707.2
9294
9866
6.15.5
None
138507
462.0
4582.3
5710.2
9299
9867
6.10.4
None
138476
462.1
4583.0
5710.9
9298
9864
# Test 4. Range Scan (benchmark.sh fwdrange)
NUM\_KEYS=900000000 CACHE\_SIZE=6442450944 DURATION=5400 benchmark.sh fwdrange
Measure performance to randomly iterate over keys. The database after bulkload was used as the starting point.
Version
Opts
ops/sec
mb/sec
usec/op
p50
p75
p99
p99.9
p99.99
7.2.2
None
70097
280.8
913.0
791.9
1435.5
1892
2811
10210
7.2.2
DIO
78828
315.7
811.9
836.9
1093.2
1771
2601
2894
7.1.1
None
74491
298.4
859.1
775.3
1380.6
1889
1899
8592
7.1.1
DIO
78831
315.8
811.8
836.7
1093.1
1771
2598
2982
7.0.3
None
74510
298.4
858.9
775.2
1380.9
1889
2786
8384
7.0.3
DIO
78832
315.8
811.8
836.8
1093.1
1771
2603
2895
6.29.1
None
74530
298.5
858.7
775.8
1392.9
1881
1899
7807
6.29.1
DIO
78830
315.7
811.8
870.2
1090.8
1434
1862
2668
6.29.0
None
74535
298.5
858.6
775.7
1393.3
1881
1899
7553
6.29.0
DIO
78832
315.8
811.8
870.3
1090.3
1388
1858
2620
6.28.0
None
75231
301.3
850.7
773.7
1381.2
1880
1899
8224
6.28.0
DIO
78828
315.7
811.9
870.2
1090.8
1438
1862
2655
6.27.0
None
75246
301.4
850.5
773.2
1384.2
1880
1899
8360
6.27.0
DIO
78829
315.7
811.9
870.5
1090.2
1373
1855
2513
6.26.0
None
65717
263.2
973.8
808.2
1492.5
1884
1899
7217
6.26.0
DIO
78831
315.8
811.8
870.5
1090.2
1370
1855
2512
6.25.0
None
65813
263.6
972.4
807.7
1491.5
1884
1899
7338
6.25.0
DIO
78833
315.8
811.8
870.4
1090.2
1369
1856
2610
6.24.0
None
67004
268.4
955.1
802.8
1480.1
1884
1899
7216
6.24.0
DIO
78832
315.8
811.8
870.4
1090.2
1376
1856
2582
6.23.0
None
70459
282.2
908.3
789.6
1443.0
1883
1899
10273
6.23.0
DIO
78829
315.7
811.9
870.5
1090.1
1356
1855
2596
6.22.1
None
70971
284.3
901.7
787.8
1437.2
1882
1899
10274
6.22.1
DIO
78829
315.7
811.9
870.3
1090.5
1411
1859
2618
6.21.2
None
70967
284.3
901.8
787.8
1437.3
1882
1899
10253
6.15.5
None
70978
284.3
901.7
787.7
1437.5
1882
1899
9890
6.10.4
None
70973
284.3
901.7
787.6
1438.0
1882
1899
9945
# Test 4b. Reverse Range Scan (benchmark.sh revrange)
NUM\_KEYS=900000000 CACHE\_SIZE=6442450944 DURATION=5400 benchmark.sh revrange
Measure performance to randomly iterate over keys. The database after bulkload was used as the starting point.
Version
Opts
ops/sec
mb/sec
usec/op
p50
p75
p99
p99.9
p99.99
7.2.2
None
68785
275.5
930.4
806.0
1467.2
1892
2859
12052
7.2.2
DIO
76200
305.2
839.9
897.5
1114.2
1776
2617
2898
7.1.1
None
73116
292.9
875.3
788.1
1399.9
1889
2853
13338
7.1.1
DIO
76202
305.2
839.8
897.1
1114.1
1778
2631
3022
7.0.3
None
73149
293.0
874.9
788.0
1399.4
1889
2853
13524
7.0.3
DIO
76202
305.2
839.8
897.4
1114.0
1776
2632
3173
6.29.1
None
73167
293.1
874.7
788.9
1406.9
1882
1900
12818
6.29.1
DIO
76204
305.2
839.8
910.2
1112.1
1562
1874
2764
6.29.0
None
73170
293.1
874.6
788.6
1409.1
1882
1899
12688
6.29.0
DIO
76202
305.2
839.8
910.2
1111.5
1524
1870
2722
6.28.0
None
73839
295.8
866.7
786.5
1391.8
1881
1900
13492
6.28.0
DIO
76205
305.2
839.8
910.0
1112.1
1560
1873
2715
6.27.0
None
73861
295.8
866.5
786.0
1396.4
1881
1899
13488
6.27.0
DIO
76204
305.2
839.8
910.3
1111.3
1510
1869
2718
# Test 5. Overwrite (benchmark.sh overwrite)
NUM\_KEYS=900000000 CACHE\_SIZE=6442450944 DURATION=5400 benchmark.sh overwrite
Measure performance to randomly overwrite keys into the database. The database was first created by the previous benchmark.
Version
Opts
ops/sec
mb/sec
W-Amp
W-MB/s
usec/op
p50
p75
p99
p99.9
p99.99
Stall-time
Stall%
du -s -k
7.2.2
None
86617
34.7
9.5
149.7
738.9
449.7
777.6
10479
30005
58328
00:04:43.188
5.3
158540048
7.2.2
DIO
86839
34.8
9.4
154.6
737.0
460.7
775.4
9534
29149
54278
00:03:00.102
3.4
159135832
7.1.1
None
90203
36.1
9.4
155.4
709.5
418.5
746.0
10469
30015
58380
00:04:45.549
5.3
160992944
7.1.1
DIO
88590
35.5
9.6
154.6
722.4
440.2
754.0
9538
29313
55494
00:04:15.453
4.8
158372164
7.0.3
None
90985
36.4
9.4
155.8
703.4
418.2
743.9
10156
29987
57788
00:04:48.049
5.3
161110716
7.0.3
DIO
89686
35.9
9.5
154.1
713.6
439.3
752.3
9377
20921
53505
00:03:28.796
3.9
160356720
6.29.1
None
90711
36.3
9.4
155.1
705.5
418.2
740.0
10213
29779
57100
00:05:28.848
6.1
161099792
6.29.1
DIO
89469
35.8
9.5
154.4
715.3
431.6
748.0
9568
29143
54324
00:04:06.106
4.6
159661172
6.29.0
None
89373
35.8
9.6
155.3
716.1
434.1
756.1
10447
29891
57952
00:04:21.622
4.9
158912856
6.29.0
DIO
88517
35.5
9.5
152.6
723.0
455.1
759.1
9219
28694
51750
00:03:31.235
3.9
160258772
6.28.0
None
89791
36.0
9.4
153.7
712.4
430.9
751.9
10292
29839
58737
00:04:15.276
4.8
161859856
6.28.0
DIO
88108
35.3
9.5
152.4
726.4
449.4
763.5
9508
28917
54122
00:03:25.719
3.8
159865440
6.27.0
None
89815
36.0
9.5
154.1
712.6
427.7
749.4
10533
29660
57615
00:04:30.399
5.0
160273772
6.27.0
DIO
88440
35.4
9.4
151.6
723.6
455.0
761.2
9383
28764
52844
00:03:20.977
3.7
159572484
6.26.0
None
90340
36.2
9.4
153.6
708.4
430.2
742.5
10198
29692
55635
00:04:54.193
5.5
161202432
6.26.0
DIO
88401
35.4
9.6
154.5
724.0
446.0
754.6
9418
28911
52526
00:03:50.428
4.3
158469672
6.25.0
None
89567
35.9
9.4
155.2
714.5
419.4
742.7
10327
29952
59957
00:05:52.335
6.5
160392244
6.25.0
DIO
88549
35.5
9.5
153.6
722.7
433.9
743.6
9483
29064
54109
00:05:00.728
5.6
158500488
6.24.0
None
90829
36.4
4.7
155.2
704.6
397.1
726.4
10359
29968
58160
00:07:01.849
7.9
160757048
6.24.0
DIO
90105
36.1
4.8
153.7
710.3
421.8
736.9
9344
28869
52676
00:05:22.128
6.0
160833572
6.23.0
None
89052
35.7
4.7
151.3
718.7
442.5
758.8
10263
29763
53874
00:04:40.429
5.2
160633196
6.23.0
DIO
88624
35.5
4.9
152.4
722.1
441.5
749.0
9319
28887
53792
00:04:53.783
5.5
158994508
6.22.1
None
91586
36.7
4.7
155.0
698.8
380.5
709.4
10140
29887
58244
00:08:29.153
9.5
161321740
6.22.1
DIO
90310
36.2
4.8
154.7
708.7
419.0
730.1
9227
28816
55513
00:06:22.790
7.1
160400436
6.21.2
None
91776
36.8
4.7
155.6
697.3
379.9
708.7
10055
29782
55942
00:08:24.882
9.4
162082088
6.15.5
None
92911
37.2
4.7
158.4
688.8
351.9
697.7
10031
29894
58333
00:08:43.334
9.7
161156844
6.10.4
None
94539
37.9
4.7
161.9
676.9
328.4
700.4
10022
29843
56548
00:07:11.226
8.0
162965216
# Test 6. Multi-threaded read and single-threaded write (benchmark.sh readwhilewriting)
NUM\_KEYS=900000000 CACHE\_SIZE=6442450944 DURATION=5400 MB\_WRITE\_PER\_SEC=2 benchmark.sh readwhilewriting
Measure performance with one writer and multiple reader threads. The writes are rate limited.
Version
Opts
ops/sec
mb/sec
W-Amp
W-MB/s
usec/op
p50
p75
p99
p99.9
p99.99
du -s -k
7.2.2
None
98240
31.1
18.1
11.4
651.4
600.6
829.8
3963
6041
10139
140646588
7.2.2
DIO
143283
45.3
17.1
7.3
446.7
394.8
539.8
2820
4315
6393
140470436
7.1.1
None
102056
32.5
16.9
10.6
627.1
584.8
803.2
3931
6031
9844
141627716
7.1.1
DIO
142958
45.3
17.9
7.6
447.7
395.6
540.1
2819
4316
6405
140849884
7.0.3
None
101948
32.5
17.0
10.7
627.7
585.6
803.6
3931
6028
9824
141767112
7.0.3
DIO
142923
45.4
18.2
7.8
447.8
393.0
539.4
2825
4322
6414
141164436
6.29.1
None
100445
31.8
28.3
18.2
637.1
593.0
810.3
3906
6524
18544
140795968
6.29.1
DIO
141799
44.8
31.5
14.2
451.3
397.1
541.4
2792
4744
9095
140017864
6.29.0
None
100853
31.9
27.7
17.7
634.6
592.9
810.8
3893
6480
17827
140416272
6.29.0
DIO
141947
44.8
32.6
14.4
450.9
397.4
542.1
2786
4791
9273
139972676
6.28.0
None
101233
32.0
28.3
18.3
632.2
591.6
807.0
3892
6530
19073
140616192
6.28.0
DIO
141854
44.7
35.0
15.2
451.2
394.1
541.4
2796
5000
9696
139803484
6.27.0
None
101375
32.1
27.7
17.8
631.3
587.9
805.0
3893
6477
18216
140673616
6.27.0
DIO
142460
44.9
31.2
14.1
449.2
394.7
539.6
2789
4685
9127
139867840
6.26.0
None
91879
29.1
27.7
19.0
696.5
630.8
904.6
4010
6424
13872
140615968
6.26.0
DIO
142148
44.8
31.8
14.4
450.2
394.7
540.0
2793
4697
8939
139826380
6.25.0
None
91736
29.0
28.7
20.0
697.6
630.8
906.2
4019
6418
13775
140615968
6.25.0
DIO
141618
44.7
33.0
14.9
451.9
394.4
540.8
2800
4825
9113
140031428
6.24.0
None
92974
29.5
27.6
19.0
688.3
624.8
869.7
4010
6436
14558
140384360
6.24.0
DIO
141491
44.7
32.7
15.0
452.3
395.8
540.8
2802
4867
9311
140255568
6.23.0
None
96811
30.6
29.1
18.9
661.1
607.3
835.3
3966
6433
13513
140384360
6.23.0
DIO
142410
44.9
29.6
13.5
449.4
394.0
539.3
2789
4598
8989
139961824
6.22.1
None
96812
30.7
28.4
18.5
661.1
606.5
832.8
3958
6500
15777
140972560
6.22.1
DIO
140635
44.5
32.5
14.9
455.1
400.4
543.4
2804
5051
9348
140465744
6.21.2
None
96891
30.7
29.1
18.9
660.5
607.1
833.4
3961
6465
13669
141208940
6.15.5
None
96223
30.6
28.0
18.7
665.1
609.4
835.1
3965
6475
15613
141339712
6.10.4
None
95649
30.5
30.2
19.7
669.1
608.1
834.5
3999
6597
17861
141636760
# Test 7. Multi-threaded scan and single-threaded write (benchmark.sh fwdrangewhilewriting)
NUM\_KEYS=900000000 CACHE\_SIZE=6442450944 DURATION=5400 MB\_WRITE\_PER\_SEC=2 benchmark.sh fwdrangewhilewriting
Measure performance with one writer and multiple iterator threads. The writes are rate limited.
Version
Opts
ops/sec
mb/sec
W-Amp
W-MB/s
usec/op
p50
p75
p99
p99.9
p99.99
du -s -k
7.2.2
None
40675
162.9
17.4
7.4
1573.4
1374.6
1855.1
6293
13434
24996
141346104
7.2.2
DIO
35619
142.7
18.3
7.5
1796.6
1540.7
2171.8
6533
9698
13325
140957044
7.1.1
None
42202
169.0
16.5
7.3
1516.4
1322.2
1821.4
6168
13098
25099
142336676
7.1.1
DIO
35535
142.3
17.9
7.3
1800.8
1544.5
2175.7
6527
9691
13298
141591172
7.0.3
None
42436
170.0
17.3
7.8
1508.0
1310.0
1815.5
6198
13226
24937
142579812
7.0.3
DIO
35702
143.0
18.9
7.8
1792.5
1535.0
2165.4
6531
9702
13343
141636716
6.29.1
None
43138
172.8
17.6
7.8
1483.5
1294.3
1804.6
6089
13026
25065
141561940
6.29.1
DIO
36460
146.0
16.5
7.1
1755.2
1517.8
2128.9
6381
9572
12979
140761644
6.29.0
None
42806
171.5
17.0
7.6
1495.0
1311.0
1813.2
6101
13108
25308
140416272
6.29.0
DIO
36418
145.9
17.4
7.4
1757.2
1522.1
2124.5
6404
9624
13210
140619752
6.28.0
None
43564
174.5
17.3
7.7
1469.0
1282.2
1794.6
6055
12926
24865
141241492
6.28.0
DIO
36230
145.1
17.7
7.5
1766.3
1527.9
2142.4
6439
9653
13251
140537532
6.27.0
None
43229
173.2
18.3
8.3
1480.4
1290.3
1802.6
6123
13140
24987
141261580
6.27.0
DIO
35860
143.6
16.9
7.4
1784.5
1540.3
2181.7
6422
9603
13041
140542060
6.26.0
None
36960
148.0
17.2
8.2
1731.4
1534.2
2217.9
6477
13239
21533
141557396
6.26.0
DIO
35961
144.0
16.5
7.3
1779.5
1536.8
2174.2
6415
9603
13055
140627180
6.25.0
None
37344
149.6
17.9
8.4
1713.7
1513.5
2164.7
6489
13409
21654
141269488
6.25.0
DIO
36023
144.3
17.9
7.8
1776.5
1532.5
2162.0
6458
9672
13308
140685060
6.24.0
None
38940
156.0
17.7
8.1
1643.4
1445.8
1970.8
6411
13480
21757
141724476
6.24.0
DIO
35955
144.0
17.1
7.5
1779.8
1534.8
2173.0
6427
9615
13093
140989196
6.23.0
None
41322
165.5
16.7
7.6
1584.7
1359.9
1838.4
6225
13285
24338
141101776
6.23.0
DIO
35968
144.1
17.0
7.4
1779.2
1536.8
2167.6
6446
9648
13218
140731428
6.22.1
None
41244
165.2
16.7
7.6
1551.6
1362.3
1845.8
6234
13346
24988
141716340
6.22.1
DIO
35962
144.0
17.0
7.4
1779.5
1538.8
2150.6
6455
9661
13264
141008104
6.21.2
None
41360
165.7
18.2
8.0
1547.2
1354.1
1840.5
6257
13434
25280
141820100
6.15.5
None
42197
169.0
17.5
8.0
1516.6
1315.5
1817.8
6185
13018
23081
142157224
6.10.4
None
41827
167.5
17.6
8.0
1530.0
1329.2
1826.2
6212
13129
23244
142497356
# Test 7b. Multi-threaded scan and single-threaded write (benchmark.sh revrangewhilewriting)
NUM\_KEYS=900000000 CACHE\_SIZE=6442450944 DURATION=5400 MB\_WRITE\_PER\_SEC=2 benchmark.sh revrangewhilewriting
Measure performance with one writer and multiple iterator threads. The writes are rate limited.