Topik ini menjelaskan cara menguji dampak enkripsi SSL pada kinerja instance ApsaraDB for MongoDB.
Lingkungan pengujian
Buat sebuah ECS instance dan instance ApsaraDB for MongoDB. Untuk informasi lebih lanjut, lihat Buat Instance Set Replika dan Buat dan Kelola ECS Instance di Konsol (Versi Ekspres).
Tabel berikut menjelaskan pengaturan untuk ECS instance dan ApsaraDB for MongoDB instance yang digunakan dalam pengujian.
ApsaraDB for MongoDB Instance
Arsitektur Instance: Instance Set Replika
Jumlah Node Primer dan Sekunder: Tiga Node
Jumlah Node Baca-Saja: Satu Node
Spesifikasi Instance: 1 Core dan 2 GB Memori (General-Purpose)
Versi Instance: MongoDB 4.2
ECS Instance
Tipe Instance: ecs.e-c1m2.large (2 Core dan 4 GB Memori)
Metode pengujian
Impor data uji
Dalam pengujian, Yahoo! Cloud Serving Benchmark (YCSB) digunakan untuk mengimpor 1.000.000 entri ke dalam koleksi bernama usertable di database bernama ycsb. Jalankan perintah berikut untuk mengimpor entri:
./bin/ycsb load mongodb -s -p workload=site.ycsb.workloads.CoreWorkload -p recordcount=1000000 -p mongodb.url="mongodb://root:******@dds-bp103175eafac****.mongodb.rds.aliyuncs.com:3717,dds-bp103175eafac****.mongodb.rds.aliyuncs.com:3717,dds-bp103175eafac****.mongodb.rds.aliyuncs.com:3717/admin?readPreference=secondary&replicaSet=mgset-82894753" -threads 8Koleksi yang dihasilkan oleh YCSB memiliki struktur berikut:
{
"_id": "user1352498093671118016",
"field1": "BinData(0,\"L1s/KS8+MlYhISUuIz8qNVx9PTRuNiooNlolPVMzJCE0ODNuP15zLjB6NSU4LV0pPC98LkovOFttOyQkL1chNV8tOlxrKlstPkp3IzkiLTcuLU93ITRqOzEwPScsIEx5L1o5JQ==\")",
"field0": "BinData(0,\"I0I/NDAmNUkrLFA3PEA5IEI3KC4qKEJ1LCc6JV8rJlo7KUR3MDRqMk95KjhoIlUjLy1qMls9OFU7PTpuKTZsNlUpMVYvNSI4KDlwK1trIUpnMlInKSAmNDg8LSpmOl85PkozMA==\")",
"field7": "BinData(0,\"NzxyPjUkNiYsOEp1MUIpIDA0M1U/JE1nMjMmODhkIko/LEh1NSRqKl1jKDBqJjMqMiw8PSc6KjgsNEwrLFkpKFh9OzQ+MS86LiB4P1oxLVxjIiQgMCdsM0AhO0QzNTFqI1dpMw==\")",
"field6": "BinData(0,\"MVhpIj1uI0RlJ1AtP0t/LkAxMVp9MlU3KFJpK0Z3M0M/OE55IFBhPyA6Njp+L1tnJjh4Iic4K1F/Oi9gKz44PFFpPE5jNydqKUJrPyV4KDY2LDd0Nic6PC9wPDhgNykwOj10Iw==\")",
"field9": "BinData(0,\"OEA/NDRwLilwLzVoMz5oIzVuLStoPlF9NVU5MVd3PDUkPV0nPl07OU05LkYnKDQ8L0VrIkwlJDg+NCRuIitoNjV4PkM9NCt0LyE4PCFkKUI/LVwxKjdsMkgnICsgKFQrJit8Lg==\")",
"field8": "BinData(0,\"P0J/P0ozMCBwIjJwP0IpJUMlPkhhIkI3MU91OjUmMFM9NEBhJD8+OEdpJDh2OyxmMCQkKUgnJjYoKC0kKVMnKTQuODp6JjVwKSRwI1FhJy88PVAhPiE2OCMsKlYvJF1xOEUrJA==\")",
"field3": "BinData(0,\"Mjc6KE4zJTEuJCJ4P18lNCZ4NkAtKTAwLFUvMDEsOzUkIEs3MVEzKT4mL1Q5IVF9N0N3O1snIUZ1L0k9IUY7IV8nNiQ+KTJ0I097Llg1MjE0PCQ4KDV2KzYsIDtwNzhuKkQrMA==\")",
"field2": "BinData(0,\"Jit6L0olLTByJzpuPygyKSE8Li9iK00xIig4PVQhKTBqLkI/O0N9Izs+NVk/ISVmIy14Nko3NyxoI1Z1Pyo4JVt/MylsK1t9PS9yP1kzJFMjPF43P1l5P1xtPDAqLF57IiAsPQ==\")",
"field5": "BinData(0,\"NSd2NiskPzcmITU4Oz58NzliP0ZpOz5wKiI0OVhlNDx0PlV1OllnNzJiOyMmOF45IEg7OD90KUZnP0g5OUJzK0M/OyN4O15lPzA6LTUgNUw9NDVoL0QrOTssISQ2KCw6KUJlKg==\")",
"field4": "BinData(0,\"NDNkKjFuPyxsJzEmNzMqLVJzL0YpMTNwMjs8MTRiNEYtLE05P0I9NEU1LS4yNEFpNjUsOUs9JEs1IU5jOF5vIjpiNTMuKSY6K0s1LDp2JEp9KyFiIS1+J1U/LkoxMEp5OzJiIw==\")"
}Jalankan skrip uji
YCSB tidak mendukung uji stres dengan enkripsi SSL diaktifkan. Oleh karena itu, skrip uji digunakan untuk uji stres dalam topik ini. Skrip tersebut berisi konten berikut.
import time
import pymongo
import datetime
import logging as log
from functools import wraps
log.basicConfig(
level=log.INFO, format='%(asctime)s - [line %(lineno)d] : %(levelname)s - %(message)s')
console = log.StreamHandler()
console.setLevel(log.INFO)
formatter = log.Formatter(
'%(asctime)s - [line %(lineno)d] : %(levelname)s - %(message)s')
console.setFormatter(formatter)
def time_recorder():
def inner(func):
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
elapsed_time = (end_time - start_time) * 1000
print_latency = kwargs.get("print_latency", False)
return_latency = kwargs.get("return_latency", False)
if print_latency:
log.info(
f"Fungsi {func.__name__} membutuhkan waktu {elapsed_time:.4f} millidetik untuk dieksekusi.")
if return_latency:
return result, elapsed_time
return result
return wrapper
return inner
@time_recorder()
def build_client_without_ssl(**kwargs):
client = pymongo.MongoClient(
"mongodb://root:******@dds-bp103175eafac****.mongodb.rds.aliyuncs.com:3717,dds-bp103175eafac****.mongodb.rds.aliyuncs.com:3717,dds-bp103175eafac****.mongodb.rds.aliyuncs.com:3717/admin?readPreference=secondary&replicaSet=mgset-82894753")
return client
@time_recorder()
def build_client_with_ssl(**kwargs):
client = pymongo.MongoClient(
"mongodb://root:******@dds-bp103175eafac****.mongodb.rds.aliyuncs.com:3717,dds-bp103175eafac****.mongodb.rds.aliyuncs.com:3717,dds-bp103175eafac****.mongodb.rds.aliyuncs.com:3717/admin?readPreference=secondary&replicaSet=mgset-82894753&tls=true&tlsAllowInvalidHostnames=true&tlsCAFile=/root/ApsaraDB-CA-Chain.pem")
return client
@time_recorder()
def find_one(client, **kwargs):
client["ycsb"]["usertable"].find_one()
def test_connection():
client = build_client_without_ssl(print_latency=True)
find_one(client)
client = build_client_with_ssl(print_latency=True)
find_one(client)
test_connection()
@time_recorder()
def test(with_ssl=False, repeat=5000, **kwargs):
log.info(f"uji, with_ssl: {with_ssl}, repeat: {repeat}")
ssl_suffix = "tanpa-ssl"
if with_ssl:
ssl_suffix = "dengan-ssl"
suffix = f"{repeat}-{ssl_suffix}.log"
only_connection_file = f"hanya-koneksi-{suffix}"
first_query_file = f"pertama-query-{suffix}"
connection_and_first_query_file = f"koneksi-dan-pertama-query-{suffix}"
only_connection_f = open(only_connection_file, 'w')
first_query_f = open(first_query_file, 'w')
connection_and_first_query_f = open(connection_and_first_query_file, 'w')
for _ in range(repeat):
client = None
connection_latency = 0
if with_ssl:
client, connection_latency = build_client_with_ssl(
return_latency=True)
else:
client, connection_latency = build_client_without_ssl(
return_latency=True)
_, query_latency = find_one(client, return_latency=True)
only_connection_f.write(f"{connection_latency}\n")
first_query_f.write(f"{query_latency}\n")
connection_and_first_query_f.write(f"{connection_latency + query_latency}\n")
only_connection_f.close()
first_query_f.close()
connection_and_first_query_f.close()
log.info(f"uji selesai, tulis ke {only_connection_file}, {first_query_file} dan {connection_and_first_query_file}")
test(False, 5000, print_latency=True)
test(True, 5000, print_latency=True)
@time_recorder()
def run(client, log_file, repeat=5000, **kwargs):
start = time.time()
log.info(f"mulai query, repeat: {repeat}")
with open(log_file, 'w') as f:
for _ in range(repeat):
latency = find_one(client, return_latency=True)
f.write(f"{latency}\n")
end = time.time()
total = (end - start) * 1000
avg = total / repeat
log.info(
f"akhir query, repeat: {repeat}, total: {total} millidetik, rata-rata: {avg} millidetik")
client = build_client_without_ssl()
run(client, "tanpa-ssl.log")
client = build_client_with_ssl()
run(client, "dengan-ssl.log")
Selama pengujian, Anda dapat memodifikasi parameter berikut sesuai kebutuhan:
client: Ganti string koneksi, nama pengguna, dan kata sandi dalam tanda kurung parameterpymongo.MongoClient()dengan informasi aktual dari ApsaraDB for MongoDB instance.repeat: Jumlah kali pengujian dijalankan. Pengujian dijalankan sebanyak 5.000 kali. Anda dapat memodifikasi parameter ini sesuai kebutuhan.
Skrip mengeluarkan parameter berikut:
hanya-koneksi: Mencatat waktu yang dikonsumsi untuk menetapkan koneksi.pertama-query: mencatat durasi query pertama setelah koneksi ditetapkan.koneksi-dan-pertama-query: Mencatat durasi total mulai dari penyetapan koneksi hingga selesainya query pertama. Nilai parameter ini adalah jumlah dari nilai hanya-koneksi dan pertama-query.latensi: Mencatat durasi rata-rata dari 5.000 query ketika klien yang ditentukan oleh pymongo.MongoClient() digunakan kembali.
Hasil pengujian
Tabel berikut menjelaskan nilai rata-rata dari 5.000 pengujian.
Item | Waktu yang dikonsumsi dengan enkripsi SSL dinonaktifkan (ms) | Waktu yang dikonsumsi dengan enkripsi SSL diaktifkan (ms) |
Waktu yang dikonsumsi untuk menetapkan koneksi | 3,7009 | 19,8515 |
Durasi query pertama setelah koneksi ditetapkan | 20,7456 | 43,5884 |
Total durasi dari penyetapan koneksi hingga selesainya query pertama | 24,4465 | 63,4399 |
Durasi query rata-rata ketika klien yang ditentukan digunakan kembali | 0,7506 | 0,7643 |
Setelah pengujian, perbedaan antara durasi dengan enkripsi SSL diaktifkan dan dinonaktifkan terutama terletak pada penyetapan koneksi. Jika koneksi yang ada digunakan kembali, perbedaan kecil terdapat antara durasi query rata-rata dengan enkripsi SSL diaktifkan dan dinonaktifkan. Alasan utama untuk perbedaan durasi kecil ini meliputi dua aspek berikut:
Round-Trip Time (RTT) tambahan ada ketika koneksi dibuat antara klien dan server Anda karena penggunaan Transport Layer Security (TLS).
Jika Anda mengonfigurasi kolam koneksi, overhead RTT tambahan dari penyetapan koneksi tersebar secara merata. Jika Anda menggunakan kembali klien yang ditentukan setelah mengaktifkan fitur enkripsi SSL, TLS RTT dapat diminimalkan selama setiap penyetapan koneksi.
Setelah koneksi ditetapkan, overhead tambahan dihasilkan ketika algoritma enkripsi dan dekripsi digunakan oleh badan pesan.
CPU dapat dengan cepat mengenkripsi dan mendekripsi badan pesan, aspek sistem lainnya mungkin memakan waktu lama dalam query, seperti disk I/O dan antrian menunggu, dan dampak enkripsi dan dekripsi pada kinerja keseluruhan relatif kecil.