Différent de la pénétration du cache, la panne du cache fait référence aux données chaudes qui ne sont pas dans le cache mais existent dans la base de données.
Par exemple : actualités brûlantes sur la page d'accueil, données brûlantes avec un très grand nombre de visites simultanées, si le cache expire, le serveur interrogera la base de données à ce moment-là, si un grand nombre de requêtes simultanées sont effectuées sur la base de données. , la base de données peut être submergée instantanément.
Dessiné un schéma simple, comme indiqué ci-dessous :
Solution : Requête DB plus verrouillage distribué.
Avant de résoudre le problème, jetez d'abord un œil au code et à l'état de fonctionnement du code non traité.
Interrogez le code des détails du produit en fonction de l'ID du produit
Videz le cache Redis, ouvrez 5 threads pour les tests d'accès simultané, le code de test est le suivant :
Nous nous attendons à ce que la base de données ne sera interrogé qu'une seule fois, et les 4 suivantes. La requête peut être récupérée à partir du cache Redis, mais le résultat est :
Aucun verrou distribué n'est ajouté. Le résultat est également attendu, mais ce conteneur met beaucoup de pression sur le. BD.
S'il s'agit d'un serveur unique, utilisez simplement le verrou de synchronisation de Java directement
Malheureusement, le backend déploie généralement un cluster et le verrou de synchronisation de Java ne peut pas implémenter de verrous distribués.
Le verrouillage distribué Redis résout les pannes de cache
Le verrouillage intégré de Java ne peut être appliqué que sur une seule machine et ne peut pas être distribué Vous pouvez utiliser Redis pour implémenter le verrouillage distribué.
Code après l'ajout du verrouillage distribué
//根据ID查询商品 @GetMapping("/{id}") public R id(@PathVariable String id){ //先查Redis缓存 Object o = redisTemplate.opsForValue().get(id); if (o != null) { //命中缓存 System.err.println("id:"+id+",命中redis缓存..."); return R.success(o); } //缓存未命中 查询数据库 String lockKey = "lock" + id; //加锁,10s后过期 for (;;) { if (redisTemplate.opsForValue().setIfAbsent(lockKey, System.currentTimeMillis(), 10L, TimeUnit.SECONDS)) { //加锁成功的线程,再次检查 o = redisTemplate.opsForValue().get(id); if (o != null) { //命中缓存 System.err.println("Thread:" + Thread.currentThread().getName() + ",id:"+id+",命中redis缓存..."); //释放锁 redisTemplate.delete(lockKey); return R.success(o); } //仍未命中 System.err.println("Thread:" + Thread.currentThread().getName() + ",id:" + id + ",查询DB..."); Goods goods = goodsMapper.selectById(id); //结果存入Redis redisTemplate.opsForValue().set(id, goods); //释放锁 redisTemplate.delete(lockKey); return R.success(goods); } //竞争不到锁,暂时让出CPU资源 Thread.yield(); } }
Démarrez 5 threads pour un accès simultané. Le résultat est le suivant :
.Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!