Yazar | LLLSQ
Baş Editör | Guo Rui
İnternet yazılımının hızlı gelişimi, kullanıcı deneyimi bir yazılımın kalitesini değerlendirmek için önemli bir nedendir, bu nedenle önbellek vazgeçilmez bir yapaydır. Çok iş parçacıklı yüksek eşzamanlılık senaryolarında önbellekler genellikle birbirlerinden ayrılamaz.Redis ve memcached gibi dağıtılmış önbellekler ve ehcache, GuavaCache gibi yerel (işlem içi) önbellekler gibi farklı uygulama senaryolarına göre farklı önbelleklerin seçilmesi gerekir. Kafein.
Guava Cache demişken, birçok kişi buna aşinadır. Google Guava araç setinde çok kullanışlı ve kullanımı kolay yerelleştirilmiş bir önbellek uygulamasıdır. LRU algoritmasına dayalı olarak uygulanır ve çoklu önbellek sona erme stratejilerini destekler. Guava'nın yaygın kullanımı nedeniyle, Guava Önbelleği de yaygın olarak kullanılmaktadır. Ancak, Guava Önbelleğinin performansı ille de en iyisi mi? Belki bir kez performansı çok iyidir. Ancak Yangtze Nehri denilen dalgaların dalgaları ileri doğru itmesinden sonra, her zaman daha iyi teknolojiler olacaktır. Bugün, Guava Cache: Caffeine'den daha yüksek performansa sahip bir önbellekleme çerçevesi tanıtacağım.
Resmi performans karşılaştırması
Google Guava araç setinde, LRU algoritmasına dayanan çok kullanışlı ve kullanımı kolay yerelleştirilmiş önbellek uygulaması, birden çok önbellek süre sonu stratejisini destekler.
EhCache, hızlı ve yetenekli olan saf bir Java işlem içi önbellekleme çerçevesidir ve Hazırda Bekletme'de varsayılan CacheProvider'dır.
Caffeine, Spring Boot 2.0'da değiştirilecek olan Java8 kullanılarak Guava önbelleğinin yeniden yazılmış bir sürümüdür.LRU algoritmasına dayalı olarak uygulanır ve çoklu önbellek sona erme stratejilerini destekler.
Kafeinin diğer önbelleklerden önemli ölçüde daha verimli olduğu açıkça görülebilir.
nasıl kullanılır?
1 genel statik boşluk ana (String args) { 2 LoadingCache < Dize, Dize > build = CacheBuilder.newBuilder (). initialCapacity (1) .maximumSize (100) .expireAfterWrite (1, TimeUnit.DAYS) 3. .build (yeni CacheLoader < Dize, Dize > () { 4 // Varsayılan veri yükleme uygulaması, değeri almak için get çağrılırken, anahtarın karşılık gelen bir değeri yoksa, yüklemek için bu yöntemi çağırın 5 @Override 6 public String yükü (String key) { 7 dönüş ""; 8} 9}); 10} 11}Parametre yöntemi:
Son kullanma stratejisi
Kafeinde iki tür önbellek vardır, biri sınırlı önbellek ve diğeri sınırsız önbellektir Sınırsız önbelleğin süresinin dolmasına gerek yoktur ve sınırları yoktur.
Sınırlı önbellekte üç süre sonu API'si sağlanır:
Stratejiyi güncelle
Güncelleme stratejisi nedir? Önbellek, ayarlanan sürenin ardından otomatik olarak yenilenir.
Kafein, yazdıktan sonra stratejiyi güncellememize izin veren yenilemeAfterWrite () yöntemini sağlar:
1 Yükleme Önbelleği < Dize, Dize > build = CacheBuilder.newBuilder (). renewAfterWrite (1, TimeUnit.DAYS) 2.build (yeni CacheLoader < Dize, Dize > () { 3 @Override 4 public String load (String key) { 5 dönüş ""; 6} 7}); 8}Yukarıdaki kodda, yenilemek için bir CacheLodaer oluşturmamız gerekiyor, burada senkron olarak yapılır ve buildAsync yöntemi ile zaman uyumsuz olarak oluşturulabilir. Gerçek işte, veri kaynağını yenilemek için kodumuzdaki eşleyiciyi geçirebiliriz.
Ancak gerçek kullanımda, yenilenmesi için bir gün ayarlarsınız, ancak bir gün sonra önbelleğin yenilenmediğini görürsünüz. Bunun nedeni, önbelleğin ancak tekrar erişildikten 1 gün sonra yenilenebilmesidir, eğer kimse erişmezse, asla yenilenmeyecektir.
Otomatik yenilemenin nasıl yapıldığına bir göz atalım. Otomatik yenileme, yalnızca afterRead () yöntemimiz olan okuma işleminden sonra mevcuttur.Bunlardan biri, eşzamanlı veya eşzamansız olmanıza göre yenilenecek olan renewIfNeeded'dir.
Doldurma stratejisi (Nüfus)
Kafein bize üç doldurma stratejisi sağlar: manuel, senkronize ve asenkron.
Manuel yükleme (Manuel)
1 Önbellek < Dize, Nesne > manualCache = Kafein.newBuilder () 2.expireAfterWrite (10, TimeUnit.MINUTES) 3. maksimumBoyut (10_000) 4.. Yapı (); 56String key = "name1"; 7 // NULL döndürmezse, anahtara göre bir önbellek sorgulayın 8graph = manualCache.getIfPresent (anahtar); 9 // createExpensiveGraph yöntemi çağrılmamışsa, Anahtarı temel alan bir önbellek sorgulayın ve dönüş değerini önbelleğe kaydedin. 10 // Eğer yöntem Null döndürürse, manualCache.get null döndürür, eğer yöntem bir istisna atarsa, manualCache.get bir istisna atar 11graph = manualCache.get (anahtar, k- > createExpensiveGraph (k)); 12 // Önbelleğe bir değer koy, daha önce bir değer varsa, önceki değerin üzerine yaz 13manualCache.put (anahtar, grafik); 14 // Bir önbelleği silin 15manualCache.invalidate (anahtar); 1617 Eşzamanlı Harita < Dize, Nesne > map = manualCache.asMap (); 18cache.invalidate (anahtar);Önbellek arayüzü, önbellek alma, güncelleme ve silme işlemlerinin açık bir şekilde kontrol edilmesini sağlar. Bir anahtarın değerini cache.getIfPresent (key) yöntemi ile alabiliriz ve CNC'yi cache.put (key, value) yöntemi ile önbelleğe koyabiliriz, ancak bu orijinal anahtarın verilerinin üzerine yazacaktır. Cache.get (key, k- > değer), get yöntemi parametre olarak parametre olarak bir anahtarla bir Function (createExpensiveGraph) iletir.
Anahtar önbellekte yoksa, bu Function işlevini çağırın ve dönüş değerini önbelleğin değeri olarak önbelleğe ekleyin. Get yöntemi çağrıyı engelleyici bir şekilde yürütür.Çok sayıda iş parçacığı değeri aynı anda talep etse bile, Function yöntemi yalnızca bir kez çağrılacaktır. Bu, diğer iş parçacıklarıyla yazma rekabetini önleyebilir, bu nedenle get kullanımı getIfPresent'ten daha iyidir.
Not: Bu yöntemi çağırmak NULL döndürürse (yukarıdaki createExpensiveGraph yöntemi gibi), cache.get null döndürür. Bu yöntemi çağırmak bir istisna atarsa, get yöntemi de bir istisna atar.
ConcurrentMap'i almak ve önbellekte bazı değişiklikler yapmak için Cache.asMap () yöntemini kullanabilirsiniz.
Eşzamanlı yükleme (Yükleme)
1Yükleniyor Önbellek < Dize, Nesne > loadingCache = Kafein.newBuilder () 2. maksimumBoyut (10_000) 3.expireAfterWrite (10, TimeUnit.MINUTES) 4. yapı (anahtar- > createExpensiveGraph (anahtar)); 56String key = "name1"; 7 // Eşzamanlı bir şekilde bir önbellek elde etmekle aynı prensip ve yukarıdaki manuel yolla. Önbellek oluştururken bir createExpensiveGraph işlevi sağlanacaktır. 8 // Eksik olması durumunda bir önbellek oluşturmak için senkronizasyonu sorgulayın ve kullanın 9Nesne grafiği = loadingCache.get (anahtar); 1011 // Grup anahtarının değerini al ve bir Harita döndür 12Liste < Dize > anahtarlar = new ArrayList < > (); 13keys.add (anahtar); 14Harita < Dize, Nesne > graphs = loadingCache.getAll (anahtarlar);LoadingCache, CacheLoader kullanılarak oluşturulan önbelleğin değeridir. Toplu arama için getAll yöntemini kullanabilirsiniz. Varsayılan olarak getAll, önbelleğe alınan değeri oluşturmak için önbellekte değeri olmayan anahtarlar üzerinde CacheLoader.load yöntemini çağırır. GetAll verimliliğini artırmak için CacheLoader.loadAll yöntemini geçersiz kılabiliriz.
Not: Özel olarak istenen anahtarın değerlerini yüklemek için bir CacheLoader.loadAll yazabilirsiniz. Örneğin, belirli bir gruptaki herhangi bir anahtarın değerini hesaplamak, o gruptaki tüm anahtarlar için değerler sağlayacaksa, loadAll, grubun geri kalanını aynı anda yükleyebilir.
Eşzamansız Yükleniyor
1AsyncLoadingCache < Dize, Nesne > asyncLoadingCache = Caffeine.newBuilder () 2. maksimumBoyut (10_000) 3.expireAfterWrite (10, TimeUnit.MINUTES) 4 // İkisi de: Eşzamansız olarak sarmalanmış eşzamanlı bir hesaplamayla derleyin 5 .buildAsync (anahtar- > createExpensiveGraph (anahtar)); 6 // Veya: Geleceği döndüren eşzamansız bir hesaplamayla derleyin 7 // .buildAsync ((anahtar, yürütücü) - > createExpensiveGraphAsync (anahtar, yürütücü)); 89 Dize anahtarı = "ad1"; 1011 // Eksik olması durumunda önbelleği oluşturmak için eşzamansız yöntemleri sorgulayın ve kullanın 12Tamamlanabilir Gelecek < Nesne > graph = asyncLoadingCache.get (anahtar); 13 // Bir dizi önbelleği sorgulayın ve eksik olması durumunda önbelleği oluşturmak için zaman uyumsuz yöntemler kullanın 14Liste < Dize > anahtarlar = new ArrayList < > (); 15keys.add (anahtar); 16Tamamlanabilir Gelecek < Harita < Dize, Nesne > > graphs = asyncLoadingCache.getAll (anahtarlar); 17 // Eşzamansızdan eşzamanlıya 18loadingCache = asyncLoadingCache.synchronous ();AsyncLoadingCache, LoadingCache sınıfından miras alınır. Zaman uyumsuz yükleme, yöntemleri çağırmak ve CompletableFuture döndürmek için Executor'u kullanır. Eşzamansız yükleme önbelleği, reaktif bir programlama modeli kullanır.
Eşzamanlı olarak aramak istiyorsanız, CacheLoader sağlamalısınız. Eşzamansız olarak ifade etmek için bir AsyncCacheLoader sağlanmalı ve bir CompletableFuture döndürülmelidir.
Senkron () yöntemi bir LoadingCacheView görünümü döndürür ve LoadingCacheView ayrıca LoadingCache'den devralır. Bu yöntemin çağrılması, zaman uyumsuz olarak yüklenen bir önbelleği AsyncLoadingCache'yi zaman uyumlu olarak yüklenmiş bir önbellek LoadingCache'ye dönüştürmeye eşdeğerdir.
Varsayılan olarak, ForkJoinPool.commonPool () eşzamansız evreleri çalıştırmak için kullanılır, ancak iş parçacığı havuzunu değiştirmek için Caffeine.executor (Executor) yöntemini kullanabiliriz.
Tahliye stratejisi (tahliye)
Kafein üç tür tahliye stratejisi sağlar: boyuta dayalı, zamana dayalı ve referansa dayalı.
Beden bazlı
Boyut tahliyesine bağlı olarak iki yol vardır: biri önbellek boyutuna, diğeri ağırlığa bağlıdır.
1 // Önbellekteki giriş sayısına göre tahliye edin 2 // Önbellek sayısına göre tahliye 3Yükleniyor Önbellek < Anahtar, Grafik > grafikler = Kafein.newBuilder () 4. maksimumBoyut (10_000) 5. yapı (anahtar- > createExpensiveGraph (anahtar)); 67 // Önbellekteki köşe sayısına göre tahliye edin 8 // Tahliye, önbelleğin ağırlığına bağlıdır (ağırlık, önbelleğin çıkarılıp çıkarılmadığını belirlemek için değil, yalnızca önbelleğin boyutunu belirlemek için kullanılır) 9Yükleniyor Önbellek < Anahtar, Grafik > grafikler = Kafein.newBuilder () 10. maksimumAğırlık (10_000) 11. tartı ((Anahtar anahtar, Grafik grafiği) - > graph.vertices (). size ()) 12. yapı (anahtar- > createExpensiveGraph (anahtar));Önbelleğin maksimum boyutunu belirtmek için Caffeine.maximumSize (long) yöntemini kullanabiliriz. Önbellek bu kapasiteyi aştığında, önbelleği silmek için Window TinyLfu stratejisi kullanılacaktır. Ayrıca boşaltmak için ağırlık stratejisini kullanabiliriz, ağırlığı belirlemek için Caffeine.weigher (Tartı) işlevini ve önbelleğin maksimum ağırlığını belirtmek için Caffeine.maximumWeight (uzun) işlevini kullanabiliriz.
Not: MaximumWeight ve maximumSize aynı anda kullanılamaz.
Zamana dayalı
1 // Sabit bir sona erme politikasına göre tahliye edin 2 // Sabit bir sona erme stratejisine dayalı çıkış 3Yükleniyor Önbellek < Anahtar, Grafik > grafikler = Kafein.newBuilder () 4.expireAfterAccess (5, TimeUnit.MINUTES) 5. yapı (anahtar- > createExpensiveGraph (anahtar)); 6Yükleniyor Önbellek < Anahtar, Grafik > grafikler = Kafein.newBuilder () 7.expireAfterWrite (10, TimeUnit.MINUTES) 8. yapı (anahtar- > createExpensiveGraph (anahtar)); 910 // Değişen bir sona erme politikasına göre tahliye edin 11 // Farklı sona erme stratejilerine göre çıkış 12Yükleniyor Önbellek < Anahtar, Grafik > grafikler = Kafein.newBuilder () 13. expireAfter (yeni Geçerlilik < Anahtar, Grafik > () { 14 @Override 15 genel uzun süreli expireAfterCreate (Anahtar anahtarı, Grafik grafiği, uzun currentTime) { 16 // Harici bir kaynaktan geliyorsa, nanotime yerine duvar saati zamanını kullan 17 uzun saniye = graph.creationDate (). PlusHours (5) 18 .minus (System.currentTimeMillis (), MILLIS) 19. toEpochSecond (); 20 dönüş TimeUnit.SECONDS.toNanos (saniye); yirmi bir } yirmi iki 23 @Override 24 halka açık uzun süreli sona ermeAfterUpdate (Anahtar anahtar, Grafik grafik, 25 uzun currentTime, long currentDuration) { 26 dönüş güncelSüresi; 27} 2829 @Override 30 halka açık uzun süre sona erdiAfterRead (Anahtar anahtar, Grafik grafik, 31 uzun currentTime, long currentDuration) { 32 dönüş güncel süresi; 33} 34}) 35. Yapı (anahtar- > createExpensiveGraph (anahtar));Referans tabanlı
Yukarıdan aşağıya Java 4 referanslarının seviyesi: güçlü referanslar > Yumuşak referans > Zayıf referans > Hayali referans.
1 // Ne anahtara ne de değere güçlü bir şekilde ulaşılamadığında tahliye edin 2 // Ne anahtara ne de değere başvurulmadığında önbelleği çıkarın 3Yükleniyor Önbellek < Anahtar, Grafik > grafikler = Kafein.newBuilder () 4. .weakKeys () 5 .weakValues () 6. yapı (anahtar- > createExpensiveGraph (anahtar)); 78 // Çöp toplayıcının belleği boşaltması gerektiğinde tahliye edin 9 // Çöp toplayıcının belleği boşaltması gerektiğinde çıkarılır 10Yükleniyor Önbellek < Anahtar, Grafik > grafikler = Kafein.newBuilder () 11. softValues () 12. yapı (anahtar- > createExpensiveGraph (anahtar));Önbellek tahliyesini çöp toplayıcıya göre yapılandırabiliriz. Bu amaçla, anahtar ve değeri zayıf referanslar olarak veya yalnızca değerleri yumuşak referanslar olarak yapılandırabiliriz.
Not: AsyncLoadingCache, zayıf referansları ve yazılım referanslarını desteklemez.
Dinleyiciyi kaldırın (Kaldırma)
Önbelleği manuel olarak silin:
Herhangi bir zamanda, önbelleğin çıkarılmasını beklemeden önbelleği açıkça geçersiz kılmak mümkündür.
1 // bireysel anahtar 2cache.invalidate (anahtar) 3 // toplu anahtarlar 4cache.invalidateAll (anahtarlar) 5 // tüm anahtarlar 6cache.invalidateAll ()Kaldırma işleyici:
Caffeine.removalListener (RemovalListener), verileri silerken belirli işlemleri gerçekleştirmek üzere önbellek için bir silme dinleyicisi belirtmek için kullanılabilir. RemovalListener anahtarı, değeri ve RemovalCause'u (silme nedeni) alabilir.
Silme dinleyicisinin içindeki işlem Executor kullanılarak eşzamansız olarak gerçekleştirilir. Varsayılan yürütücü, Caffeine.executor (Executor) tarafından geçersiz kılınabilir ForkJoinPool.commonPool () 'dur. İşlemin silme ile eşzamanlı olarak gerçekleştirilmesi gerektiğinde, lütfen bunun yerine CacheWrite kullanın.Aşağıda CacheWrite açıklanacaktır.
Not: RemovalListener tarafından atılan herhangi bir istisna günlüğe kaydedilecek (Logger kullanılarak) ve atılmayacaktır.
İstatistikler (İstatistikler)
Önbellek < Anahtar, Grafik > grafikler = Kafein.newBuilder () 2. maksimumBoyut (10_000) 3. .recordStats () 4.. Yapı ();İstatistik toplamayı açmak için Caffeine.recordStats () kullanın. Cache.stats () yöntemi, aşağıdakiler gibi istatistiksel bilgiler sağlayan CacheStats döndürür:
sonuç olarak
Kafein ayarlaması sadece algoritmanın ayarlanması değil, aynı zamanda hafızanın optimizasyonudur.Kafeine API'sinin çalışma işlevi temelde Guava'nınkiyle aynıdır ve Kafein daha önce Guava kullanıcısı ile uyumludur, bu nedenle önbelleği kullanmak veya yeniden yazmak için Kafein sorun olmamalı ama aynı zamanda projeye de bağlı, körü körüne kullanmayın.
Yazar: LLLSQ, bir North drift programcılarının trajik bir öyküsüne sahip, BT ve teknik makaleler gerçek zamanlı okuyucularda sıcak haberler, mimari, röportajlar ve diğer en son bilgiler.
Feragatname: Bu makale yazar tarafından sunulmuştur ve telif hakkı karşı tarafa aittir.