การต่อสู้ของสองยาโกะสึนะ หรือคาสซานดราปะทะเอชเบส ประสบการณ์ของทีม Sberbank

นี่ไม่ใช่เรื่องตลกด้วยซ้ำ แต่ดูเหมือนว่ารูปภาพนี้สะท้อนถึงสาระสำคัญของฐานข้อมูลเหล่านี้ได้แม่นยำที่สุดและท้ายที่สุดก็จะชัดเจนว่าทำไม:

การต่อสู้ของสองยาโกะสึนะ หรือคาสซานดราปะทะเอชเบส ประสบการณ์ของทีม Sberbank

ตามการจัดอันดับ DB-Engines ฐานข้อมูลเรียงเป็นแนว NoSQL ที่ได้รับความนิยมมากที่สุดสองฐานข้อมูลคือ Cassandra (ต่อไปนี้จะเรียกว่า CS) และ HBase (HB)

การต่อสู้ของสองยาโกะสึนะ หรือคาสซานดราปะทะเอชเบส ประสบการณ์ของทีม Sberbank

ตามความประสงค์แห่งโชคชะตา ทีมจัดการการโหลดข้อมูลของเราที่ Sberbank ได้ดำเนินการไปแล้ว นานมาแล้ว และทำงานอย่างใกล้ชิดกับ HB ในช่วงเวลานี้ เราศึกษาจุดแข็งและจุดอ่อนของมันค่อนข้างดีและเรียนรู้วิธีทำอาหาร อย่างไรก็ตาม การมีอยู่ของทางเลือกอื่นในรูปแบบของ CS มักจะบังคับให้เราต้องทรมานตัวเองเล็กน้อยด้วยความสงสัย: เราเลือกถูกแล้วหรือยัง? อีกทั้งผลลัพธ์ เปรียบเทียบซึ่งดำเนินการโดย DataStax พวกเขากล่าวว่า CS เอาชนะ HB ได้อย่างง่ายดายด้วยคะแนนที่แทบจะแหลกสลาย ในทางกลับกัน DataStax เป็นกลุ่มที่สนใจ และคุณไม่ควรเชื่อคำพูดของพวกเขา นอกจากนี้เรายังสับสนกับข้อมูลจำนวนเล็กน้อยเกี่ยวกับเงื่อนไขการทดสอบ ดังนั้นเราจึงตัดสินใจค้นหาด้วยตัวเองว่าใครคือราชาแห่ง BigData NoSql และผลลัพธ์ที่ได้ก็น่าสนใจมาก

อย่างไรก็ตาม ก่อนที่จะไปยังผลลัพธ์ของการทดสอบที่ดำเนินการ จำเป็นต้องอธิบายลักษณะสำคัญของการกำหนดค่าสภาพแวดล้อมก่อน ความจริงก็คือ CS สามารถใช้ในโหมดที่ช่วยให้ข้อมูลสูญหายได้ เหล่านั้น. นี่คือเวลาที่เซิร์ฟเวอร์ (โหนด) เดียวเท่านั้นที่รับผิดชอบข้อมูลของคีย์บางตัว และหากล้มเหลวด้วยเหตุผลบางประการ ค่าของคีย์นี้จะหายไป สำหรับงานหลายๆ อย่าง สิ่งนี้ไม่สำคัญ แต่สำหรับภาคการธนาคาร นี่เป็นข้อยกเว้นมากกว่ากฎเกณฑ์ ในกรณีของเรา สิ่งสำคัญคือต้องมีสำเนาข้อมูลหลายชุดเพื่อการจัดเก็บข้อมูลที่เชื่อถือได้

ดังนั้นจึงพิจารณาเฉพาะโหมดการทำงานของ CS ในโหมดการจำลองแบบสามเท่าเท่านั้น กล่าวคือ การสร้าง casespace ดำเนินการโดยใช้พารามิเตอร์ต่อไปนี้:

CREATE KEYSPACE ks WITH REPLICATION = {'class' : 'NetworkTopologyStrategy', 'datacenter1' : 3};

ถัดไป มีสองวิธีในการรับรองระดับความสอดคล้องที่ต้องการ กฎทั่วไป:
NW + NR > RF

ซึ่งหมายความว่าจำนวนการยืนยันจากโหนดเมื่อเขียน (NW) บวกจำนวนการยืนยันจากโหนดเมื่ออ่าน (NR) จะต้องมากกว่าปัจจัยการจำลอง ในกรณีของเรา RF = 3 ซึ่งหมายความว่าตัวเลือกต่อไปนี้เหมาะสม:
2 + 2 > 3
3 + 1 > 3

เนื่องจากเป็นสิ่งสำคัญพื้นฐานสำหรับเราในการจัดเก็บข้อมูลอย่างน่าเชื่อถือที่สุดเท่าที่จะเป็นไปได้ จึงเลือกรูปแบบ 3+1 นอกจากนี้ HB ยังทำงานบนหลักการที่คล้ายกัน นั่นคือ การเปรียบเทียบดังกล่าวจะยุติธรรมมากขึ้น

ควรสังเกตว่า DataStax ทำสิ่งที่ตรงกันข้ามในการศึกษา โดยตั้งค่า RF = 1 สำหรับทั้ง CS และ HB (สำหรับอย่างหลังโดยการเปลี่ยนการตั้งค่า HDFS) นี่เป็นประเด็นที่สำคัญมากเนื่องจากผลกระทบต่อประสิทธิภาพของ CS ในกรณีนี้มีขนาดใหญ่มาก ตัวอย่างเช่น รูปภาพด้านล่างแสดงเวลาที่เพิ่มขึ้นในการโหลดข้อมูลลงใน CS:

การต่อสู้ของสองยาโกะสึนะ หรือคาสซานดราปะทะเอชเบส ประสบการณ์ของทีม Sberbank

เราจะเห็นสิ่งต่อไปนี้: ยิ่งเธรดที่แข่งขันกันเขียนข้อมูลมากเท่าไรก็ยิ่งใช้เวลานานเท่านั้น นี่เป็นเรื่องปกติ แต่สิ่งสำคัญคือการลดประสิทธิภาพของ RF=3 จะสูงขึ้นอย่างมาก กล่าวอีกนัยหนึ่ง ถ้าเราเขียน 4 เธรดลงใน 5 ตารางแต่ละตาราง (รวม 20 ตาราง) ดังนั้น RF=3 จะสูญเสียประมาณ 2 ครั้ง (150 วินาทีสำหรับ RF=3 เทียบกับ 75 สำหรับ RF=1) แต่ถ้าเราเพิ่มภาระโดยการโหลดข้อมูลลงใน 8 ตารางโดยมี 5 เธรดต่อเธรด (รวม 40 รายการ) ดังนั้นการสูญเสีย RF=3 จะเป็น 2,7 เท่าแล้ว (375 วินาทีต่อ 138)

บางทีนี่อาจเป็นความลับบางส่วนที่ทำให้การทดสอบโหลดสำเร็จโดย DataStax สำหรับ CS เนื่องจากสำหรับ HB ที่จุดยืนของเรา การเปลี่ยนปัจจัยการจำลองจาก 2 เป็น 3 ไม่มีผลกระทบใดๆ เหล่านั้น. ดิสก์ไม่ใช่ปัญหาคอขวดของ HB สำหรับการกำหนดค่าของเรา อย่างไรก็ตาม ยังมีข้อผิดพลาดอื่นๆ อีกมากมายที่นี่ เนื่องจากควรสังเกตว่าเวอร์ชัน HB ของเราได้รับการแก้ไขและปรับแต่งเล็กน้อย สภาพแวดล้อมแตกต่างไปจากเดิมอย่างสิ้นเชิง เป็นต้น นอกจากนี้ ยังเป็นที่น่าสังเกตว่าบางทีฉันอาจไม่รู้วิธีเตรียม CS อย่างถูกต้อง และมีวิธีที่มีประสิทธิภาพมากกว่านี้ในการทำงาน และฉันหวังว่าเราจะทราบคำตอบในความคิดเห็น แต่สิ่งแรกก่อน

การทดสอบทั้งหมดดำเนินการบนคลัสเตอร์ฮาร์ดแวร์ที่ประกอบด้วยเซิร์ฟเวอร์ 4 เครื่อง โดยแต่ละเซิร์ฟเวอร์มีการกำหนดค่าดังต่อไปนี้:

CPU: Xeon E5-2680 v4 @ 2.40GHz 64 เธรด
ดิสก์: 12 ชิ้น SATA HDD
เวอร์ชันจาวา: 1.8.0_111

เวอร์ชัน CS: 3.11.5

พารามิเตอร์ cassandra.ymlnum_tokens: 256
Hinted_handoff_enabled: จริง
Hinted_handoff_throttle_in_kb: 1024
max_hints_delivery_threads: 2
tips_directory: /data10/cassandra/hints
tips_flush_ช่วงเวลา_in_ms: 10000
max_hints_file_size_in_mb: 128
ชุดบันทึก_replay_throttle_in_kb: 1024
ผู้ตรวจสอบสิทธิ์: AllowAllAuthenticator
ผู้อนุญาต: AllowAllAuthorizer
Role_Manager: แคสแซนดราโรเลผู้จัดการ
Roles_validity_in_ms: 2000
การอนุญาต_validity_in_ms: 2000
ข้อมูลประจำตัว_validity_in_ms: 2000
พาร์ติชัน: org.apache.cassandra.dht.Murmur3Partitioner
data_file_directories:
- /data1/cassandra/data # แต่ละไดเร็กทอรี dataN เป็นดิสก์แยกต่างหาก
- /data2/คาสซานดรา/data
- /data3/คาสซานดรา/data
- /data4/คาสซานดรา/data
- /data5/คาสซานดรา/data
- /data6/คาสซานดรา/data
- /data7/คาสซานดรา/data
- /data8/คาสซานดรา/data
commitlog_directory: /data9/cassandra/commitlog
cdc_enabled: เท็จ
disk_failure_policy: หยุด
commit_failure_policy: หยุด
เตรียม_statements_cache_size_mb:
thrift_prepared_statements_cache_size_mb:
คีย์_แคช_ขนาด_in_mb:
key_cache_save_ช่วงเวลา: 14400
row_cache_size_in_mb: 0
row_cache_save_ช่วงเวลา: 0
counter_cache_size_in_mb:
counter_cache_save_ช่วงเวลา: 7200
save_caches_directory: /data10/cassandra/saved_caches
commitlog_sync: เป็นระยะ
commitlog_sync_term_in_ms: 10000
commitlog_segment_size_in_mb: 32
เมล็ดพันธุ์_ผู้ให้บริการ:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
พารามิเตอร์:
— เมล็ด: "*,*"
concurrent_reads: 256 # ลอง 64 - ไม่พบความแตกต่าง
concurrent_writes: 256 # ลอง 64 - ไม่สังเกตเห็นความแตกต่าง
concurrent_counter_writes: 256 # ลอง 64 - ไม่พบความแตกต่าง
concurrent_materialized_view_writes: 32
memtable_heap_space_in_mb: 2048 # ลอง 16 GB - มันช้ากว่า
memtable_allocation_type: heap_buffers
index_summary_capacity_in_mb:
index_summary_resize_interval_in_ minutes: 60
Trickle_fsync: เท็จ
Trickle_fsync_interval_in_kb: 10240
ที่เก็บข้อมูล_พอร์ต: 7000
ssl_storage_port: 7001
Listen_address: *
ที่อยู่ออกอากาศ: *
Listen_on_broadcast_address: จริง
internode_authenticator: org.apache.cassandra.auth.AllowAllInternodeAuthenticator
start_native_transport: จริง
Native_transport_port: 9042
start_rpc: จริง
rpc_address: *
rpc_port: 9160
rpc_keepalive: จริง
rpc_server_type: ซิงค์
thrift_framed_transport_size_in_mb: 15
increamental_backups: เท็จ
snapshot_before_compacation: เท็จ
auto_snapshot: จริง
คอลัมน์_ดัชนี_ขนาด_in_kb: 64
คอลัมน์_ดัชนี_แคช_ขนาด_in_kb: 2
พร้อมกัน_compactors: 4
การบดอัด_throughput_mb_per_sec: 1600
sstable_preemptive_open_interval_in_mb: 50
read_request_timeout_in_ms: 100000
range_request_timeout_in_ms: 200000
write_request_timeout_in_ms: 40000
counter_write_request_timeout_in_ms: 100000
cas_contention_timeout_in_ms: 20000
ตัดทอน_request_timeout_in_ms: 60000
คำขอ_หมดเวลา_in_ms: 200000
slow_query_log_timeout_in_ms: 500
cross_node_timeout: เท็จ
endpoint_snitch: GossipingPropertyFileSnitch
dynamic_snitch_update_interval_in_ms: 100
dynamic_snitch_reset_interval_in_ms: 600000
dynamic_snitch_badness_threshold: 0.1
request_scheduler: org.apache.cassandra.scheduler.NoScheduler
เซิร์ฟเวอร์_การเข้ารหัส_ตัวเลือก:
internode_encryption: ไม่มี
ลูกค้า_การเข้ารหัส_ตัวเลือก:
เปิดใช้งาน: เท็จ
internode_compression: กระแสตรง
inter_dc_tcp_nodelay: เท็จ
Tracetype_query_ttl: 86400
Tracetype_repair_ttl: 604800
Enable_user_Defined_functions: เท็จ
Enable_scripted_user_Defined_functions: เท็จ
windows_timer_interval: 1
transparent_data_encryption_options:
เปิดใช้งาน: เท็จ
tombstone_warn_threshold: 1000
tombstone_failure_threshold: 100000
ชุด_ขนาด_คำเตือน_threshold_in_kb: 200
ชุด_ขนาด_ล้มเหลว_threshold_in_kb: 250
unlogged_batch_across_partitions_warn_threshold: 10
การบดอัด_large_partition_warning_threshold_mb: 100
gc_warn_threshold_in_ms: 1000
back_pressure_enabled: เท็จ
Enable_materialized_views: จริง
Enable_sasi_indexes: จริง

การตั้งค่า GC:

### การตั้งค่า CMS-XX:+UseParNewGC
-XX:+ใช้ConcMarkSweepGC
-XX:+CMSParallelRemarkEnabled
-XX:อัตราส่วนผู้รอดชีวิต=8
-XX:MaxTenuringThreshold=1
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSWaitDuration=10000
-XX:+CMSParallelInitialMarkEnabled
-XX:+CMSEdenChunksRecordAlways
-XX:+CMSClassUnloadingEnabled แล้ว

หน่วยความจำ jvm.options ได้รับการจัดสรร 16Gb (เราลองใช้ 32 Gb ด้วย แต่ก็ไม่พบความแตกต่าง)

ตารางถูกสร้างขึ้นด้วยคำสั่ง:

CREATE TABLE ks.t1 (id bigint PRIMARY KEY, title text) WITH compression = {'sstable_compression': 'LZ4Compressor', 'chunk_length_kb': 64};

เวอร์ชัน HB: 1.2.0-cdh5.14.2 (ในคลาส org.apache.hadoop.hbase.regionserver.HRegion เราไม่รวม MetricsRegion ซึ่งนำไปสู่ ​​GC เมื่อจำนวนภูมิภาคมากกว่า 1000 บน RegionServer)

พารามิเตอร์ HBase ที่ไม่ใช่ค่าเริ่มต้นผู้ดูแลสวนสัตว์.session.timeout: 120000
hbase.rpc.timeout: 2 นาที
hbase.client.scanner.timeout.ช่วงเวลา: 2 นาที
hbase.master.handler.count: 10
hbase.regionserver.lease.ช่วงเวลา, hbase.client.scanner.timeout.ช่วงเวลา: 2 นาที
hbase.regionserver.handler.count: 160
hbase.regionserver.metahandler.count: 30
hbase.regionserver.logroll.ระยะเวลา: 4 ชั่วโมง
hbase.regionserver.maxlogs: 200
hbase.hregion.memstore.flush.size: 1 GiB
hbase.hregion.memstore.block.multiplier: 6
hbase.hstore.compactionThreshold: 5
hbase.hstore.blockingStoreFiles: 200
hbase.hregion.majorcompacation: 1 วัน
ตัวอย่างการกำหนดค่าขั้นสูงของบริการ HBase (วาล์วนิรภัย) สำหรับ hbase-site.xml:
hbase.regionserver.wal.codecorg.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec
hbase.master.namespace.init.timeout3600000
hbase.regionserver.opticalcacheflushinterval18000000
hbase.regionserver.thread.compacion.large12
hbase.regionserver.wal.enablecompressiontrue
hbase.hstore.compacion.max.size1073741824
hbase.server.compactchecker.interval.multiplier200
ตัวเลือกการกำหนดค่า Java สำหรับ HBase RegionServer:
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:ReservedCodeCacheSize=256m
hbase.snapshot.master.timeoutMillis: 2 นาที
hbase.snapshot.region.timeout: 2 นาที
hbase.snapshot.master.timeout.millis: 2 นาที
ขนาดบันทึกสูงสุดของเซิร์ฟเวอร์ HBase REST: 100 MiB
การสำรองข้อมูลไฟล์บันทึกสูงสุดของเซิร์ฟเวอร์ HBase REST: 5
ขนาดบันทึกสูงสุดของเซิร์ฟเวอร์ HBase Thrift: 100 MiB
การสำรองข้อมูลไฟล์บันทึกสูงสุดของเซิร์ฟเวอร์ HBase Thrift: 5
ขนาดบันทึกสูงสุดหลัก: 100 MiB
การสำรองข้อมูลไฟล์บันทึกสูงสุดหลัก: 5
ขนาดบันทึกสูงสุดของเซิร์ฟเวอร์ภูมิภาค: 100 MiB
การสำรองข้อมูลไฟล์บันทึกสูงสุดของ RegionServer: 5
หน้าต่างการตรวจจับหลักที่ใช้งาน HBase: 4 นาที
dfs.client.hedged.read.threadpool.size: 40
dfs.client.hedged.read.threshold.millis: 10 มิลลิวินาที
hbase.rest.threads.min: 8
hbase.rest.threads.max: 150
ตัวอธิบายไฟล์กระบวนการสูงสุด: 180000
hbase.thrift.minWorkerThreads: 200
hbase.master.executor.openregion.threads: 30
hbase.master.executor.closeregion.threads: 30
hbase.master.executor.serverops.threads: 60
hbase.regionserver.thread.compacion.small: 6
hbase.ipc.server.read.threadpool.size: 20
หัวข้อผู้เสนอญัตติภูมิภาค: 6
ขนาดฮีป Java ของไคลเอ็นต์เป็นไบต์: 1 GiB
กลุ่มเริ่มต้นเซิร์ฟเวอร์ HBase REST: 3 GiB
กลุ่มเริ่มต้นเซิร์ฟเวอร์ HBase Thrift: 3 GiB
ขนาดฮีป Java ของ HBase Master ในหน่วยไบต์: 16 GiB
ขนาดฮีป Java ของ HBase RegionServer ในหน่วยไบต์: 32 GiB

+ผู้ดูแลสวนสัตว์
maxClientCnxns: 601
หมดเวลาเซสชันสูงสุด: 120000
การสร้างตาราง:
hbase org.apache.hadoop.hbase.util.RegionSplitter ns:t1 UniformSplit -c 64 -f cf
แก้ไข 'ns:t1', {NAME => 'cf', DATA_BLOCK_ENCODING => 'FAST_DIFF', การบีบอัด => 'GZ'}

มีจุดสำคัญจุดหนึ่งที่นี่ - คำอธิบาย DataStax ไม่ได้บอกว่ามีการใช้ขอบเขตจำนวนเท่าใดในการสร้างตาราง HB แม้ว่านี่จะเป็นสิ่งสำคัญสำหรับปริมาณมากก็ตาม ดังนั้นสำหรับการทดสอบจึงเลือกจำนวน = 64 ซึ่งช่วยให้สามารถจัดเก็บได้สูงสุด 640 GB เช่น โต๊ะขนาดกลาง

ในขณะที่ทำการทดสอบ HBase มี 22 ตารางและ 67 ภูมิภาค (ซึ่งอาจเป็นอันตรายถึงชีวิตสำหรับเวอร์ชัน 1.2.0 หากไม่ใช่สำหรับแพตช์ที่กล่าวถึงข้างต้น)

ตอนนี้สำหรับรหัส เนื่องจากไม่ชัดเจนว่าการกำหนดค่าแบบใดที่ได้เปรียบมากกว่าสำหรับฐานข้อมูลใดฐานข้อมูลหนึ่ง การทดสอบจึงดำเนินการในหลายรูปแบบ เหล่านั้น. ในการทดสอบบางอย่าง มีการโหลด 4 ตารางพร้อมกัน (ใช้ทั้ง 4 โหนดในการเชื่อมต่อ) ในการทดสอบอื่นๆ เราทำงานกับตารางที่แตกต่างกัน 8 ตาราง ในบางกรณี ขนาดแบทช์คือ 100 ส่วนขนาดอื่นๆ คือ 200 (พารามิเตอร์แบทช์ - ดูโค้ดด้านล่าง) ขนาดข้อมูลสำหรับค่าคือ 10 ไบต์หรือ 100 ไบต์ (dataSize) โดยรวมแล้ว มีการเขียนและอ่านบันทึก 5 ล้านรายการลงในแต่ละตารางในแต่ละครั้ง ในเวลาเดียวกัน มีการเขียน/อ่าน 5 เธรดในแต่ละตาราง (หมายเลขเธรด - thNum) ซึ่งแต่ละเธรดใช้ช่วงคีย์ของตัวเอง (จำนวน = 1 ล้าน):

if (opType.equals("insert")) {
    for (Long key = count * thNum; key < count * (thNum + 1); key += 0) {
        StringBuilder sb = new StringBuilder("BEGIN BATCH ");
        for (int i = 0; i < batch; i++) {
            String value = RandomStringUtils.random(dataSize, true, true);
            sb.append("INSERT INTO ")
                    .append(tableName)
                    .append("(id, title) ")
                    .append("VALUES (")
                    .append(key)
                    .append(", '")
                    .append(value)
                    .append("');");
            key++;
        }
        sb.append("APPLY BATCH;");
        final String query = sb.toString();
        session.execute(query);
    }
} else {
    for (Long key = count * thNum; key < count * (thNum + 1); key += 0) {
        StringBuilder sb = new StringBuilder("SELECT * FROM ").append(tableName).append(" WHERE id IN (");
        for (int i = 0; i < batch; i++) {
            sb = sb.append(key);
            if (i+1 < batch)
                sb.append(",");
            key++;
        }
        sb = sb.append(");");
        final String query = sb.toString();
        ResultSet rs = session.execute(query);
    }
}

ดังนั้นจึงมีฟังก์ชันที่คล้ายกันสำหรับ HB:

Configuration conf = getConf();
HTable table = new HTable(conf, keyspace + ":" + tableName);
table.setAutoFlush(false, false);
List<Get> lGet = new ArrayList<>();
List<Put> lPut = new ArrayList<>();
byte[] cf = Bytes.toBytes("cf");
byte[] qf = Bytes.toBytes("value");
if (opType.equals("insert")) {
    for (Long key = count * thNum; key < count * (thNum + 1); key += 0) {
        lPut.clear();
        for (int i = 0; i < batch; i++) {
            Put p = new Put(makeHbaseRowKey(key));
            String value = RandomStringUtils.random(dataSize, true, true);
            p.addColumn(cf, qf, value.getBytes());
            lPut.add(p);
            key++;
        }
        table.put(lPut);
        table.flushCommits();
    }
} else {
    for (Long key = count * thNum; key < count * (thNum + 1); key += 0) {
        lGet.clear();
        for (int i = 0; i < batch; i++) {
            Get g = new Get(makeHbaseRowKey(key));
            lGet.add(g);
            key++;
        }
        Result[] rs = table.get(lGet);
    }
}

เนื่องจากใน HB ไคลเอนต์จะต้องดูแลการกระจายข้อมูลอย่างสม่ำเสมอ ฟังก์ชันการเกลือคีย์จึงมีลักษณะดังนี้:

public static byte[] makeHbaseRowKey(long key) {
    byte[] nonSaltedRowKey = Bytes.toBytes(key);
    CRC32 crc32 = new CRC32();
    crc32.update(nonSaltedRowKey);
    long crc32Value = crc32.getValue();
    byte[] salt = Arrays.copyOfRange(Bytes.toBytes(crc32Value), 5, 7);
    return ArrayUtils.addAll(salt, nonSaltedRowKey);
}

ตอนนี้ส่วนที่น่าสนใจที่สุด - ผลลัพธ์:

การต่อสู้ของสองยาโกะสึนะ หรือคาสซานดราปะทะเอชเบส ประสบการณ์ของทีม Sberbank

สิ่งเดียวกันในรูปแบบกราฟ:

การต่อสู้ของสองยาโกะสึนะ หรือคาสซานดราปะทะเอชเบส ประสบการณ์ของทีม Sberbank

ข้อดีของ HB นั้นน่าประหลาดใจมากจนมีข้อสงสัยว่าการตั้งค่า CS มีปัญหาคอขวดบางประการ อย่างไรก็ตาม Google และการค้นหาพารามิเตอร์ที่ชัดเจนที่สุด (เช่น concurrent_writes หรือ memtable_heap_space_in_mb) ไม่ได้เร่งความเร็ว ในขณะเดียวกัน บันทึกก็สะอาดและไม่สาบานอะไรเลย

ข้อมูลมีการกระจายเท่าๆ กันทั่วทั้งโหนด สถิติจากโหนดทั้งหมดใกล้เคียงกัน

นี่คือลักษณะของสถิติตารางจากโหนดใดโหนดหนึ่งคีย์สเปซ: ks
จำนวนการอ่าน: 9383707
เวลาแฝงในการอ่าน: 0.04287025042448576 ms
จำนวนการเขียน: 15462012
เวลาแฝงในการเขียน: 0.1350068438699957 ms
รอดำเนินการฟลัช: 0
ตาราง: t1
SSTจำนวนตาราง: 16
พื้นที่ที่ใช้ (สด): 148.59 MiB
พื้นที่ใช้งาน(ทั้งหมด): 148.59 MiB
พื้นที่ที่ใช้โดยสแน็ปช็อต (ทั้งหมด): 0 ไบต์
หน่วยความจำนอกฮีปที่ใช้ (ทั้งหมด): 5.17 MiB
อัตราการบีบอัด SSTable: 0.5720989576459437
จำนวนพาร์ติชัน (ประมาณ): 3970323
จำนวนเซลล์ที่สามารถจดจำได้: 0
ขนาดข้อมูล Memtable: 0 ไบต์
หน่วยความจำฮีปแบบ Memtable off ที่ใช้: 0 ไบต์
จำนวนสวิตช์ Memtable: 5
จำนวนการอ่านในท้องถิ่น: 2346045
เวลาแฝงในการอ่านในเครื่อง: NaN ms
จำนวนการเขียนในท้องถิ่น: 3865503
เวลาแฝงในการเขียนในเครื่อง: NaN ms
รอดำเนินการฟลัช: 0
เปอร์เซ็นต์การซ่อมแซม: 0.0
บลูมกรองผลบวกลวง: 25
บลูมกรองอัตราส่วนเท็จ: 0.00000
พื้นที่กรอง Bloom ที่ใช้: 4.57 MiB
Bloom กรองหน่วยความจำฮีปที่ใช้: 4.57 MiB
สรุปดัชนีหน่วยความจำฮีปที่ใช้: 590.02 KiB
ข้อมูลเมตาการบีบอัดออกจากหน่วยความจำฮีปที่ใช้: 19.45 KiB
ไบต์ขั้นต่ำของพาร์ติชันที่บีบอัด: 36
ไบต์สูงสุดของพาร์ติชันที่บีบอัด: 42
พาร์ติชันที่บีบอัดมีค่าเฉลี่ยไบต์: 42
เซลล์ที่มีชีวิตเฉลี่ยต่อชิ้น (ห้านาทีที่ผ่านมา): NaN
เซลล์ที่มีชีวิตสูงสุดต่อชิ้น (ห้านาทีสุดท้าย): 0
หลุมฝังศพเฉลี่ยต่อชิ้น (ห้านาทีที่ผ่านมา): NaN
จำนวนหลุมฝังศพสูงสุดต่อชิ้น (ห้านาทีสุดท้าย): 0
การกลายพันธุ์ที่ลดลง: 0 ไบต์

ความพยายามที่จะลดขนาดของแบทช์ (แม้จะส่งแยกกันก็ตาม) ไม่มีผลใดๆ มีแต่แย่ลงเท่านั้น เป็นไปได้ว่าในความเป็นจริงนี่คือประสิทธิภาพสูงสุดสำหรับ CS เนื่องจากผลลัพธ์ที่ได้รับสำหรับ CS นั้นคล้ายคลึงกับผลลัพธ์ที่ได้รับสำหรับ DataStax - ประมาณหลายแสนการดำเนินการต่อวินาที นอกจากนี้ หากเราดูที่การใช้ทรัพยากร เราจะเห็นว่า CS ใช้ CPU และดิสก์มากกว่ามาก:

การต่อสู้ของสองยาโกะสึนะ หรือคาสซานดราปะทะเอชเบส ประสบการณ์ของทีม Sberbank
รูปนี้แสดงการใช้งานระหว่างการทดสอบทั้งหมดติดต่อกันสำหรับฐานข้อมูลทั้งสอง

เกี่ยวกับข้อได้เปรียบในการอ่านอันทรงพลังของ HB คุณจะเห็นได้ว่าสำหรับทั้งสองฐานข้อมูล การใช้งานดิสก์ในระหว่างการอ่านนั้นต่ำมาก (การทดสอบการอ่านเป็นส่วนสุดท้ายของรอบการทดสอบสำหรับแต่ละฐานข้อมูล เช่น สำหรับ CS คือเวลา 15:20 ถึง 15:40 น.) ในกรณีของ HB เหตุผลก็ชัดเจน - ข้อมูลส่วนใหญ่ค้างอยู่ในหน่วยความจำ ใน memstore และบางส่วนถูกแคชไว้ในบล็อคแคช สำหรับ CS นั้นยังไม่ชัดเจนว่ามันทำงานอย่างไร แต่การรีไซเคิลดิสก์ก็ไม่สามารถมองเห็นได้ แต่ในกรณีที่มีการพยายามเปิดใช้งานแคช row_cache_size_in_mb = 2048 และตั้งค่าแคช = {'keys': 'ALL', 'rows_per_partition': ' 2000000'} แต่นั่นทำให้แย่ลงไปอีกเล็กน้อย

นอกจากนี้ยังควรกล่าวถึงประเด็นสำคัญเกี่ยวกับจำนวนภูมิภาคใน HB อีกครั้ง ในกรณีของเราระบุค่าเป็น 64 หากคุณลดและทำให้มันเท่ากับเช่น 4 ความเร็วจะลดลง 2 เท่าเมื่ออ่าน เหตุผลก็คือ memstore จะเต็มเร็วขึ้นและไฟล์จะถูกล้างบ่อยขึ้น และเมื่ออ่าน จะต้องประมวลผลไฟล์มากขึ้น ซึ่งเป็นการดำเนินการที่ค่อนข้างซับซ้อนสำหรับ HB ในสภาวะจริง สิ่งนี้สามารถรักษาได้ด้วยการคิดผ่านกลยุทธ์การแยกส่วนล่วงหน้าและการกระชับ โดยเฉพาะอย่างยิ่ง เราใช้ยูทิลิตี้ที่เขียนขึ้นเองซึ่งรวบรวมขยะและบีบอัด HFiles อย่างต่อเนื่องในเบื้องหลัง ค่อนข้างเป็นไปได้ที่สำหรับการทดสอบ DataStax พวกเขาจัดสรรเพียง 1 ภูมิภาคต่อตาราง (ซึ่งไม่ถูกต้อง) และนี่จะค่อนข้างชัดเจนว่าทำไม HB จึงด้อยกว่าในการทดสอบการอ่าน

ข้อสรุปเบื้องต้นต่อไปนี้ได้มาจากสิ่งนี้ สมมติว่าไม่มีข้อผิดพลาดใหญ่ๆ เกิดขึ้นระหว่างการทดสอบ แคสแซนดราก็ดูเหมือนยักษ์ใหญ่ที่มีเท้าเป็นดินเหนียว แม่นยำยิ่งขึ้นในขณะที่เธอทรงตัวด้วยขาข้างเดียวดังที่แสดงในภาพตอนต้นของบทความเธอแสดงผลลัพธ์ที่ค่อนข้างดี แต่ในการต่อสู้ภายใต้เงื่อนไขเดียวกันเธอก็พ่ายแพ้ทันที ในเวลาเดียวกัน เมื่อคำนึงถึงการใช้งาน CPU ที่ต่ำบนฮาร์ดแวร์ของเรา เราจึงเรียนรู้ที่จะติดตั้ง RegionServer HB สองตัวต่อโฮสต์ และด้วยเหตุนี้จึงเพิ่มประสิทธิภาพเป็นสองเท่า เหล่านั้น. เมื่อคำนึงถึงการใช้ทรัพยากรแล้ว สถานการณ์ของ CS ก็ยิ่งน่าเสียดายมากยิ่งขึ้น

แน่นอนว่าการทดสอบเหล่านี้ค่อนข้างเป็นการสังเคราะห์และปริมาณข้อมูลที่ใช้ในที่นี้ค่อนข้างน้อย เป็นไปได้ว่าหากเราเปลี่ยนไปใช้เทราไบต์ สถานการณ์จะแตกต่างออกไป แต่สำหรับ HB เราสามารถโหลดเทราไบต์ได้ แต่สำหรับ CS สิ่งนี้กลายเป็นปัญหา บ่อยครั้งที่ส่ง OperationTimedOutException แม้จะมีวอลุ่มเหล่านี้ แม้ว่าพารามิเตอร์สำหรับการรอการตอบสนองจะเพิ่มขึ้นหลายครั้งแล้วเมื่อเทียบกับพารามิเตอร์เริ่มต้นก็ตาม

ฉันหวังว่าด้วยความพยายามร่วมกัน เราจะพบปัญหาคอขวดของ CS และหากเราสามารถเร่งความเร็วได้ ฉันจะเพิ่มข้อมูลเกี่ยวกับผลลัพธ์สุดท้ายในตอนท้ายของโพสต์อย่างแน่นอน

UPD: ด้วยคำแนะนำของสหาย ฉันจึงสามารถเร่งความเร็วในการอ่านได้ เคยเป็น:
159 การดำเนินการ (644 ตาราง 4 สตรีม ชุด 5)
โพสต์:
.withLoadBalancingPolicy (TokenAwarePolicy ใหม่ (DCAwareRoundRobinPolicy.builder().build()))
และฉันก็เล่นกับจำนวนเธรด ผลลัพธ์จะเป็นดังนี้:
4 ตาราง 100 เธรด ชุด = 1 (ชิ้นต่อชิ้น): 301 ops
4 ตาราง 100 เธรด ชุด = 10: 447 ops
4 ตาราง 100 เธรด ชุด = 100: 625 ops

หลังจากนั้นฉันจะใช้เคล็ดลับการปรับแต่งอื่นๆ ทำการทดสอบแบบสมบูรณ์ และเพิ่มผลลัพธ์ที่ส่วนท้ายของโพสต์

ที่มา: will.com

เพิ่มความคิดเห็น