reidis分散式鎖做介面防重放
需求:
隨著專案的發展壯大,也會引起一些外圍的大神,幫助測測併發,挑挑系統漏洞,以及宕機測試。這時候介面做防重放勢在必行,選用redis做鎖在合適不過,nosql資料庫
單執行緒的redis為什麼這麼快
(一)純記憶體操作
(二)單執行緒操作,避免了頻繁的上下文切換
(三)採用了非阻塞I/O多路複用機制
redis的過期策略以及記憶體淘汰機制 redis採用的是定期刪除+惰性刪除策略。
===========================分割線===========================
redis的資料型別,以及每種資料型別的使用場景
(一)String
這個其實沒啥好說的,最常規的set/get操作,value可以是String也可以是數字。一般做一些複雜的計數功能的快取。
(二)hash
這裡value存放的是結構化的物件,比較方便的就是操作其中的某個欄位。博主在做單點登入的時候,就是用這種資料結構儲存使用者資訊,以cookieId作為key,設定30分鐘為快取過期時間,能很好的模擬出類似session的效果。
(三)list
使用List的資料結構,可以做簡單的訊息佇列的功能。另外還有一個就是,可以利用lrange命令,做基於redis的分頁功能,效能極佳,使用者體驗好。
(四)set
因為set堆放的是一堆不重複值的集合。所以可以做全域性去重的功能。為什麼不用JVM自帶的Set進行去重?因為我們的系統一般都是叢集部署,使用JVM自帶的Set,比較麻煩,難道為了一個做一個全域性去重,再起一個公共服務,太麻煩了。
另外,就是利用交集、並集、差集等操作,可以計算共同喜好,全部的喜好,自己獨有的喜好等功能。
(五)sorted set
sorted set多了一個權重引數score,集合中的元素能夠按score進行排列。可以做排行榜應用,取TOP N操作。另外,參照另一篇《分散式之延時任務方案解析》,該文指出了sorted set可以用來做延時任務。最後一個應用就是可以做範圍查詢。
(六)redis做訊息伺服器
spring-redis redisTemplate.convertAndSend(channel, message);
用SETNX實現分散式鎖
【java程式碼參考】:
static final Log log = LogFactory.getLog(RedisServiceImpl.class); /** spring-redis 設定分散式鎖並設定鎖的有效期 */ @Autowired private RedisTemplate<String, ?> redisTemplate; public boolean setNXAndExpire(final String key, final String value, long expiredSeconds) { boolean result = redisTemplate.execute(new RedisCallback<Boolean>() { @Override public Boolean doInRedis(RedisConnection connection) throws DataAccessException { RedisSerializer<String> serializer = redisTemplate.getStringSerializer(); // log.info("Before RedisServiceImpl.setNXAndExpire() " + key + ":" + value); boolean success = connection.setNX(serializer.serialize(key), serializer.serialize(value)); if (success) { connection.expire(serializer.serialize(key), expiredSeconds); } return success; } }); log.info("after RedisServiceImpl.setNXAndExpire() :" + result); return result; } /** spring-redis 還可以做訊息伺服器 傳送topic訊息 */ @Override public void sendRedisMsg(String channel, String message) { redisTemplate.convertAndSend(channel, message); } @Override public boolean del(final String key) { boolean result = redisTemplate.execute(new RedisCallback<Boolean>() { @Override public Boolean doInRedis(RedisConnection connection) throws DataAccessException { RedisSerializer<String> serializer = redisTemplate.getStringSerializer(); connection.del(serializer.serialize(key)); return true; } }); return result; } @Override public String getset(final String key, final String value) { String result = redisTemplate.execute(new RedisCallback<String>() { @Override public String doInRedis(RedisConnection connection) throws DataAccessException { RedisSerializer<String> serializer = redisTemplate.getStringSerializer(); log.info("RedisServiceImpl.getset():" + key); byte[] value1 = connection.getSet(serializer.serialize(key), serializer.serialize(value)); return serializer.deserialize(value1); } }); return result; }
===========================分割線===========================
把引數md5一下setnx存為key並設定有效期60s,只要在介面攔截器 或者切面攔截下url, 然後每次請求檢查key是否存在 以及過期,則過濾掉介面,否則通過校驗,這樣就避免每次都請求連線資料庫,
快取雪崩,即快取同一時間大面積的失效,這個時候又來了一波請求,結果請求都懟到資料庫上,從而導致資料庫連線異常;
減少了併發,削減了峰值;
避免了ddos攻擊;這樣在一定程度上緩解了系統宕機風險。
總結
本文對redis的常見問題做了一個總結。大部分是自己在工作中遇到,以及以前面試別人的時候,愛問的一些問題。另外,不推薦大家臨時抱佛腳,真正碰到一些有經驗的工程師,其實幾下就能把你問懵。最後,希望大家有所收穫吧。