it_lv 3 settimane fa
parent
commit
031f2e9780
1 ha cambiato i file con 88 aggiunte e 55 eliminazioni
  1. 88 55
      第6章 详情优化.md

+ 88 - 55
第6章 详情优化.md

@@ -715,50 +715,57 @@ ln: 自然对数是以常数e为[底数](https://baike.baidu.com/item/底数/541
 
 ## 3.2 初始化布隆过滤器
 
-在`service-search` 模块的启动类中添加
+在`service-album` 模块的启动类中添加
 
 ```java
 package com.atguigu.tingshu;
 
 import com.atguigu.tingshu.common.constant.RedisConstant;
+import jakarta.annotation.PostConstruct;
+import lombok.extern.slf4j.Slf4j;
 import org.redisson.api.RBloomFilter;
 import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.CommandLineRunner;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 import org.springframework.cloud.openfeign.EnableFeignClients;
-import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
 
-@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)//取消数据源自动配置
+@Slf4j
+@SpringBootApplication
 @EnableDiscoveryClient
-@EnableFeignClients//(basePackages = {"a","b"})  //确保能够扫描到依赖中OpenFeign接口
-@EnableAsync
-public class ServiceSearchApplication implements CommandLineRunner {
+@EnableFeignClients
+@EnableScheduling //开启定时任务
+public class ServiceAlbumApplication implements CommandLineRunner {
 
     public static void main(String[] args) {
-        SpringApplication.run(ServiceSearchApplication.class, args);
+        SpringApplication.run(ServiceAlbumApplication.class, args);
     }
 
     @Autowired
     private RedissonClient redissonClient;
 
+    @PostConstruct
+    public void initBloomFilter() {
+        log.info("模拟初始化布隆过滤器开始...");
+    }
+
     /**
-     * 当springboot应用启动成功后执行
-     *
-     * @param args incoming main method arguments
-     * @throws Exception
+     * springboot启动后自动执行一次该方法
+     * 项目启动后自动初始化布隆过滤器
      */
     @Override
     public void run(String... args) throws Exception {
-        //初始化布隆过滤器
+        //1.创建/获取布隆过滤器对象
         RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
-        //判断布隆过滤器是否存在
-        if (!bloomFilter.isExists()) {
-            //通过数据规模+误判率进行初始化布隆过滤器
-            bloomFilter.tryInit(100000, 0.03);
+        //2.判断过滤过滤器是否存在
+        boolean exists = bloomFilter.isExists();
+        log.info("布隆过滤器是否存在:{}", exists);
+        if (!exists) {
+            boolean flag = bloomFilter.tryInit(10000L, 0.03);
+            log.info("初始化布隆过滤器,完成结果:{}", flag);
         }
     }
 }
@@ -780,10 +787,11 @@ private RedissonClient redissonClient;
 @Override
 public void upperAlbum(Long albumId) {
     //....省略代码
-    //将新增的商品SKUID存入布隆过滤器
-    //获取布隆过滤器,将新增skuID存入布隆过滤器
+    //9.将专辑ID存入布隆过滤器
     RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
-    bloomFilter.add(albumInfo.getId());
+    if(bloomFilter.isExists()){
+        bloomFilter.add(albumId);
+    }
 }
 ```
 
@@ -803,11 +811,11 @@ private RedissonClient redissonClient;
  */
 @Override
 public Map<String, Object> getAlbumItem(Long albumId) {
-    //0.查询布隆过滤器是否包含查询专辑ID
+    //0.采用布隆过滤器解决缓存穿透问题
     RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
-    boolean flag = bloomFilter.contains(albumId);
-    if (!flag) {
-        throw new GuiguException(404, "访问专辑不存在");
+    boolean contains = bloomFilter.contains(albumId);
+    if(!contains){
+        throw new GuiguException(404, "专辑不存在");
     }
     //.....省略代码
 }
@@ -818,11 +826,11 @@ public Map<String, Object> getAlbumItem(Long albumId) {
 采用定时任务机制进行布隆过滤器扩容
 
 ```java
-package com.atguigu.tingshu.album.job;
+package com.atguigu.tingshu.album.task;
 
-import cn.hutool.core.collection.CollectionUtil;
-import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
+import com.atguigu.tingshu.album.service.AlbumInfoService;
 import com.atguigu.tingshu.common.constant.RedisConstant;
+import com.atguigu.tingshu.common.constant.SystemConstant;
 import com.atguigu.tingshu.model.album.AlbumInfo;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import lombok.extern.slf4j.Slf4j;
@@ -836,47 +844,72 @@ import java.util.List;
 
 /**
  * @author: atguigu
- * @create: 2024-08-17 14:10
+ * @create: 2025-06-11 10:19
  */
 @Slf4j
 @Component
-public class RebuildBloomFilter {
+public class RebuildBloomFilterTask {
+
 
     @Autowired
     private RedissonClient redissonClient;
 
     @Autowired
-    private AlbumInfoMapper albumInfoMapper;
+    private AlbumInfoService albumInfoService;
 
     /**
-     * 每月1号凌晨3点整重建布隆过滤器 cron表达式:0 0 3 * * ?
-     * 测试每隔10s进行一次扩容
+     * 公告:每月1号凌晨2~3点项目维护,避免数据不一致
+     * 每月1号2点:重建布隆过滤器
      */
-    @Scheduled(cron = "0 0 3 * * ?")
+    @Scheduled(cron = "0 0 2 1 * ?")
+    //@Scheduled(cron = "0/5 * * * * ?")
     public void rebuildBloomFilter() {
-        log.info("重建布隆过滤器定时任务执行");
-        //1.获取"旧"的布隆过滤器-获取现有数据量
+        //1.获取现有布隆过滤器对象,得到配置信息:1.期望数据规模  2.误判率 3.现有元素数量(预估值)
         RBloomFilter<Long> oldBloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
-        //2.判断是否需要进行扩容,扩容条件:现有数量>期望数据规模
-        if (oldBloomFilter.count() >= oldBloomFilter.getExpectedInsertions()) {
-            //2.1 创建"新"的布隆过滤器完成初始化
+        long expectedInsertions = oldBloomFilter.getExpectedInsertions();
+        double falseProbability = oldBloomFilter.getFalseProbability();
+        long count = oldBloomFilter.count();
+        //2.判断是否满足扩容条件:现有元素数量大于等于期望数据规模
+        if (count >= expectedInsertions) {
+            log.info("满足扩容条件,开始扩容重建...");
+            //2.1 先初始化新的布隆过滤器,原有期望数据规模*2
             RBloomFilter<Long> newBloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER + ":new");
-            newBloomFilter.tryInit(oldBloomFilter.getExpectedInsertions() * 2, oldBloomFilter.getFalseProbability());
-            //2.2 删除"旧"的布隆过滤器
-            oldBloomFilter.delete();
-            //2.3 再对新的布隆进行重命名:改回旧的名称
-            newBloomFilter.rename(RedisConstant.ALBUM_BLOOM_FILTER);
-            //3.查询专辑表得到最新库中审核通过的专辑ID列表
-            LambdaQueryWrapper<AlbumInfo> queryWrapper = new LambdaQueryWrapper<>();
-            queryWrapper.eq(AlbumInfo::getStatus, "0301");
-            queryWrapper.select(AlbumInfo::getId);
-            List<AlbumInfo> albumInfoList = albumInfoMapper.selectList(queryWrapper);
-            //4.将专辑ID加入到"新"的布隆过滤器
-            if (CollectionUtil.isNotEmpty(albumInfoList)) {
-                for (AlbumInfo albumInfo : albumInfoList) {
+            if (!newBloomFilter.isExists()) {
+                newBloomFilter.tryInit(expectedInsertions * 2, falseProbability);
+                //2.2 将数据中先有合法专辑ID加入到新的布隆过滤器中
+                List<AlbumInfo> list = albumInfoService.list(
+                        new LambdaQueryWrapper<AlbumInfo>()
+                                .eq(AlbumInfo::getStatus, SystemConstant.ALBUM_STATUS_PASS)
+                                .select(AlbumInfo::getId)
+                );
+                for (AlbumInfo albumInfo : list) {
                     newBloomFilter.add(albumInfo.getId());
                 }
+                //2.3 删除旧的布隆过滤器:布隆过滤器配置及位图
+                oldBloomFilter.delete();
+                //2.4 重命名布隆过滤器,改为原来名称
+                newBloomFilter.rename(RedisConstant.ALBUM_BLOOM_FILTER);
             }
+        } else {
+            log.info("不满足扩容条件,开始重建...");
+            //3.不满足扩容条件,做基本重建:  1.初始化布隆过滤器 2.将数据中先有合法专辑ID加入到布隆过滤器中 3.重命名布隆过滤器,改为原来名称 4.删除旧的布隆过滤器
+            //3.1 先初始化新的布隆过滤器
+            RBloomFilter<Long> newBloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER + ":new");
+            newBloomFilter.tryInit(expectedInsertions, falseProbability);
+            //3.2 将数据中先有合法专辑ID加入到新的布隆过滤器中
+            List<AlbumInfo> list = albumInfoService.list(
+                    new LambdaQueryWrapper<AlbumInfo>()
+                            .eq(AlbumInfo::getStatus, SystemConstant.ALBUM_STATUS_PASS)
+                            .select(AlbumInfo::getId)
+            );
+            for (AlbumInfo albumInfo : list) {
+                newBloomFilter.add(albumInfo.getId());
+            }
+            //3.3 删除旧的布隆过滤器:布隆过滤器配置及位图
+            oldBloomFilter.delete();
+            //3.4 重命名布隆过滤器,改为原来名称
+            newBloomFilter.rename(RedisConstant.ALBUM_BLOOM_FILTER);
+            log.info("布隆过滤器重建完成...");
         }
     }
 }
@@ -1066,7 +1099,7 @@ FLUSH PRIVILEGES;
    > -e canal.instance.filter.regex=.*\\..*  代表监控所有数据库表变更的日志
 
    ```shell
-   docker run -p 11111:11111 --name canal \
+   docker run -p 11113:11111 --name canal1.5 \
    -e canal.destinations=tingshuTopic \
    -e canal.instance.master.address=192.168.200.6:3306  \
    -e canal.instance.dbUsername=canal  \
@@ -1074,8 +1107,8 @@ FLUSH PRIVILEGES;
    -e canal.instance.connectionCharset=UTF-8 \
    -e canal.instance.tsdb.enable=true \
    -e canal.instance.gtidon=false  \
-   -e canal.instance.filter.regex=^tingshu_.*\\..* \
-   -d canal/canal-server:v1.1.8
+   -e canal.instance.filter.regex=.*\\..* \
+   -d canal/canal-server:v1.1.5
    ```
 
 4. 删除容器,重新创建canal容器,促使canal重新跟MySQL建立连接,从MySQL最新BinLog偏移量开始读取数据
@@ -1154,7 +1187,7 @@ FLUSH PRIVILEGES;
 
 3. 在Nacos创建配置文件`service-canal-dev.yaml` 内容如下:
 
-    ![image-20250321170122534](assets/image-20250321170122534.png)
+     ![image-20250321170122534](assets/image-20250321170122534.png)
 
    ```yaml
    server: