τα στοιχεία επικοινωνίας μου
Ταχυδρομείο[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Στον κόσμο της Java, η τεχνολογία προσωρινής αποθήκευσης χρησιμοποιείται ευρέως για τη βελτίωση της απόδοσης της εφαρμογής και χωρίζεται κυρίως σε δύο κατηγορίες: απομακρυσμένη προσωρινή αποθήκευση και τοπική προσωρινή αποθήκευση. Η απομακρυσμένη προσωρινή αποθήκευση, με την εξαιρετική απόδοση και την ευελιξία της, υλοποιείται συχνά μέσω δημοφιλών λύσεων όπως το Redis και το Memcached. Η τοπική κρυφή μνήμη, με τα χαρακτηριστικά ελαφριάς και γρήγορης πρόσβασης, αντιπροσωπεύεται από τεχνολογίες όπως HashMap, Guava Cache, Caffeine και Ehcache.
Θα εμβαθύνουμε στα μυστήρια της απομακρυσμένης προσωρινής αποθήκευσης σε μελλοντικές αναρτήσεις ιστολογίου, αλλά σήμερα, ας εστιάσουμε στην τοπική προσωρινή αποθήκευση. Αυτό το άρθρο θα σας οδηγήσει πρώτα στην τοπική τεχνολογία προσωρινής αποθήκευσης για να σας παρέχει μια ολοκληρωμένη επισκόπηση. Στη συνέχεια, θα εμβαθύνουμε στην τεχνολογία προσωρινής αποθήκευσης, γνωστή ως ο βασιλιάς της απόδοσης, και θα εξερευνήσουμε τις αρχές και τις μεθόδους υλοποίησης πίσω από αυτήν. Τέλος, μέσω μιας σειράς πρακτικών περιπτώσεων, θα δείξουμε πώς να χρησιμοποιείτε αποτελεσματικά αυτές τις τεχνολογίες τοπικής προσωρινής αποθήκευσης υψηλής απόδοσης στην καθημερινή εργασία για να βελτιώσετε την αποδοτικότητα ανάπτυξης και την απόδοση της εφαρμογής σας.
Χρησιμοποιώντας την υποκείμενη υλοποίηση του Map, μπορούμε να αποθηκεύσουμε τα αντικείμενα που θα αποθηκευτούν στην προσωρινή μνήμη απευθείας στη μνήμη, η οποία είναι μια άμεση και αποτελεσματική μέθοδος.
Πλεονέκτημα: Αυτή η μέθοδος είναι απλή και άμεση, χωρίς να βασίζεται σε εξωτερικές βιβλιοθήκες και είναι πολύ κατάλληλη για εφαρμογές με απλές απαιτήσεις προσωρινής αποθήκευσης και απλά σενάρια.
Μειονεκτήματα: Ωστόσο, αυτή η μέθοδος δεν διαθέτει μηχανισμό αυτόματης εξάλειψης της κρυφής μνήμης Εάν πρέπει να εφαρμοστούν πιο προηγμένες στρατηγικές προσωρινής αποθήκευσης, ενδέχεται να απαιτηθούν υψηλότερα προσαρμοσμένα κόστη ανάπτυξης.
- public class LRUCache extends LinkedHashMap {
-
- /**
- * 可重入读写锁,保证并发读写安全性
- */
- private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
- private Lock readLock = readWriteLock.readLock();
- private Lock writeLock = readWriteLock.writeLock();
-
- /**
- * 缓存大小限制
- */
- private int maxSize;
-
- public LRUCache(int maxSize) {
- super(maxSize + 1, 1.0f, true);
- this.maxSize = maxSize;
- }
-
- @Override
- public Object get(Object key) {
- readLock.lock();
- try {
- return super.get(key);
- } finally {
- readLock.unlock();
- }
- }
-
- @Override
- public Object put(Object key, Object value) {
- writeLock.lock();
- try {
- return super.put(key, value);
- } finally {
- writeLock.unlock();
- }
- }
-
- @Override
- protected boolean removeEldestEntry(Map.Entry eldest) {
- return this.size() > maxSize;
- }
- }
Το Guava Cache είναι μια τεχνολογία προσωρινής αποθήκευσης που αναπτύχθηκε από την Google που βασίζεται στον αλγόριθμο αντικατάστασης LRU (που χρησιμοποιήθηκε λιγότερο πρόσφατα). Ωστόσο, με την άνοδο της καφεΐνης, το Guava Cache σταδιακά έσβησε από τα μάτια των ανθρώπων. Η καφεΐνη όχι μόνο κληρονομεί τα πλεονεκτήματα του Guava Cache, αλλά την ξεπερνά και σε πολλές πτυχές. Παρόλο που δεν παρέχεται συγκεκριμένο δείγμα κώδικα εδώ, οι αναγνώστες που ενδιαφέρονται για το Guava Cache μπορούν να επισκεφτούν τον επίσημο ιστότοπο του για περισσότερες πληροφορίες.
Πλεονέκτημα: Το Guava Cache υποστηρίζει τον καθορισμό ορίων μέγιστης χωρητικότητας και παρέχει δύο στρατηγικές λήξης: με βάση τον χρόνο εισαγωγής και τον χρόνο πρόσβασης και υποστηρίζει επίσης ορισμένες βασικές στατιστικές λειτουργίες.
Μειονεκτήματα: Με την κυκλοφορία των Spring Boot 2 και Spring 5, το Guava Cache δεν συνιστάται πλέον και για τα δύο.
Η καφεΐνη είναι μια τεχνολογία προσωρινής αποθήκευσης ανοιχτού κώδικα που χρησιμοποιεί τον αλγόριθμο W-TinyLFU, ο οποίος είναι μια στρατηγική εξάλειψης της κρυφής μνήμης που συνδυάζει τα πλεονεκτήματα των LRU και LFU (χρησιμοποιείται ελάχιστη συχνότητα). Η απόδοση της cache της καφεΐνης είναι κοντά στη θεωρητική βέλτιστη λύση και μπορεί να θεωρηθεί ως μια αναβαθμισμένη έκδοση του Guava Cache.
- public class CaffeineCacheTest {
-
- public static void main(String[] args) throws Exception {
- //创建guava cache
- Cache<String, String> loadingCache = Caffeine.newBuilder()
- //cache的初始容量
- .initialCapacity(5)
- //cache最大缓存数
- .maximumSize(10)
- //设置写缓存后n秒钟过期
- .expireAfterWrite(17, TimeUnit.SECONDS)
- //设置读写缓存后n秒钟过期,实际很少用到,类似于expireAfterWrite
- //.expireAfterAccess(17, TimeUnit.SECONDS)
- .build();
- String key = "key";
- // 往缓存写数据
- loadingCache.put(key, "v");
-
- // 获取value的值,如果key不存在,获取value后再返回
- String value = loadingCache.get(key, CaffeineCacheTest::getValueFromDB);
-
- // 删除key
- loadingCache.invalidate(key);
- }
-
- private static String getValueFromDB(String key) {
- return "v";
- }
- }
Το Ehcache είναι ένα καθαρό πλαίσιο προσωρινής αποθήκευσης σε διαδικασία Java, γνωστό για τη γρήγορη και αποτελεσματική απόδοσή του. Είναι ευρέως αναγνωρισμένο και χρησιμεύει ως ο προεπιλεγμένος πάροχος προσωρινής μνήμης για την Αδρανοποίηση.
Πλεονέκτημα : Το Ehcache παρέχει μια ευρεία γκάμα αλγορίθμων εξάλειψης της κρυφής μνήμης, συμπεριλαμβανομένων των LFU (χρησιμοποιείται λιγότερο συχνά), LRU (λιγότερο πρόσφατα χρησιμοποιημένος) και FIFO (πρώτος εισερχόμενος, πρώτη έξοδος). Υποστηρίζει διαφορετικούς τύπους αποθήκευσης κρυφής μνήμης, όπως cache in-heap, cache off-heap και cache δίσκου, για προσαρμογή σε διαφορετικές ανάγκες αποθήκευσης. Επιπλέον, το Ehcache υποστηρίζει επίσης μια ποικιλία λύσεων συμπλέγματος, επιλύοντας αποτελεσματικά το πρόβλημα της κοινής χρήσης δεδομένων.
Μειονεκτήματα: Αν και το Ehcache υπερέχει σε πολλές πτυχές, υπολείπεται ελαφρώς της καφεΐνης όσον αφορά την απόδοση.
-
- public class EncacheTest {
-
- public static void main(String[] args) throws Exception {
- // 声明一个cacheBuilder
- CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
- .withCache("encacheInstance", CacheConfigurationBuilder
- //声明一个容量为20的堆内缓存
- .newCacheConfigurationBuilder(String.class,String.class, ResourcePoolsBuilder.heap(20)))
- .build(true);
- // 获取Cache实例
- Cache<String,String> myCache = cacheManager.getCache("encacheInstance", String.class, String.class);
- // 写缓存
- myCache.put("key","v");
- // 读缓存
- String value = myCache.get("key");
- // 移除换粗
- cacheManager.removeCache("myCache");
- cacheManager.close();
- }
- }
Cache<Key, Graph> cache = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(10_000)
.build();
// 查找一个缓存元素, 没有查找到的时候返回null
Graph graph = cache.getIfPresent(key);
// 查找缓存,如果缓存不存在则生成缓存元素, 如果无法生成则返回null
graph = cache.get(key, k -> createExpensiveGraph(key));
// 添加或者更新一个缓存元素
cache.put(key, graph);
// 移除一个缓存元素
cache.invalidate(key);
Η διεπαφή προσωρινής μνήμης παρέχει τη δυνατότητα εύρεσης, ενημέρωσης και αφαίρεσης στοιχείων που έχουν αποθηκευτεί στην κρυφή μνήμη χρησιμοποιώντας ρητές αναζητήσεις. Όταν το αποθηκευμένο στοιχείο δεν μπορεί να δημιουργηθεί ή δημιουργείται εξαίρεση κατά τη διαδικασία δημιουργίας και η δημιουργία του στοιχείου αποτυγχάνει, το cache.get μπορεί να επιστρέψει null.
LoadingCache<Key, Graph> cache = Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(key -> createExpensiveGraph(key));
// 查找缓存,如果缓存不存在则生成缓存元素, 如果无法生成则返回null
Graph graph = cache.get(key);
// 批量查找缓存,如果缓存不存在则生成缓存元素
Map<Key, Graph> graphs = cache.getAll(keys);
Το LoadingCache είναι μια εφαρμογή προσωρινής μνήμης μιας προσωρινής μνήμης με την δυνατότητα προσθήκης CacheLoader.
Εάν η προσωρινή μνήμη δεν υπάρχει, το αντίστοιχο στοιχείο κρυφής μνήμης θα δημιουργηθεί μέσω του CacheLoader.load.
AsyncCache<Key, Graph> cache = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(10_000)
.buildAsync();
// 查找一个缓存元素, 没有查找到的时候返回null
CompletableFuture<Graph> graph = cache.getIfPresent(key);
// 查找缓存元素,如果不存在,则异步生成
graph = cache.get(key, k -> createExpensiveGraph(key));
// 添加或者更新一个缓存元素
cache.put(key, graph);
// 移除一个缓存元素
cache.synchronous().invalidate(key);
Το AsyncCache είναι η ασύγχρονη μορφή της προσωρινής μνήμης, παρέχοντας τη δυνατότητα στον Executor να δημιουργεί στοιχεία κρυφής μνήμης και να επιστρέφει το CompletableFuture. Η προεπιλεγμένη υλοποίηση της ομάδας νημάτων είναι η ForkJoinPool.commonPool(), αλλά μπορείτε επίσης να προσαρμόσετε την επιλογή της ομάδας νημάτων παρακάμπτοντας και εφαρμόζοντας τη μέθοδο Caffeine.executor(Executor).
AsyncLoadingCache<Key, Graph> cache = Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(10, TimeUnit.MINUTES)
// 你可以选择: 去异步的封装一段同步操作来生成缓存元素
.buildAsync(key -> createExpensiveGraph(key));
// 你也可以选择: 构建一个异步缓存元素操作并返回一个future
.buildAsync((key, executor) -> createExpensiveGraphAsync(key, executor));
// 查找缓存元素,如果其不存在,将会异步进行生成
CompletableFuture<Graph> graph = cache.get(key);
// 批量查找缓存元素,如果其不存在,将会异步进行生成
CompletableFuture<Map<Key, Graph>> graphs = cache.getAll(keys);
Το AsyncLoadingCache είναι η ασύγχρονη μορφή του LoadingCache, η οποία παρέχει τη λειτουργία του ασύγχρονου φορτίου για τη δημιουργία στοιχείων κρυφής μνήμης.
// 基于缓存内的元素个数进行驱逐
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
.maximumSize(10_000)
.build(key -> createExpensiveGraph(key));
// 基于缓存内元素权重进行驱逐
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
.maximumWeight(10_000)
.weigher((Key key, Graph graph) -> graph.vertices().size())
.build(key -> createExpensiveGraph(key));
// 基于固定的过期时间驱逐策略
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
.expireAfterAccess(5, TimeUnit.MINUTES)
.build(key -> createExpensiveGraph(key));
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(key -> createExpensiveGraph(key));
// 基于不同的过期驱逐策略
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
.expireAfter(new Expiry<Key, Graph>() {
public long expireAfterCreate(Key key, Graph graph, long currentTime) {
// Use wall clock time, rather than nanotime, if from an external resource
long seconds = graph.creationDate().plusHours(5)
.minus(System.currentTimeMillis(), MILLIS)
.toEpochSecond();
return TimeUnit.SECONDS.toNanos(seconds);
}
public long expireAfterUpdate(Key key, Graph graph,
long currentTime, long currentDuration) {
return currentDuration;
}
public long expireAfterRead(Key key, Graph graph,
long currentTime, long currentDuration) {
return currentDuration;
}
})
.build(key -> createExpensiveGraph(key));
// 当key和缓存元素都不再存在其他强引用的时候驱逐
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
.weakKeys()
.weakValues()
.build(key -> createExpensiveGraph(key));
// 当进行GC的时候进行驱逐
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
.softValues()
.build(key -> createExpensiveGraph(key));
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
.maximumSize(10_000)
.refreshAfterWrite(1, TimeUnit.MINUTES)
.build(key -> createExpensiveGraph(key));
Η στρατηγική ανανέωσης μπορεί να χρησιμοποιηθεί μόνο στο LoadingCache, σε αντίθεση με το eiction, εάν το στοιχείο της κρυφής μνήμης ζητηθεί κατά τη διάρκεια της ανανέωσης, η παλιά του τιμή θα επιστραφεί και η ανανεωμένη νέα τιμή δεν θα επιστραφεί μέχρι να ολοκληρωθεί η ανανέωση του στοιχείου.
Cache<Key, Graph> graphs = Caffeine.newBuilder()
.maximumSize(10_000)
.recordStats()
.build();
Η συλλογή δεδομένων μπορεί να ενεργοποιηθεί χρησιμοποιώντας τη μέθοδο Caffeine.recordStats(). Η μέθοδος Cache.stats() θα επιστρέψει ένα αντικείμενο CacheStats, το οποίο θα περιέχει ορισμένους στατιστικούς δείκτες, όπως:
hitRate(): Ρυθμός επιτυχίας της κρυφής μνήμης ερωτήματος
evictionCount(): Αριθμός κρυφών μνήμων που αποβάλλονται
averageLoadPenalty(): Ο μέσος χρόνος που χρειάζεται για να φορτωθεί μια νέα τιμή
Με τον ελεγκτή RESTful που παρέχεται από το SpringBoot, μπορείτε εύκολα να ρωτήσετε τη χρήση της προσωρινής μνήμης.