Teknologian jakaminen

välimuisti - välimuisti käyttää 2

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1. Välimuistin hajoaminen, tunkeutuminen, lumivyöry

1. Välimuistin tunkeutuminen

Viittaa tietojen, joita ei saa olla, kyselyyn Koska välimuistiin ei osu, tietokannasta kysytään, mutta tietokannassa ei ole tällaista tietuetta. Emme kirjoittaneet tämän kyselyn tyhjää arvoa välimuistiin jokaisessa pyynnössä näitä olemattomia tietoja varten sinun on mentävä tallennuskerrokseen kyselyä varten, mikä menettää välimuistin merkityksen.

riski:

Olemattomien tietojen käyttäminen hyökkäyksiin lisää tietokantaan kohdistuvaa välitöntä painetta ja johtaa lopulta romahtamiseen.

ratkaista:

Nollatulos tallennetaan välimuistiin ja siihen lisätään lyhyt vanhenemisaika.

2. Välimuistin lumivyöry

Välimuistivyöry: Välimuistin lumivyöry tarkoittaa, että kun asetamme välimuistin, avain ottaa käyttöön saman vanhenemisajan, jolloin välimuisti lakkaa tietyllä hetkellä, kaikki pyynnöt välitetään tietokantaan ja tietokanta on välittömän paineen ja lumivyöryjen alla.

Ratkaisu: Lisää alkuperäiseen vanhenemisaikaan satunnainen arvo, kuten 1–5 minuuttia satunnaisesti, jotta kunkin välimuistissa olevan vanhenemisajan toistotiheys vähenee, mikä vaikeuttaa kollektiivisten virhetapahtumien aiheuttamista.

3. Välimuistin erittely

Välimuistin erittely:

  • Joillekin avaimille, joille on asetettu vanhenemisaika, jos näitä avaimia voidaan käyttää hyvin samanaikaisesti tiettyinä aikoina, se on erittäin "kuumaa" dataa.
  • Jos tämä hotspot-avain vanhenee juuri ennen kuin suuri määrä pyyntöjä tulee samaan aikaan, kaikki tätä avainta koskevat tietokyselyt siirtyvät tietokantaan, jota kutsutaan välimuistin erittelyksi.

ratkaista:

Lukko

Suuri määrä samanaikaisuutta sallii vain yhden tarkistaa, ja muut odottavat Tarkistuksen jälkeen lukko vapautetaan, ja muut hankkivat lukon, vievät hiiri, tarkistavat ensin välimuistin, niin dataa tulee ilman siirtymistä db:iin.

2. Ratkaise ongelma

Ratkaise ensin välimuistin tunkeutuminen ja lumivyöry

  1. private static final String CATALOG_JSON="CATALOG_JSON";
  2. @Override
  3. public Map<String, List<Catelog2Vo>> getCatalogJson() {
  4. /**
  5. * 空结果缓存:解决缓存穿透
  6. * 设置过期时间(加随机值) 缓存雪崩
  7. * 加锁 解决缓存击穿
  8. */
  9. Object result = redisTemplate.opsForValue().get(CATALOG_JSON);
  10. if(result!=null){
  11. return (Map<String, List<Catelog2Vo>>) result;
  12. }
  13. Map<String, List<Catelog2Vo>> map = getCatalogJsonFromDB();
  14. if (map==null){
  15. /**
  16. * 解决缓存穿透
  17. */
  18. map=new HashMap<>();
  19. }
  20. redisTemplate.opsForValue().set(CATALOG_JSON,map, Duration.ofDays(1));
  21. return map;
  22. }

Ratkaise välimuistin erittely

1. Käytä paikallista lukitusta ratkaistaksesi

Springboot-säilöobjekti on oletuksena singleton-tilassa, joten sama objekti voidaan synkronoida ja lukita Kun käytetään kaksoistunnistustilaa, se voidaan suorittaa samanaikaisesti.

  1. public synchronized Map<String, List<Catelog2Vo>> getCatalogJsonFromDB() {
  2. Object result = redisTemplate.opsForValue().get(CATALOG_JSON);
  3. if (result != null) {
  4. return (Map<String, List<Catelog2Vo>>) result;
  5. }
  6. //1.查出所有1级分类
  7. List<CategoryEntity> selectList = baseMapper.selectList(null);
  8. /**
  9. * 将数据库的多次查询变成一次
  10. */
  11. //2. 封装数据
  12. List<CategoryEntity> level1Category = selectList.stream().filter(s -> s.getParentCid().equals(0L)).collect(Collectors.toList());
  13. Map<String, List<Catelog2Vo>> map = level1Category.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
  14. //1.每一个的一级分类,查到1级分类的所有二级分类
  15. List<CategoryEntity> categoryEntities = selectList.stream().filter(s -> s.getParentCid().equals(v.getCatId())).collect(Collectors.toList());
  16. List<Catelog2Vo> catelog2VoList = categoryEntities.stream().map(c -> {
  17. Catelog2Vo catelog2Vo = new Catelog2Vo();
  18. catelog2Vo.setId(c.getCatId().toString());
  19. catelog2Vo.setName(c.getName());
  20. catelog2Vo.setCatalog1Id(v.getCatId().toString());
  21. List<CategoryEntity> categoryEntities1 = selectList.stream().filter(s -> s.getParentCid().equals(c.getCatId())).collect(Collectors.toList());
  22. List<Catelog2Vo.Catelog3Vo> collect = categoryEntities1.stream().map(c3 -> {
  23. Catelog2Vo.Catelog3Vo catelog3Vo = new Catelog2Vo.Catelog3Vo();
  24. catelog3Vo.setId(c3.getCatId().toString());
  25. catelog3Vo.setName(c3.getName());
  26. catelog3Vo.setCatalog2Id(c.getCatId().toString());
  27. return catelog3Vo;
  28. }).collect(Collectors.toList());
  29. catelog2Vo.setCatalog3List(collect);
  30. return catelog2Vo;
  31. }).collect(Collectors.toList());
  32. return catelog2VoList;
  33. }));
  34. return map;
  35. }
  1. public Map<String, List<Catelog2Vo>> getCatalogJson() {
  2. /**
  3. * 空结果缓存:解决缓存穿透
  4. * 设置过期时间(加随机值) 缓存雪崩
  5. * 加锁 解决缓存击穿
  6. */
  7. Object result = redisTemplate.opsForValue().get(CATALOG_JSON);
  8. if (result != null) {
  9. return (Map<String, List<Catelog2Vo>>) result;
  10. }
  11. Map<String, List<Catelog2Vo>> map = getCatalogJsonFromDB();
  12. if (map == null) {
  13. /**
  14. * 解决缓存穿透
  15. */
  16. map = new HashMap<>();
  17. }
  18. redisTemplate.opsForValue().set(CATALOG_JSON, map, Duration.ofDays(1));
  19. return map;
  20. }

Yllä olevan koodin logiikassa esiintyy edelleen ongelmia Samanaikaisesti suoritettaessa säie nro 1 suorittaa tietokannan tarkistuksen ja vapauttaa lukituksen ennen kuin se asetetaan välimuistiin ei ole mitään takeita siitä, että tietokannassa on vain yksi säie

Oikea lähestymistapa

  1. public synchronized Map<String, List<Catelog2Vo>> getCatalogJsonFromDB() {
  2. Object result = redisTemplate.opsForValue().get(CATALOG_JSON);
  3. if (result != null) {
  4. return (Map<String, List<Catelog2Vo>>) result;
  5. }
  6. //1.查出所有1级分类
  7. List<CategoryEntity> selectList = baseMapper.selectList(null);
  8. /**
  9. * 将数据库的多次查询变成一次
  10. */
  11. //2. 封装数据
  12. List<CategoryEntity> level1Category = selectList.stream().filter(s -> s.getParentCid().equals(0L)).collect(Collectors.toList());
  13. Map<String, List<Catelog2Vo>> map = level1Category.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
  14. //1.每一个的一级分类,查到1级分类的所有二级分类
  15. List<CategoryEntity> categoryEntities = selectList.stream().filter(s -> s.getParentCid().equals(v.getCatId())).collect(Collectors.toList());
  16. List<Catelog2Vo> catelog2VoList = categoryEntities.stream().map(c -> {
  17. Catelog2Vo catelog2Vo = new Catelog2Vo();
  18. catelog2Vo.setId(c.getCatId().toString());
  19. catelog2Vo.setName(c.getName());
  20. catelog2Vo.setCatalog1Id(v.getCatId().toString());
  21. List<CategoryEntity> categoryEntities1 = selectList.stream().filter(s -> s.getParentCid().equals(c.getCatId())).collect(Collectors.toList());
  22. List<Catelog2Vo.Catelog3Vo> collect = categoryEntities1.stream().map(c3 -> {
  23. Catelog2Vo.Catelog3Vo catelog3Vo = new Catelog2Vo.Catelog3Vo();
  24. catelog3Vo.setId(c3.getCatId().toString());
  25. catelog3Vo.setName(c3.getName());
  26. catelog3Vo.setCatalog2Id(c.getCatId().toString());
  27. return catelog3Vo;
  28. }).collect(Collectors.toList());
  29. catelog2Vo.setCatalog3List(collect);
  30. return catelog2Vo;
  31. }).collect(Collectors.toList());
  32. return catelog2VoList;
  33. }));
  34. if (map == null) {
  35. /**
  36. * 解决缓存穿透
  37. */
  38. map = new HashMap<>();
  39. }
  40. redisTemplate.opsForValue().set(CATALOG_JSON, map, Duration.ofDays(1));
  41. return map;
  42. }

Aseta välimuistiin tallennustoiminto synkronointikoodilohkoon

  1. @Override
  2. public Map<String, List<Catelog2Vo>> getCatalogJson() {
  3. /**
  4. * 空结果缓存:解决缓存穿透
  5. * 设置过期时间(加随机值) 缓存雪崩
  6. * 加锁 解决缓存击穿
  7. */
  8. Object result = redisTemplate.opsForValue().get(CATALOG_JSON);
  9. if (result != null) {
  10. return (Map<String, List<Catelog2Vo>>) result;
  11. }
  12. Map<String, List<Catelog2Vo>> map = getCatalogJsonFromDB();
  13. return map;
  14. }

 

 

Paikalliset lukot voivat lukita vain nykyisen prosessin, joten tarvitsemme hajautettuja lukkoja

3. Ongelmia paikallisten lukkojen kanssa hajautetuissa ympäristöissä

Eli jokainen lukko voi lukita vain nykyisen prosessin, eli jokainen palvelu tarkistaa tietokannan.