Penyimpanan Nilai Kunci dengan Peta Kronik

1. Ikhtisar

Dalam tutorial ini, kita akan melihat bagaimana kita dapat menggunakan Peta Chronicle untuk menyimpan pasangan nilai-kunci. Kami juga akan membuat contoh singkat untuk menunjukkan perilaku dan penggunaannya.

2. Apa Itu Peta Kronik?

Mengikuti dokumentasi, "Chronicle Map adalah penyimpanan nilai kunci yang super cepat, dalam memori, non-pemblokiran, dirancang untuk latensi rendah, dan / atau aplikasi multi-proses".

Singkatnya, ini adalah penyimpanan nilai kunci di luar timbunan. Peta tidak membutuhkan RAM dalam jumlah besar agar dapat berfungsi dengan baik. Ini dapat berkembang berdasarkan kapasitas disk yang tersedia . Selain itu, ini mendukung replikasi data dalam pengaturan server multi-master.

Sekarang mari kita lihat bagaimana kita dapat mengatur dan bekerja dengannya.

3. Ketergantungan Maven

Untuk memulai, kita perlu menambahkan dependensi chronicle-map ke proyek kita:

 net.openhft chronicle-map 3.17.2 

4. Jenis Peta Kronik

Kita dapat membuat peta dengan dua cara: baik sebagai peta dalam memori atau sebagai peta tetap.

Mari kita lihat keduanya secara detail.

4.1. Peta Dalam Memori

Peta Chronicle dalam memori adalah penyimpanan peta yang dibuat di dalam memori fisik server. Ini berarti itu hanya dapat diakses dalam proses JVM di mana penyimpanan peta dibuat .

Mari kita lihat contoh singkatnya:

ChronicleMap inMemoryCountryMap = ChronicleMap .of(LongValue.class, CharSequence.class) .name("country-map") .entries(50) .averageValue("America") .create();

Demi kesederhanaan, kami membuat peta yang menyimpan 50 ID negara dan namanya. Seperti yang bisa kita lihat di cuplikan kode, pembuatannya cukup mudah kecuali untuk konfigurasi averageValue () . Ini memberitahu peta untuk mengonfigurasi jumlah rata-rata byte yang diambil oleh nilai entri peta.

Dengan kata lain, saat membuat peta, Peta Kronik menentukan jumlah rata-rata byte yang diambil oleh bentuk nilai berseri. Ini dilakukan dengan membuat serialisasi nilai rata-rata menggunakan marshaller nilai yang dikonfigurasi. Ini kemudian akan mengalokasikan jumlah byte yang ditentukan untuk nilai setiap entri peta.

Satu hal yang harus kita perhatikan ketika datang ke peta dalam memori adalah bahwa data hanya dapat diakses ketika proses JVM hidup. Perpustakaan akan menghapus data saat proses berakhir.

4.2. Peta Tetap

Tidak seperti peta dalam memori, penerapannya akan menyimpan peta yang ada ke disk . Sekarang mari kita lihat bagaimana kita dapat membuat peta yang bertahan:

ChronicleMap persistedCountryMap = ChronicleMap .of(LongValue.class, CharSequence.class) .name("country-map") .entries(50) .averageValue("America") .createPersistedTo(new File(System.getProperty("user.home") + "/country-details.dat"));

Ini akan membuat file bernama country-details.dat di folder yang ditentukan. Jika file ini sudah tersedia di jalur yang ditentukan, implementasi builder akan membuka tautan ke penyimpanan data yang ada dari proses JVM ini.

Kita dapat menggunakan peta yang ada jika kita menginginkannya:

  • bertahan melampaui proses pencipta; misalnya, untuk mendukung penerapan ulang aplikasi panas
  • jadikan global di server; misalnya, untuk mendukung beberapa akses proses bersamaan
  • bertindak sebagai penyimpan data yang akan kita simpan ke disk

5. Konfigurasi Ukuran

Ini wajib untuk mengonfigurasi nilai rata-rata dan kunci rata-rata saat membuat Peta Chronicle, kecuali dalam kasus di mana jenis kunci / nilai kita adalah kotak primitif atau antarmuka nilai. Dalam contoh kami, kami tidak mengonfigurasi kunci rata-rata karena jenis kunci LongValue adalah antarmuka nilai.

Sekarang, mari kita lihat apa pilihannya untuk mengonfigurasi jumlah rata-rata byte kunci / nilai:

  • averageValue () - Nilai dari mana jumlah rata-rata byte akan dialokasikan untuk nilai entri peta ditentukan
  • averageValueSize () - Jumlah rata-rata byte yang akan dialokasikan untuk nilai entri peta
  • constantValueSizeBySample () - Jumlah byte yang akan dialokasikan untuk nilai entri peta ketika ukuran nilainya selalu sama
  • averageKey () - Kunci dari mana jumlah rata-rata byte yang akan dialokasikan untuk kunci entri peta ditentukan
  • averageKeySize () - Jumlah rata-rata byte yang akan dialokasikan untuk kunci entri peta
  • constantKeySizeBySample () - Jumlah byte yang akan dialokasikan untuk kunci entri peta ketika ukuran kunci selalu sama

6. Jenis Kunci dan Nilai

Ada standar tertentu yang perlu kita ikuti saat membuat Peta Chronicle, terutama saat menentukan kunci dan nilai. Peta bekerja paling baik saat kita membuat kunci dan nilai menggunakan tipe yang direkomendasikan.

Berikut beberapa jenis yang direkomendasikan:

  • Antarmuka nilai
  • Semua kelas yang mengimplementasikan antarmuka Byteable dari Chronicle Bytes
  • Semua kelas yang mengimplementasikan antarmuka BytesMarshallable dari Chronicle Bytes; kelas implementasi harus memiliki konstruktor no-arg publik
  • byte [] dan ByteBuffer
  • CharSequence , String , dan StringBuilder
  • Integer , Long , dan Double
  • Semua kelas yang mengimplementasikan java.io.Externalizable ; kelas implementasi harus memiliki konstruktor no-arg publik
  • Semua tipe yang mengimplementasikan java.io.Serializable , termasuk tipe primitif berkotak (kecuali yang tercantum di atas) dan tipe array
  • Jenis lainnya, jika serializer khusus disediakan

7. Menanyakan Peta Kronik

Chronicle Map mendukung kueri satu tombol serta kueri multi-kunci.

7.1. Single-Key Queries

Single-key queries are the operations that deal with a single key. ChronicleMap supports all the operations from the Java Map interface and ConcurrentMap interface:

LongValue qatarKey = Values.newHeapInstance(LongValue.class); qatarKey.setValue(1); inMemoryCountryMap.put(qatarKey, "Qatar"); //... CharSequence country = inMemoryCountryMap.get(key);

In addition to the normal get and put operations, ChronicleMap adds a special operation, getUsing(), that reduces the memory footprint while retrieving and processing an entry. Let's see this in action:

LongValue key = Values.newHeapInstance(LongValue.class); StringBuilder country = new StringBuilder(); key.setValue(1); persistedCountryMap.getUsing(key, country); assertThat(country.toString(), is(equalTo("Romania"))); key.setValue(2); persistedCountryMap.getUsing(key, country); assertThat(country.toString(), is(equalTo("India")));

Here we've used the same StringBuilder object for retrieving values of different keys by passing it to the getUsing() method. It basically reuses the same object for retrieving different entries. In our case, the getUsing() method is equivalent to:

country.setLength(0); country.append(persistedCountryMap.get(key));

7.2. Multi-Key Queries

There may be use cases where we need to deal with multiple keys at the same time. For this, we can use the queryContext() functionality. The queryContext() method will create a context for working with a map entry.

Let's first create a multimap and add some values to it:

Set averageValue = IntStream.of(1, 2).boxed().collect(Collectors.toSet()); ChronicleMap
    
      multiMap = ChronicleMap .of(Integer.class, (Class
     
      ) (Class) Set.class) .name("multi-map") .entries(50) .averageValue(averageValue) .create(); Set set1 = new HashSet(); set1.add(1); set1.add(2); multiMap.put(1, set1); Set set2 = new HashSet(); set2.add(3); multiMap.put(2, set2);
     
    

To work with multiple entries, we have to lock those entries to prevent inconsistency that may occur due to a concurrent update:

try (ExternalMapQueryContext
    
      fistContext = multiMap.queryContext(1)) { try (ExternalMapQueryContext
     
       secondContext = multiMap.queryContext(2)) { fistContext.updateLock().lock(); secondContext.updateLock().lock(); MapEntry
      
        firstEntry = fistContext.entry(); Set firstSet = firstEntry.value().get(); firstSet.remove(2); MapEntry
       
         secondEntry = secondContext.entry(); Set secondSet = secondEntry.value().get(); secondSet.add(4); firstEntry.doReplaceValue(fistContext.wrapValueAsData(firstSet)); secondEntry.doReplaceValue(secondContext.wrapValueAsData(secondSet)); } } finally { assertThat(multiMap.get(1).size(), is(equalTo(1))); assertThat(multiMap.get(2).size(), is(equalTo(2))); }
       
      
     
    

8. Closing the Chronicle Map

Sekarang setelah kita selesai mengerjakan peta kita, mari panggil metode close () pada objek peta kita untuk melepaskan memori off-heap dan sumber daya yang terkait dengannya:

persistedCountryMap.close(); inMemoryCountryMap.close(); multiMap.close();

Satu hal yang perlu diingat di sini adalah bahwa semua operasi peta harus diselesaikan sebelum menutup peta. Jika tidak, JVM mungkin macet secara tidak terduga.

9. Kesimpulan

Dalam tutorial ini, kita telah mempelajari cara menggunakan Peta Chronicle untuk menyimpan dan mengambil pasangan nilai kunci. Meskipun versi komunitas tersedia dengan sebagian besar fungsi inti, versi komersial memiliki beberapa fitur lanjutan seperti replikasi data di beberapa server dan panggilan jarak jauh.

Semua contoh yang telah kita diskusikan di sini dapat ditemukan di proyek Github.