redis百万级数据量预热方案

一、需求描述

项目中需要查询用户对应的地市信息,这些数据是存储在mysql数据库中,并且数据量是百万级别,查询频率高,所以想将需要查询的字段存储到redis中,来提高查询速度

二、需求分析

对redis数据预热,一般思路就通过mysql将数据查询出来,然后遍历存储到redis中。

注意点:

1、因为数据量大,不要直接将所有数据查询出来然后遍历存储,因为大数据量数据全部缓存在服务器内存中会导致内存溢出报错;
解决方式: 分页读取数据,循环遍历直到最后一页

以下是分页读取和数据存储代码

java 复制代码
int i=0;
while (true){
    String sql =" select userid,CITYCODE from tb_tc_orderuser_bycity limit "+i+",5000";
    List<Tcorderinfo> datalist = new ArrayList<>();
    try {
        datalist = jdbcTemplate.query(sql, Tcorderinfo.class);
        if (datalist!=null && datalist.size() >0){
            i=i+datalist.size();
        }else {
            break;
        }
    } catch (Exception e) {
        logger.error("查询用户的数据失败");
    }
    for (Tcorderinfo one : datalist) {
        stringRedisTemplate.opsForValue().set("userCity:"+one.getUserid(),one.getCitycode());
    }
    logger.info("已存入{}数据",i);
    datalist.clear();
}

上述方式是通过stringRedisTemplate.opsForValue().set方法将数据一条条插入redis中的。

虽然能正常执行了,但是一条条的存储到redis中是相当耗时的,统计了一下,一分钟只能存储500左右的数据量,显然不可行
优化方案 :

redis中有一个叫管道的概念,简单概括,就是可以数据先存储到管道中,然后一起推到redis缓存中,这样可以大大提高存储效率

java 复制代码
int i=0;
while (true){
    String sql =" select userid,CITYCODE from tb_tc_orderuser_bycity limit "+i+",5000";
    List<Tcorderinfo> datalist = new ArrayList<>();
    try {
        datalist = jdbcTemplate.query(sql, Tcorderinfo.class);
        if (datalist!=null && datalist.size() >0){
            i=i+datalist.size();
        }else {
            break;
        }
    } catch (Exception e) {
        logger.error("查询用户的数据失败");
    }
    for (Tcorderinfo one : datalist) {
        batchStoreStringsUsingConnection(datalist);
    }
    logger.info("已存入{}数据",i);
    datalist.clear();
}
java 复制代码
public void batchStoreStringsUsingConnection(List<Tcorderinfo> datalist) {
        stringRedisTemplate.executePipelined((RedisCallback<Void>) connection -> {
            RedisSerializer<String> stringSerializer = stringRedisTemplate.getStringSerializer();

            for (Tcorderinfo one : datalist) {
                String key = "userCity:"+one.getUserid();
                String value = one.getCitycode();

                connection.set(stringSerializer.serialize(key), stringSerializer.serialize(value));
            }

            return null;
        });
    }

将存储方式改为管道存储,分页大小设置为50000,10秒能执行一次循环,也就是10秒能向redis存储5w数据,十分钟可以存储百万数据量,可实现redis数据预热。

相关推荐
余槐i4 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
数据库小学妹4 小时前
PostgreSQL表膨胀怎么办?autovacuum清不动的根因与排查命令
数据库·postgresql·表膨胀·mvcc·数据库运维
mister_guo4 小时前
MySQL-1267错误:排序规则冲突的原因与解决方案
数据库·mysql
骇客野人5 小时前
在麒麟操作系统上 分别安装 jdk1.8, 达梦数据库,redis ,memcache 的操作实施方案和步骤
数据库·redis·memcached
美狐美颜SDK开放平台6 小时前
直播APP如何实现美白滤镜功能?视频美颜SDK技术开发方案详解
前端·数据库·人工智能·音视频·美颜sdk·直播美颜sdk·视频美颜sdk
silvamux_7 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi
花间相见8 小时前
【计算基础|MySQL01】【上手】安装连接、数据类型与建库建表
数据库·后端
花间相见8 小时前
【计算基础|MySQL02】【上手】SQL 增删改查
数据库·后端
ITxiaobing20238 小时前
IP 库与 AppsFlyer 国家/地区数据不一致,如何系统地对账?
数据库·网络协议·tcp/ip
.Bryce.8 小时前
在智能体中使用A2A工具:让大模型自己决定“该找谁帮忙“
android·java·服务器·redis·后端·agent·a2a