RocksDB
RocksDB là một công cụ lưu trữ với giao diện key/value, trong đó các khóa và giá trị là các luồng byte tùy ý. Nó được phát triển bởi Facebook bằng ngôn ngữ lập trình C++ dựa trên LevelDB.
- Hướng dẫn cài đặt RocksDB trên RHEL/Centos 7
- RocksDB - Open database
- RocksDB - Iterator
- RocksDB - Put data
- RocksDB - Get data
- RocksDB - Delete data
- RocksDB - Merge data
- RocksDB - Write batch
- RocksDB - Rate Limiter
- RocksDB - Prefix Seek
- RocksDB - Compaction Filter
- RocksDB - Column Families
- RocksDB - Low Priority Write
- RocksDB - Time To Live
- RocksDB - Transaction
- RocksDB - Snapshot data
- RocksDB - Delete Range
- RocksDB - Atomic Flush
- RocksDB - Read only và Secondary instances
- RocksDB - Wide Columns
- RocksDB - BlobDB
- RocksDB - MemTable
- RocksDB - Leveled Compaction
- RocksDB - Universal compaction style
- RocksDB - FIFO compaction style
- RocksDB - SST
- RocksDB - Delete Stale Files
- RocksDB - Partitioned Index/Filters
- RocksDB - Repairer
- RocksDB - Write Batch With Index
- RocksDB - Performance Benchmarks
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
Yêu cầu:
- Java: OpenJDK 1.7+ (required only for RocksJava)
- Tools:
- curl (recommended; required only for RocksJava)
- Libraries:
- Architecture: x86 / x86_64 / arm64 / ppc64le / s390x
- C/C++ Compiler: GCC 4.8+ or Clang
- Tools:
- GNU Make or CMake 3.14.5+
Hướng dẫn cài đặt
-Cài gói gcc4.8:
yum install gcc48-c++
- Cài gói gflags:
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:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
- Cài gói snappy:
sudo yum install snappy snappy-devel
- Cài gói zlib:
sudo yum install zlib zlib-devel
- Cài gói bzip2:
sudo yum install bzip2 bzip2-devel
- Cài gói lz4:
sudo yum install lz4-devel
- Cài gói ASAN (optional for debugging):
sudo yum install libasan
- Cài gói zstandard:
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:
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:
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++:
#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:
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++:
#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:
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++:
#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:
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++:
#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:
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++:
#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++:
#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++:
#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:
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++:
#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:
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++:
#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:
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++:
#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:
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++:
#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:
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ụ:
#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:
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++:
#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:
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++:
#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:
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++:
#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:
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++:
#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:
- 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.
- 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.
- 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.
- Đọ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:
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++:
#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:
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++:
#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:
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ụ:
# 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 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.
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 | 33680 | 134.9 | 17.3 | 7.5 | 1900.1 | 1668.2 | 2417.1 | 7207 | 16605 | 29880 | 142066536 |
7.2.2 | DIO | 31215 | 125.0 | 16.4 | 6.9 | 2050.0 | 1755.3 | 2528.0 | 7637 | 10178 | 13981 | 141817860 |
7.1.1 | None | 34825 | 139.5 | 17.4 | 7.7 | 1837.6 | 1623.9 | 2360.8 | 6742 | 16569 | 30135 | 142975980 |
7.1.1 | DIO | 31259 | 125.2 | 17.4 | 7.3 | 2047.2 | 1744.1 | 2520.7 | 7673 | 10205 | 13980 | 142349268 |
7.0.3 | None | 35015 | 140.3 | 17.5 | 7.8 | 1827.6 | 1614.4 | 2345.4 | 6695 | 16540 | 29947 | 143211480 |
7.0.3 | DIO | 31155 | 124.8 | 15.9 | 7.0 | 2054.0 | 1753.5 | 2529.0 | 7627 | 9970 | 13948 | 142568752 |
6.29.1 | None | 35535 | 142.3 | 17.6 | 7.8 | 1800.8 | 1598.9 | 2320.1 | 6572 | 16547 | 30132 | 142191812 |
6.29.1 | DIO | 31839 | 127.5 | 16.8 | 7.3 | 2009.9 | 1731.9 | 2489.0 | 7184 | 9882 | 13917 | 141520096 |
6.29.0 | None | 35676 | 142.9 | 17.3 | 7.8 | 1793.8 | 1592.1 | 2307.6 | 6569 | 16711 | 30812 | 141867556 |
6.29.0 | DIO | 31896 | 127.8 | 17.8 | 7.8 | 2006.3 | 1728.1 | 2483.7 | 7320 | 10017 | 13938 | 141162940 |
6.28.0 | None | 35882 | 143.7 | 16.6 | 7.5 | 1783.4 | 1588.0 | 2292.4 | 6534 | 16405 | 30385 | 142078076 |
6.28.0 | DIO | 31855 | 127.6 | 16.5 | 7.3 | 2008.9 | 1727.1 | 2485.2 | 7287 | 10012 | 14000 | 141298660 |
6.27.0 | None | 35594 | 142.6 | 17.0 | 7.7 | 1797.9 | 1596.8 | 2315.0 | 6566 | 16418 | 29917 | 142075232 |
6.27.0 | DIO | 32086 | 128.5 | 17.0 | 7.4 | 1994.4 | 1717.5 | 2470.2 | 7116 | 9865 | 13867 | 141261580 |
Appendix
fio test results
]$ fio --randrepeat=1 --ioengine=sync --direct=1 --gtod_reduce=1 --name=test --filename=/data/test_file --bs=4k --iodepth=64 --size=4G --readwrite=randread --numjobs=32 --group_reporting
test: (g=0): rw=randread, bs=4K-4K/4K-4K/4K-4K, ioengine=sync, iodepth=64
...
fio-2.14
Starting 32 processes
Jobs: 3 (f=3): [_(3),r(1),_(1),E(1),_(10),r(1),_(13),r(1),E(1)] [100.0% done] [445.3MB/0KB/0KB /s] [114K/0/0 iops] [eta 00m:00s]
test: (groupid=0, jobs=32): err= 0: pid=28042: Fri Jul 24 01:36:19 2020
read : io=131072MB, bw=469326KB/s, iops=117331, runt=285980msec
cpu : usr=1.29%, sys=3.26%, ctx=33585114, majf=0, minf=297
IO depths : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued : total=r=33554432/w=0/d=0, short=r=0/w=0/d=0, drop=r=0/w=0/d=0
latency : target=0, window=0, percentile=100.00%, depth=64
Run status group 0 (all jobs):
READ: io=131072MB, aggrb=469325KB/s, minb=469325KB/s, maxb=469325KB/s, mint=285980msec, maxt=285980msec
Disk stats (read/write):
nvme1n1: ios=33654742/61713, merge=0/40, ticks=8723764/89064, in_queue=8788592, util=100.00%
]$ fio --randrepeat=1 --ioengine=libaio --direct=1 --gtod_reduce=1 --name=test --filename=/data/test_file --bs=4k --iodepth=64 --size=4G --readwrite=randread
test: (g=0): rw=randread, bs=4K-4K/4K-4K/4K-4K, ioengine=libaio, iodepth=64
fio-2.14
Starting 1 process
Jobs: 1 (f=1): [r(1)] [100.0% done] [456.3MB/0KB/0KB /s] [117K/0/0 iops] [eta 00m:00s]
test: (groupid=0, jobs=1): err= 0: pid=28385: Fri Jul 24 01:36:56 2020
read : io=4096.0MB, bw=547416KB/s, iops=136854, runt= 7662msec
cpu : usr=22.20%, sys=48.81%, ctx=144112, majf=0, minf=73
IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.1%, >=64=100.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.1%, >=64=0.0%
issued : total=r=1048576/w=0/d=0, short=r=0/w=0/d=0, drop=r=0/w=0/d=0
latency : target=0, window=0, percentile=100.00%, depth=64
Run status group 0 (all jobs):
READ: io=4096.0MB, aggrb=547416KB/s, minb=547416KB/s, maxb=547416KB/s, mint=7662msec, maxt=7662msec
Disk stats (read/write):
nvme1n1: ios=1050868/1904, merge=0/1, ticks=374836/2900, in_queue=370532, util=98.70%