From 33b098bea7a8b24dc223c2bdeb319ff9b1d622aa Mon Sep 17 00:00:00 2001 From: Rikako Wu <496063163@qq.com> Date: Mon, 6 Feb 2023 18:37:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90redisson=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E9=98=85=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spring/redisson/redisson.md | 306 ++++++++++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) diff --git a/spring/redisson/redisson.md b/spring/redisson/redisson.md index 3ee7e44..6be0cef 100644 --- a/spring/redisson/redisson.md +++ b/spring/redisson/redisson.md @@ -577,3 +577,309 @@ RLocalCachedMap map = ... map.destroy(); ``` #### Map Persistence +redisson允许将map中的数据存储到除了redis以外的空间,其通常用于和应用和数据库之间的缓存,类似于spring cache。 +##### read-through策略 +当请求的条目在redisson map object中不存在时,其会使用MapLoader对象来进行加载,示例代码如下: +```java +MapLoader mapLoader = new MapLoader() { + + @Override + public Iterable loadAllKeys() { + List list = new ArrayList(); + Statement statement = conn.createStatement(); + try { + ResultSet result = statement.executeQuery("SELECT id FROM student"); + while (result.next()) { + list.add(result.getString(1)); + } + } finally { + statement.close(); + } + + return list; + } + + @Override + public String load(String key) { + PreparedStatement preparedStatement = conn.prepareStatement("SELECT name FROM student where id = ?"); + try { + preparedStatement.setString(1, key); + ResultSet result = preparedStatement.executeQuery(); + if (result.next()) { + return result.getString(1); + } + return null; + } finally { + preparedStatement.close(); + } + } +}; +``` +配置map的示例如下: +```java +MapOptions options = MapOptions.defaults() + .loader(mapLoader); + +RMap map = redisson.getMap("test", options); +// or +RMapCache map = redisson.getMapCache("test", options); +// or with boost up to 45x times +RLocalCachedMap map = redisson.getLocalCachedMap("test", options); +// or with boost up to 45x times +RLocalCachedMapCache map = redisson.getLocalCachedMapCache("test", options); +``` +##### write-through(sync)策略 +如果map entry被更新,那么更新方法不会返回,直到通过MapWriter对象将entry更新写入到外部存储中: +```java +MapWriter mapWriter = new MapWriter() { + + @Override + public void write(Map map) { + PreparedStatement preparedStatement = conn.prepareStatement("INSERT INTO student (id, name) values (?, ?)"); + try { + for (Entry entry : map.entrySet()) { + preparedStatement.setString(1, entry.getKey()); + preparedStatement.setString(2, entry.getValue()); + preparedStatement.addBatch(); + } + preparedStatement.executeBatch(); + } finally { + preparedStatement.close(); + } + } + + @Override + public void delete(Collection keys) { + PreparedStatement preparedStatement = conn.prepareStatement("DELETE FROM student where id = ?"); + try { + for (String key : keys) { + preparedStatement.setString(1, key); + preparedStatement.addBatch(); + } + preparedStatement.executeBatch(); + } finally { + preparedStatement.close(); + } + } +}; +``` +write-through策略配置如下: +```java +MapOptions options = MapOptions.defaults() + .writer(mapWriter) + .writeMode(WriteMode.WRITE_BEHIND) + .writeBehindDelay(5000) + .writeBehindBatchSize(100); + +RMap map = redisson.getMap("test", options); +// or +RMapCache map = redisson.getMapCache("test", options); +// or with boost up to 45x times +RLocalCachedMap map = redisson.getLocalCachedMap("test", options); +// or with boost up to 45x times +RLocalCachedMapCache map = redisson.getLocalCachedMapCache("test", options); +``` +##### write-behind策略(async) +在使用write-behind之后,对于map object的修改是批量累计的,并且按定义的延迟异步被MapWriter写入到外部存储中。 +writeBehindDelay是批量写入或删除的延迟,默认情况下值为1000ms。writeBehindBatchSize是batch的容量,每个batch都包含写入和删除的命令集合,默认情况下size是50 . +配置代码如下所示: +```java +MapOptions options = MapOptions.defaults() + .writer(mapWriter) + .writeMode(WriteMode.WRITE_BEHIND) + .writeBehindDelay(5000) + .writeBehindBatchSize(100); + +RMap map = redisson.getMap("test", options); +// or +RMapCache map = redisson.getMapCache("test", options); +// or with boost up to 45x times +RLocalCachedMap map = redisson.getLocalCachedMap("test", options); +// or with boost up to 45x times +RLocalCachedMapCache map = redisson.getLocalCachedMapCache("test", options); +``` +#### Map Listener +Redisson允许为实现RMapCache接口的Map对象绑定监听器,监听如下的map事件: +- entry创建:org.redisson.api.map.event.EntryCreatedListener +- entry过期:org.redisson.api.map.event.EntryExpiredListener +- entry移除:org.redisson.api.map.event.EntryRemovedListener +- entry更新:org.redisson.api.map.event.EntryUpdatedListener + +使用实例如下所示: +```java +RMapCache map = redisson.getMapCache("anyMap"); +// or +RMapCache map = redisson.getLocalCachedMapCache("anyMap", LocalCachedMapOptions.defaults()); +// or +RMapCache map = redisson.getClusteredLocalCachedMapCache("anyMap", LocalCachedMapOptions.defaults()); +// or +RMapCache map = redisson.getClusteredMapCache("anyMap"); + + +int updateListener = map.addListener(new EntryUpdatedListener() { + @Override + public void onUpdated(EntryEvent event) { + event.getKey(); // key + event.getValue() // new value + event.getOldValue() // old value + // ... + } +}); + +int createListener = map.addListener(new EntryCreatedListener() { + @Override + public void onCreated(EntryEvent event) { + event.getKey(); // key + event.getValue() // value + // ... + } +}); + +int expireListener = map.addListener(new EntryExpiredListener() { + @Override + public void onExpired(EntryEvent event) { + event.getKey(); // key + event.getValue() // value + // ... + } +}); + +int removeListener = map.addListener(new EntryRemovedListener() { + @Override + public void onRemoved(EntryEvent event) { + event.getKey(); // key + event.getValue() // value + // ... + } +}); + +map.removeListener(updateListener); +map.removeListener(createListener); +map.removeListener(expireListener); +map.removeListener(removeListener); +``` +#### LRU/LFU bounded Map +实现了RMapCache接口的Map对象支持按LRU或LFU顺序进行绑定。绑定了LRU或LFU的Map可以存储固定数量的entry,并且按照LRU或LFU的顺序淘汰entry。 +```java +RMapCache map = redisson.getMapCache("anyMap"); +// or +RMapCache map = redisson.getLocalCachedMapCache("anyMap", LocalCachedMapOptions.defaults()); +// or +RMapCache map = redisson.getClusteredLocalCachedMapCache("anyMap", LocalCachedMapOptions.defaults()); +// or +RMapCache map = redisson.getClusteredMapCache("anyMap"); + + +// tries to set limit map to 10 entries using LRU eviction algorithm +map.trySetMaxSize(10); +// ... using LFU eviction algorithm +map.trySetMaxSize(10, EvictionMode.LFU); + +// set or change limit map to 10 entries using LRU eviction algorithm +map.setMaxSize(10); +// ... using LFU eviction algorithm +map.setMaxSize(10, EvictionMode.LFU); + +map.put("1", "2"); +map.put("3", "3", 1, TimeUnit.SECONDS); +``` +### MultiMap +基于Redis的MultiMap支持为一个key绑定多个value +#### Set based MultiMap +基于set的multimap实现对于相同的key不允许出现重复的value: +```java +RSetMultimap map = redisson.getSetMultimap("myMultimap"); +map.put(new SimpleKey("0"), new SimpleValue("1")); +map.put(new SimpleKey("0"), new SimpleValue("2")); +map.put(new SimpleKey("3"), new SimpleValue("4")); + +Set allValues = map.get(new SimpleKey("0")); + +List newValues = Arrays.asList(new SimpleValue("7"), new SimpleValue("6"), new SimpleValue("5")); +Set oldValues = map.replaceValues(new SimpleKey("0"), newValues); + +Set removedValues = map.removeAll(new SimpleKey("0")); +``` +#### List based MultiMap +基于List的MultiMap允许对相同的key存在多个相同value,并且对同一个key其value按插入顺序存储: +```java +RListMultimap map = redisson.getListMultimap("test1"); +map.put(new SimpleKey("0"), new SimpleValue("1")); +map.put(new SimpleKey("0"), new SimpleValue("2")); +map.put(new SimpleKey("0"), new SimpleValue("1")); +map.put(new SimpleKey("3"), new SimpleValue("4")); + +List allValues = map.get(new SimpleKey("0")); + +Collection newValues = Arrays.asList(new SimpleValue("7"), new SimpleValue("6"), new SimpleValue("5")); +List oldValues = map.replaceValues(new SimpleKey("0"), newValues); + +List removedValues = map.removeAll(new SimpleKey("0")); +``` +#### MultiMap eviction +对于实现了MultimapCache接口的map对象,分别支持基于list和基于set的evicition。 +过期的entry清除由EvictionScheduler执行,其一次性会移除100条过期的entry。Task启动时间会根据上次任务删除的条目数目自动进行调整,时间间隔在1s和2h之间进行调整。 +MultiMap eviction使用示例如下所示: +```java +RSetMultimapCache multimap = redisson.getSetMultimapCache("myMultimap"); +multimap.put("1", "a"); +multimap.put("1", "b"); +multimap.put("1", "c"); + +multimap.put("2", "e"); +multimap.put("2", "f"); + +multimap.expireKey("2", 10, TimeUnit.MINUTES); +``` +### Set +基于redis的set object实现了java.util.set接口。 +redis set的使用如下所示: +```java +RSet set = redisson.getSet("anySet"); +set.add(new SomeObject()); +set.remove(new SomeObject()); +``` +根据是否支持数据淘汰,可以分为如下方法: +| Redisson Client method | Eviction Support | +| :-: | :-: | +| getSet() | false | +|getSetCache() | true | +#### eviction +支持淘汰功能的Set对象实现了RSetCache接口,当前redis尚不支持淘汰set中的值,故而淘汰是由EvictionScheduler实现的,其一次性移除300条entry,根据上次task淘汰的key数量,下次执行task的间隔在1s到1h之间调整。 +```java +RSetCache set = redisson.getSetCache("mySet"); +// or +RMapCache set = redisson.getClusteredSetCache("mySet"); + +// ttl = 10 minutes, +set.add(new SomeObject(), 10, TimeUnit.MINUTES); + +// if object is not used anymore +set.destroy(); +``` +#### SortedSet +基于Redis的SortedSet实现了java.util.SortedSet接口,其通过比较元素来确保元素的在set中的唯一性。对于String数据类型,更推荐使用LexSortedSet,其性能表现更好。 +RSortedSet的使用示例如下所示: +```java +RSortedSet set = redisson.getSortedSet("anySet"); +set.trySetComparator(new MyComparator()); // set object comparator +set.add(3); +set.add(1); +set.add(2); + +set.removeAsync(0); +set.addAsync(5); +``` +#### ScoredSortedSet +基于redis的分布式ScoredSortedSet根据插入元素时的score来对元素进行排序。使用示例如下所示: +```java +set.add(0.13, new SomeObject(a, b)); +set.addAsync(0.251, new SomeObject(c, d)); +set.add(0.302, new SomeObject(g, d)); + +set.pollFirst(); +set.pollLast(); + +int index = set.rank(new SomeObject(g, d)); // get element index +Double score = set.getScore(new SomeObject(g, d)); // get element score +``` \ No newline at end of file