Redis インベントリ削減の主な目的は、データベースへのアクセスを削減することです。以前のインベントリ削減では、データベースに直接アクセスしてインベントリを読み取りました。同時に高いリクエストが来ると、大量の読み取りデータによってデータベースが崩壊する可能性があります。
システムが初期化されると、製品インベントリが Redis キャッシュにロードされて保存されます。
リクエストを受信すると、まずRedis上で商品の在庫金額を取得し、事前に在庫を削減し、削減後に在庫が不足した場合は、論理的な例外を直接返します。アクセスなしでデータベースが在庫を削減します。在庫値が正しい場合は、次のステップに進みます。
リクエストをキューに入れ、すぐにフロントエンドに値を返し、リクエストがキューに入れられていることを示し、フラッシュ強制終了ロジックを実行します。バックエンド キューはフラッシュ強制終了ロジックを実行し、フロントエンドはバックエンドによって送信されたリクエストをポーリングし、フラッシュキルが成功した場合はフラッシュキル、成功を返し、それ以外の場合は失敗を返します。
/** * 秒杀接口优化之--- 第一步: 系统初始化后就将所有商品库存放入 缓存 */ @Override public void afterPropertiesSet() throws Exception { List<GoodsVo> goods = goodsService.getGoodsList(); if (goods == null) { return; } for (GoodsVo goodsVo : goods) { redisService.set(GoodsKey.getId(), goodsVo.getStockCount()); isOverMap.put(goodsVo.getId(), false);//先初始化 每个商品都是false 就是还有 } }
/**秒杀接口优化之 ----第二步: 预减库存 从缓存中减库存 * 利用 redis 中的方法,减去库存,返回值为 减去1 之后的值 * */ long stock = redisService.decr(GoodsKey.getGoodsStock, "" + goodsId); /*这里判断不能小于等于,因为减去之后等于 说明还有是正常范围*/ if (stock < 0) { isOverMap.put(goodsId, true);//没有库存就设置 对应id 商品的map 为true return Result.error(CodeMsg.MIAO_SHA_NO_STOCK); }
全体的なロジックは次のとおりです:
1. まずすべてのデータを読み出し、それをキャッシュに初期化し、ストック Goodid の形式で Redis に保存します。
2. フラッシュセール中は、まず削減前の在庫検出を実行し、decrを使用して該当商品の在庫をredisから差し引きます。在庫が0未満の場合は、在庫が不足していることを意味します現時点ではデータベースにアクセスする必要はありません。例外を直接スローするだけです。
上記ではメモリマークである isOverMap も使用しました。
インターフェイスの最適化により、同時実行性が高い場合、Redis に基づく多くのキャッシュ操作も Redis サーバーに大きな負荷をもたらします。削減されると、Access の最適化効果も達成できます。
そこで、該当製品の在庫がまだあるかどうかを示すメモリマップを追加することで、Redisにアクセスする前にマップ上で該当製品の在庫マークを取得することができ、在庫有無を判断することができます。 Redis にアクセスしています。在庫がありません。
1. マップを生成し、初期化中にすべての製品の ID をキーとして使用し、false をマークしてマップに保存します。
private Map<Long, Boolean> isOverMap = new HashMap<Long, Boolean>(); /** * 秒杀接口优化之--- 第一步: 系统初始化后就将所有商品库存放入 缓存 */ @Override public void afterPropertiesSet() throws Exception { List<GoodsVo> goods = goodsService.getGoodsList(); if (goods == null) { return; } for (GoodsVo goodsVo : goods) { redisService.set(GoodsKey.getGoodsStock, "" + goodsVo.getId(), goodsVo.getStockCount()); isOverMap.put(goodsVo.getId(), false);//先初始化 每个商品都是false 就是还有 } }
/**再优化: 优化 库存之后的请求不访问redis 通过判断 对应 map 的值 * */ boolean isOver = isOverMap.get(goodsId); if (isOver) { return Result.error(CodeMsg.MIAO_SHA_NO_STOCK); } if (stock < 0) { isOverMap.put(goodsId, true);//没有库存就设置 对应id 商品的map 为true }
2. 在庫を事前に減らす前に、マップからマークを取得し、マークが偽の場合は在庫を意味します
在庫が不足している場合は、製品の在庫を減らします前に進み、true としてマークします。製品が在庫切れであることを示します。以下のリクエストはすべてインターセプトされるため、事前に在庫を削減するために Redis にアクセスする必要はありません。
したがって、キャッシュを使用する全体的な考え方は次のとおりです。
製品の在庫データをメモリにロードし、同時にメモリ タグを初期化します。つまり、マップ内の各製品の ID は、各フラッシュ セール ロジックを実行する前に false に初期化され、メモリ マークで値が取得されます。在庫がまだある場合、つまりマップが false を返す場合、フラッシュはsale ロジックが実行されます。それ以外の場合は、例外が直接スローされます。
在庫を同時に差し引く場合、キャッシュ内の在庫数量がまだ 0 より大きいかどうかを判断する必要があります。0 以下の場合は、メモリ マークを変更します。
以上が在庫削減のフラッシュセールシナリオをredisで実現する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。