中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Redis分布式緩存與秒殺怎么實現

發布時間:2023-04-03 11:29:06 來源:億速云 閱讀:107 作者:iii 欄目:開發技術

本篇內容介紹了“Redis分布式緩存與秒殺怎么實現”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

一、單點Redis的問題

1、數據丟失問題

Redis數據持久化。

2、并發能力問題

大家主從集群,實現讀寫分離。

3、故障恢復問題

利用Redis哨兵,實現健康檢測和自動恢復。

4、存儲能力問題

搭建分片集群,利用插槽機制實現動態擴容。

二、RDB

RDB全稱Redis Database Backup file(Redis數據備份文件),也被叫做Redis數據快照。簡單來說就是把內存中的所有數據都記錄到磁盤中。當Redis實例故障重啟后,從磁盤讀取快照文件,恢復數據。
快照文件稱為RDB文件,默認是保存在當前運行目錄。

Redis內部有觸發RDB的機制,可以在redis.conf文件中找到,格式如下:

Redis分布式緩存與秒殺怎么實現

bgsave開始時會fork主進程得到子進程,子進程共享主進程的內存數據。完成fork后讀取內存數據并寫入 RDB 文件。

fork采用的是copy-on-write技術:

  • 當主進程執行讀操作時,訪問共享內存;

  • 當主進程執行寫操作時,則會拷貝一份數據,執行寫操作;

RDB方式bgsave的基本流程?

  1. fork主進程得到一個子進程,共享內存空間;

  2. 子進程讀取內存數據并寫入新的RDB文件;

  3. 用新RDB文件替換舊的RDB文件;

Redis分布式緩存與秒殺怎么實現

RDB會在什么時候執行?save 60 1000代表什么含義?

  • 默認是服務停止時;

  • 代表60秒內至少執行1000次修改則觸發RDB;

RDB的缺點?

  • RDB執行間隔時間長,兩次RDB之間寫入數據有丟失的風險;

  • fork子進程、壓縮、寫出RDB文件都比較耗時;

AOF的命令記錄的頻率也可以通過redis.conf文件來配:

三、AOF

AOF全稱為Append Only File(追加文件)。Redis處理的每一個寫命令都會記錄在AOF文件,可以看做是命令日志文件。

AOF默認是關閉的,需要修改redis.conf配置文件來開啟AOF:

Redis分布式緩存與秒殺怎么實現

AOF的命令記錄的頻率也可以通過redis.conf文件來配:

Redis分布式緩存與秒殺怎么實現

配置項刷盤時機優點缺點
Always同步刷盤可靠性高,幾乎不丟數據性能影響大
everysec每秒刷盤性能適中最多丟失一分鐘的數據
no操作系統控制性能最好可靠性較差,可能丟失大量數據

 因為是記錄命令,AOF文件會比RDB文件大的多。而且AOF會記錄對同一個key的多次寫操作,但只有最后一次寫操作才有意義。通過執行bgrewriteaof命令,可以讓AOF文件執行重寫功能,用最少的命令達到相同效果。

set id 1
set name nezha
set id 2

bgrewriteaof

mset name nezha id 2

Redis也會在觸發閾值時自動去重寫AOF文件。閾值也可以在redis.conf中配置:

# AOF文件比上次文件 增長超過多少百分比則觸發重寫auto-aof-rewrite-percentage 100# AOF文件體積最小多大以上才觸發重寫 auto-aof-rewrite-min-size 64mb 

 RDB和AOF各有自己的優缺點,如果對數據安全性要求較高,在實際開發中往往會結合兩者來使用。


RDBAOF
持久化方式定時對整個內存做快照記錄每一次執行的命令
數據完整性不完整,兩次備份之間會丟失相對完整,取決于刷盤策略
文件大小會有壓縮,文件體積小記錄命令,文件體積很大
宕機恢復速度很快
數據恢復優先級低,因為數據完整性不低高,因為數據完整性更高
系統資源占用高,大量CPU和內存消耗低,主要是磁盤IO資源,但AOF重寫時會占用大量CPU和內存資源
使用場景可以容忍數分鐘的數據丟失,追求更快的啟動速度對數據安全性要求較高常見

四、Redis優化秒殺流程

1、秒殺步驟:

  1. 查詢優惠券;

  2. 判斷秒殺商品庫存;

  3. 查詢訂單

  4. 校驗一人一單;

  5. 減庫存;

  6. 創建訂單;

Redis分布式緩存與秒殺怎么實現

2、Redis優化秒殺步驟:

  1. 新增秒殺的優惠券,將優惠券信息保存到Redis中;

  2. 基于Lua腳本,判斷秒殺商品庫存,一人一單,決定用戶是否秒殺成功;

  3. 如果秒殺成功,將優惠券id、用戶id、商品id封裝到阻塞隊列中;

  4. 開啟異步任務,不斷從阻塞隊列中讀取信息,實現異步下單功能;

Redis分布式緩存與秒殺怎么實現

3、秒殺的lua腳本

Redis分布式緩存與秒殺怎么實現

 4、調用秒殺的lua腳本

public Result seckillVoucher(Long voucherId) {
     Long userId = UserHolder.getUser().getId();
     long orderId = redisIdWorker.nextId("order");
     // 1.執行lua腳本
     Long result = stringRedisTemplate.execute(
             SECKILL_SCRIPT,
             Collections.emptyList(),
             voucherId.toString(), userId.toString(), String.valueOf(orderId)
     );
     int r = result.intValue();
     // 2.判斷結果是否為0
     if (r != 0) {
         // 2.1.不為0 ,代表沒有購買資格
         return Result.fail(r == 1 ? "庫存不足" : "不能重復下單");
     }
     // 3.返回訂單id
     return Result.ok(orderId);
 }

5、通過線程池,操作阻塞隊列

// 線程池
private static final ExecutorService SECKILL_ORDER_EXECUTOR = Executors.newSingleThreadExecutor();

/**
* 在類初始化完成后執行
*/
@PostConstruct
private void init() {
    SECKILL_ORDER_EXECUTOR.submit(new VoucherOrderHandler());
}

// 阻塞隊列
private BlockingQueue<VoucherOrder> orderTasks = new ArrayBlockingQueue<>(1024 * 1024);
private class OrderHandler implements Runnable{

    @Override
    public void run() {
        while (true){
            try {
                doSomething();
            } catch (Exception e) {
                log.error("處理訂單異常", e);
            }
        }
    }
}

五、基于Redis實現共享session登錄

基于session實現登錄

Redis分布式緩存與秒殺怎么實現

基于Redis實現共享session登錄

public class RefreshTokenInterceptor implements HandlerInterceptor {

    private StringRedisTemplate stringRedisTemplate;

    public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1、獲取請求頭中的token
        String token = request.getHeader("authorization");
        if (StrUtil.isBlank(token)) {
            return true;
        }
        // 2、基于TOKEN獲取redis中的用戶
        String key  = LOGIN_USER_KEY + token;
        Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);
        // 3、判斷用戶是否存在
        if (userMap.isEmpty()) {
            return true;
        }
        // 5、將查詢到的hash數據轉為UserDTO
        UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
        // 6、存在,保存用戶信息到 ThreadLocal
        UserHolder.saveUser(userDTO);
        // 7、刷新token有效期
        stringRedisTemplate.expire(key, LOGIN_USER_TTL, TimeUnit.MINUTES);
        // 8、放行
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 移除用戶
        UserHolder.removeUser();
    }
}

Redis分布式緩存與秒殺怎么實現

“Redis分布式緩存與秒殺怎么實現”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

深水埗区| 色达县| 广元市| 武鸣县| 新巴尔虎右旗| 五寨县| 西平县| 儋州市| 江北区| 博兴县| 安福县| 泰和县| 专栏| 通州区| 盐城市| 安多县| 沾化县| 兰西县| 镇原县| 南京市| 麻栗坡县| 扶沟县| 自治县| 东阿县| 凌云县| 通辽市| 宜阳县| 仪陇县| 霍林郭勒市| 文安县| 桃江县| 鲁甸县| 石家庄市| 赤峰市| 富蕴县| 斗六市| 中西区| 贵南县| 平塘县| 依安县| 小金县|