文章目錄
- 01.緩存數據(Cache)
- 02.布式鎖(Distributed Lock)
- 03.計數器(Counter)
- 04.排行榜(Leaderboard)
- 05.消息隊列(Message Queue)
- 06.限流(Rate Limiting)
- 07.會話存儲(Session Storage)
- 08.地理位置(Geo)
- 09. 發布訂閱(Pub/Sub)
01.緩存數據(Cache)
將數據庫查詢結果緩存到Redis,減輕數據庫壓力
示例:在電商網站中,可以將熱門商品的信息存儲在Redis中,當用戶訪問這些商品時,首先從Redis中讀取,如果Redis中沒有,再從數據庫中讀取并更新到Redis中。
@Service
public class ProductService {@Autowiredprivate ProductRepository productRepository;@Autowiredprivate RedisTemplate<String, Object> redisTemplate;private static final String PRODUCT_CACHE_PREFIX = "product:";public Product getProductById(Long id) {String cacheKey = PRODUCT_CACHE_PREFIX + id;// 1. 先查緩存Product product = (Product) redisTemplate.opsForValue().get(cacheKey);if (product != null) {return product;}// 2. 緩存沒有則查數據庫product = productRepository.findById(id).orElse(null);if (product != null) {// 3. 寫入緩存,設置過期時間redisTemplate.opsForValue().set(cacheKey, product, 30, TimeUnit.MINUTES);}return product;}
}
02.布式鎖(Distributed Lock)
在分布式系統中,Redis可以用于實現分布式鎖,可以在分布式系統中協調多節點對共享資源的訪問,確保操作的原子性。
示例:分布式系統中用戶購買商品,同一時間只能一個用戶創建訂單。
@Service
public class OrderService {@Autowiredprivate StringRedisTemplate redisTemplate;private static final String LOCK_PREFIX = "lock:";private static final long LOCK_EXPIRE = 30; // 30秒public boolean createOrder(Long productId, Long userId) {String lockKey = LOCK_PREFIX + "order_" + productId;String requestId = UUID.randomUUID().toString();try {// 嘗試獲取鎖Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, LOCK_EXPIRE, TimeUnit.SECONDS);if (Boolean.TRUE.equals(locked)) {// 獲取鎖成功,執行業務邏輯return doCreateOrder(productId, userId);}return false;} finally {// 釋放鎖 - 使用Lua腳本保證原子性String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +" return redis.call('del', KEYS[1]) " +"else " +" return 0 " +"end";redisTemplate.execute(new DefaultRedisScript<>(script, Long.class),Collections.singletonList(lockKey),requestId);}}
}
03.計數器(Counter)
Redis的原子增減操作非常適合用于計數器和排行榜應用,如社交媒體的點贊數、閱讀數、排名等。
示例:實現文章閱讀量、商品點擊量等統計
@Service
public class ArticleService {@Autowiredprivate StringRedisTemplate redisTemplate;private static final String VIEW_COUNT_PREFIX = "article:view:";// 增加閱讀量public void incrementViewCount(Long articleId) {String key = VIEW_COUNT_PREFIX + articleId;redisTemplate.opsForValue().increment(key);}// 獲取閱讀量public Long getViewCount(Long articleId) {String key = VIEW_COUNT_PREFIX + articleId;String count = redisTemplate.opsForValue().get(key);return count == null ? 0L : Long.parseLong(count);}// 批量獲取閱讀量public Map<Long, Long> getBatchViewCounts(List<Long> articleIds) {List<String> keys = articleIds.stream().map(id -> VIEW_COUNT_PREFIX + id).collect(Collectors.toList());List<String> counts = redisTemplate.opsForValue().multiGet(keys);Map<Long, Long> result = new HashMap<>();for (int i = 0; i < articleIds.size(); i++) {Long articleId = articleIds.get(i);String count = counts.get(i);result.put(articleId, count == null ? 0L : Long.parseLong(count));}return result;}
}
04.排行榜(Leaderboard)
Redis的原子增減操作非常適合用于計數器和排行榜應用,如社交媒體的點贊數、閱讀數、排名等。
示例:實現商品銷量排行、游戲積分排行等
@Service
public class RankingService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;private static final String SALES_RANK_KEY = "product:sales:rank";// 更新商品銷量public void updateProductSales(Long productId, int sales) {redisTemplate.opsForZSet().add(SALES_RANK_KEY, productId, sales);}// 獲取銷量前N的商品public List<Long> getTopSalesProducts(int topN) {Set<Object> productIds = redisTemplate.opsForZSet().reverseRange(SALES_RANK_KEY, 0, topN - 1);return productIds.stream().map(id -> Long.parseLong(id.toString())).collect(Collectors.toList());}// 獲取商品排名public Long getProductRank(Long productId) {// ZREVRANK返回的是從0開始的排名Long rank = redisTemplate.opsForZSet().reverseRank(SALES_RANK_KEY, productId);return rank == null ? null : rank + 1; // 轉換為1-based排名}// 獲取商品銷量public Double getProductSales(Long productId) {return redisTemplate.opsForZSet().score(SALES_RANK_KEY, productId);}
}
05.消息隊列(Message Queue)
Redis支持發布/訂閱模式,可以用作輕量級的消息隊列系統,用于異步任務處理、事件處理等。
示例:實現簡單的消息隊列系統
@Service
public class MessageQueueService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;private static final String QUEUE_KEY = "message:queue";// 發送消息public void sendMessage(String message) {redisTemplate.opsForList().rightPush(QUEUE_KEY, message);}// 接收消息 - 阻塞式public String receiveMessage() throws InterruptedException {return (String) redisTemplate.opsForList().leftPop(QUEUE_KEY, 30, TimeUnit.SECONDS);}// 批量發送消息public void batchSendMessages(List<String> messages) {redisTemplate.executePipelined((RedisCallback<Object>) connection -> {for (String message : messages) {connection.listCommands().rPush(QUEUE_KEY.getBytes(), message.getBytes());}return null;});}
}
06.限流(Rate Limiting)
Redis 適合用于限流(Rate Limiting)場景。限流的目的是控制某個操作在特定時間內的訪問頻率,比如 API 請求、短信發送、登錄嘗試等。Redis 的原子操作和高效性能使其成為實現限流的理想工具。
示例:實現API訪問限流
@Service
public class RateLimitService {@Autowiredprivate StringRedisTemplate redisTemplate;private static final String RATE_LIMIT_PREFIX = "rate_limit:";/*** 限流檢查* @param key 限流key(如用戶ID或IP)* @param limit 時間窗口內允許的最大請求數* @param windowInSeconds 時間窗口大小(秒)* @return true-允許訪問 false-拒絕訪問*/public boolean allowRequest(String key, int limit, int windowInSeconds) {String redisKey = RATE_LIMIT_PREFIX + key;// 使用Lua腳本保證原子性String script = "local current = redis.call('incr', KEYS[1])\n" +"if current == 1 then\n" +" redis.call('expire', KEYS[1], ARGV[1])\n" +"end\n" +"return current <= tonumber(ARGV[2])";Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class),Collections.singletonList(redisKey),String.valueOf(windowInSeconds),String.valueOf(limit));return result != null && result == 1;}
}
07.會話存儲(Session Storage)
在Web應用中,Redis常用于存儲用戶會話信息,如登錄狀態、購物車內容等。由于其快速的讀寫速度,Redis非常適合這種需要頻繁訪問和更新的數據。
示例:分布式系統中的會話存儲
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800) // 30分鐘過期
public class RedisSessionConfig {// Spring Session會自動配置Redis連接
}// 使用示例
@RestController
public class UserController {@PostMapping("/login")public String login(@RequestParam String username, HttpSession session) {// 存儲用戶信息到sessionsession.setAttribute("username", username);return "登錄成功";}@GetMapping("/userinfo")public String getUserInfo(HttpSession session) {// 從session獲取用戶信息String username = (String) session.getAttribute("username");return "當前用戶: " + (username != null ? username : "未登錄");}
}
08.地理位置(Geo)
Redis支持地理空間數據,可以用于構建地理位置應用,如附近的人、地點推薦等功能。
示例:實現附近的人、附近的商家等功能
@Service
public class LocationService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;private static final String GEO_KEY = "shop:locations";// 添加商家位置public void addShopLocation(Long shopId, double lng, double lat) {redisTemplate.opsForGeo().add(GEO_KEY, new Point(lng, lat), shopId.toString());}// 獲取附近商家public List<Long> getNearbyShops(double lng, double lat, double radius) {Circle within = new Circle(new Point(lng, lat), new Distance(radius, Metrics.KILOMETERS));RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().sortAscending().limit(10);GeoResults<RedisGeoCommands.GeoLocation<Object>> results = redisTemplate.opsForGeo().radius(GEO_KEY, within, args);return results.getContent().stream().map(geoResult -> Long.parseLong(geoResult.getContent().getName().toString())).collect(Collectors.toList());}// 計算兩個商家距離public Distance calculateDistance(Long shopId1, Long shopId2) {List<String> ids = Arrays.asList(shopId1.toString(), shopId2.toString());return redisTemplate.opsForGeo().distance(GEO_KEY, ids.get(0), ids.get(1), Metrics.KILOMETERS);}
}
09. 發布訂閱(Pub/Sub)
示例:實現實時消息通知、事件廣播等
// 配置消息監聽容器
@Configuration
public class RedisPubSubConfig {@Beanpublic RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory,MessageListenerAdapter orderEventListenerAdapter) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);container.addMessageListener(orderEventListenerAdapter, new ChannelTopic("order:events"));return container;}@Beanpublic MessageListenerAdapter orderEventListenerAdapter(OrderEventListener listener) {return new MessageListenerAdapter(listener, "handleMessage");}
}// 消息監聽器
@Component
public class OrderEventListener {public void handleMessage(OrderEvent event) {switch (event.getType()) {case CREATED:handleOrderCreated(event);break;case PAID:handleOrderPaid(event);break;// 其他事件處理...}}private void handleOrderCreated(OrderEvent event) {// 處理訂單創建事件}
}// 消息發布服務
@Service
public class OrderEventPublisher {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;public void publishOrderEvent(OrderEvent event) {redisTemplate.convertAndSend("order:events", event);}
}