欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Redis Caffeine實(shí)現(xiàn)兩級(jí)緩存的項(xiàng)目實(shí)踐

 更新時(shí)間:2024年12月27日 11:26:19   作者:YAnalytics  
本文介紹了使用Redis和Caffeine實(shí)現(xiàn)兩級(jí)緩存,以提高查詢(xún)接口的性能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

背景

? 事情的開(kāi)始是這樣的,前段時(shí)間接了個(gè)需求,給公司的商城官網(wǎng)提供一個(gè)查詢(xún)預(yù)計(jì)送達(dá)時(shí)間的接口。接口很簡(jiǎn)單,根據(jù)請(qǐng)求傳的城市+倉(cāng)庫(kù)+發(fā)貨時(shí)間查詢(xún)快遞的預(yù)計(jì)送達(dá)時(shí)間。因?yàn)樯坛窍聠尉蜁?huì)調(diào)用這個(gè)接口,所以對(duì)接口的性能要求還是挺高的,據(jù)老員工的說(shuō)法是特別是大促的時(shí)候,訪(fǎng)問(wèn)量還是比較大的。

? 因?yàn)閿?shù)據(jù)量不是很大,每天會(huì)全量推今天和明天的預(yù)計(jì)送達(dá)時(shí)間到MySQL,總數(shù)據(jù)量大約7k+。每次推完數(shù)據(jù)后會(huì)把數(shù)據(jù)全量寫(xiě)入到redis中,做一個(gè)緩存預(yù)熱,然后設(shè)置過(guò)期時(shí)間為1天。

? 鑒于之前Redis集群出現(xiàn)過(guò)壓力過(guò)大查詢(xún)緩慢的情況,進(jìn)一步保證接口的高性能和高可用,防止redis出現(xiàn)壓力大,查詢(xún)慢,緩存雪崩,緩存穿透等問(wèn)題,我們最終采用了Reids + Caffeine兩級(jí)緩存的策略。

本地緩存優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

  • 本地緩存,基于本地內(nèi)存,查詢(xún)速度是很快的。適用于:實(shí)時(shí)性要求不高,更新頻率不高等場(chǎng)景。(我們的數(shù)據(jù)每天凌晨更新一次,總量7k左右)
  • 查詢(xún)本地緩存與查詢(xún)遠(yuǎn)程緩存相比可以減少網(wǎng)絡(luò)的I/O,降低網(wǎng)絡(luò)上的一些消耗。(我們的redis之前出現(xiàn)過(guò)查詢(xún)緩慢的情況)

缺點(diǎn):

  • Caffeine既然是本地緩存,在分布式環(huán)境的情況下就要考慮各個(gè)節(jié)點(diǎn)之間緩存的一致性問(wèn)題,一個(gè)節(jié)點(diǎn)的本地緩存更新了,怎么可以同步到其他的節(jié)點(diǎn)。
  • Caffeine不支持持久化的存儲(chǔ)。
  • Caffeine使用本地內(nèi)存,需要合理設(shè)置大小,避免內(nèi)存溢出。

流程圖

在這里插入圖片描述

代碼實(shí)現(xiàn)

MySQL表

CREATE TABLE `t_estimated_arrival_date`  (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主鍵id',
  `warehouse_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '貨倉(cāng)id',
  `warehouse` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '發(fā)貨倉(cāng)',
  `city` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '簽收城市',
  `delivery_date` date NULL DEFAULT NULL COMMENT '發(fā)貨時(shí)間',
  `estimated_arrival_date` date NULL DEFAULT NULL COMMENT '預(yù)計(jì)到貨日期',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `uk_warehouse_id_city_delivery_date`(`warehouse_id`, `city`, `delivery_date`) USING BTREE
) ENGINE = InnoDB  COMMENT = '預(yù)計(jì)到貨時(shí)間表(具體到day:T, T+1,近90天到貨時(shí)間眾數(shù))' ROW_FORMAT = Dynamic;

INSERT INTO `t_estimated_arrival_date` VALUES (9, '6', '湖熟正常倉(cāng)', '蘭州市', '2024-07-08', '2024-07-10');
INSERT INTO `t_estimated_arrival_date` VALUES (10, '6', '湖熟正常倉(cāng)', '蘭州市', '2024-07-09', '2024-07-11');
INSERT INTO `t_estimated_arrival_date` VALUES (11, '6', '湖熟正常倉(cāng)', '興安盟', '2024-07-08', '2024-07-11');
INSERT INTO `t_estimated_arrival_date` VALUES (12, '6', '湖熟正常倉(cāng)', '興安盟', '2024-07-09', '2024-07-12');
INSERT INTO `t_estimated_arrival_date` VALUES (13, '6', '湖熟正常倉(cāng)', '其他', '2024-07-08', '2024-07-19');
INSERT INTO `t_estimated_arrival_date` VALUES (14, '6', '湖熟正常倉(cāng)', '其他', '2024-07-09', '2024-07-20');
INSERT INTO `t_estimated_arrival_date` VALUES (15, '6', '湖熟正常倉(cāng)', '內(nèi)江市', '2024-07-08', '2024-07-10');
INSERT INTO `t_estimated_arrival_date` VALUES (16, '6', '湖熟正常倉(cāng)', '內(nèi)江市', '2024-07-09', '2024-07-11');
INSERT INTO `t_estimated_arrival_date` VALUES (17, '6', '湖熟正常倉(cāng)', '涼山彝族自治州', '2024-07-08', '2024-07-11');
INSERT INTO `t_estimated_arrival_date` VALUES (18, '6', '湖熟正常倉(cāng)', '涼山彝族自治州', '2024-07-09', '2024-07-12');
INSERT INTO `t_estimated_arrival_date` VALUES (19, '6', '湖熟正常倉(cāng)', '包頭市', '2024-07-08', '2024-07-11');
INSERT INTO `t_estimated_arrival_date` VALUES (20, '6', '湖熟正常倉(cāng)', '包頭市', '2024-07-09', '2024-07-12');
INSERT INTO `t_estimated_arrival_date` VALUES (21, '6', '湖熟正常倉(cāng)', '北京城區(qū)', '2024-07-08', '2024-07-10');
INSERT INTO `t_estimated_arrival_date` VALUES (22, '6', '湖熟正常倉(cāng)', '北京城區(qū)', '2024-07-09', '2024-07-11');

pom.xm

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--redis連接池-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>

application.yml

server:
  port: 9001
spring:
  application:
    name: springboot-redis
  datasource:
    name: demo
    url: jdbc:mysql://localhost:3306/test?userUnicode=true&&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: 
    password: 
  # mybatis相關(guān)配置
  mybatis-plus:
    mapper-locations: classpath:mapper/*.xml
    configuration:
      cache-enabled: true
      use-generated-keys: true
      default-executor-type: REUSE
      use-actual-param-name: true
      # 打印日志
  #    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  redis:
    host: 192.168.117.73
    port: 6379
    password: root
#  redis:
#    lettuce:
#      cluster:
#        refresh:
#          adaptive: true
#          period: 10S
#      pool:
#        max-idle: 50
#        min-idle: 8
#        max-active: 100
#        max-wait: -1
#    timeout: 100000
#    cluster:
#      nodes:
#        - 192.168.117.73:6379
logging:
  level:
    com.itender.redis.mapper: debug


配置類(lèi)

  • RedisConfig
/**
 * @author yuanhewei
 * @date 2024/5/31 16:18
 * @description
 */
@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(connectionFactory);
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        serializer.setObjectMapper(mapper);
        // 如果不序列化在key value 使用redis客戶(hù)端工具 直連redis服務(wù)器 查看數(shù)據(jù)時(shí) 前面會(huì)有一個(gè) \xac\xed\x00\x05t\x00\x05 字符串
        // StringRedisSerializer 來(lái)序列化和反序列化 String 類(lèi)型 redis 的 key value
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(serializer);
        // StringRedisSerializer 來(lái)序列化和反序列化 hash 類(lèi)型 redis 的 key value
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(serializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}
  • CaffeineConfig
/**
 * @author yuanhewei
 * @date 2024/7/9 14:16
 * @description
 */
@Configuration
public class CaffeineConfig {

    /**
     * Caffeine 配置類(lèi)
     *  initialCapacity:初始緩存空間大小
     *  maximumSize:緩存的最大數(shù)量,設(shè)置這個(gè)值避免內(nèi)存溢出
     *  expireAfterWrite:指定緩存的過(guò)期時(shí)間,是最后一次寫(xiě)操作的一個(gè)時(shí)間
     *  容量的大小要根據(jù)自己的實(shí)際應(yīng)用場(chǎng)景設(shè)置
     *
     * @return
     */
    @Bean
    public Cache<String, Object> caffeineCache() {
        return Caffeine.newBuilder()
                // 初始大小
                .initialCapacity(128)
                //最大數(shù)量
                .maximumSize(1024)
                //過(guò)期時(shí)間
                .expireAfterWrite(60, TimeUnit.SECONDS)
                .build();
    }

    @Bean
    public CacheManager cacheManager(){
        CaffeineCacheManager cacheManager=new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
                .initialCapacity(128)
                .maximumSize(1024)
                .expireAfterWrite(60, TimeUnit.SECONDS));
        return cacheManager;
    }
}

Mapper

這里采用了Mybatis Plus

/**
 * @author yuanhewei
 * @date 2024/7/9 18:11
 * @description
 */
@Mapper
public interface EstimatedArrivalDateMapper extends BaseMapper<EstimatedArrivalDateEntity> {

} 

Service

/**
 * @author yuanhewei
 * @date 2024/7/9 14:25
 * @description
 */
public interface DoubleCacheService {

    /**
     * 查詢(xún)一級(jí)送達(dá)時(shí)間-常規(guī)方式
     *
     * @param request
     * @return
     */
    EstimatedArrivalDateEntity getEstimatedArrivalDateCommon(EstimatedArrivalDateEntity request);

    /**
     * 查詢(xún)一級(jí)送達(dá)時(shí)間-注解方式
     *
     * @param request
     * @return
     */
    EstimatedArrivalDateEntity getEstimatedArrivalDate(EstimatedArrivalDateEntity request);
}

實(shí)現(xiàn)類(lèi)

/**
 * @author yuanhewei
 * @date 2024/7/9 14:26
 * @description
 */
@Slf4j
@Service
public class DoubleCacheServiceImpl implements DoubleCacheService {

    @Resource
    private Cache<String, Object> caffeineCache;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private EstimatedArrivalDateMapper estimatedArrivalDateMapper;

    @Override
    public EstimatedArrivalDateEntity getEstimatedArrivalDateCommon(EstimatedArrivalDateEntity request) {
        String key = request.getDeliveryDate() + RedisConstants.COLON + request.getWarehouseId() + RedisConstants.COLON + request.getCity();
        log.info("Cache key: {}", key);
        Object value = caffeineCache.getIfPresent(key);
        if (Objects.nonNull(value)) {
            log.info("get from caffeine");
            return EstimatedArrivalDateEntity.builder().estimatedArrivalDate(value.toString()).build();
        }
        value = redisTemplate.opsForValue().get(key);
        if (Objects.nonNull(value)) {
            log.info("get from redis");
            caffeineCache.put(key, value);
            return EstimatedArrivalDateEntity.builder().estimatedArrivalDate(value.toString()).build();
        }
        log.info("get from mysql");
        DateTime deliveryDate = DateUtil.parse(request.getDeliveryDate(), "yyyy-MM-dd");
        EstimatedArrivalDateEntity estimatedArrivalDateEntity = estimatedArrivalDateMapper.selectOne(new QueryWrapper<EstimatedArrivalDateEntity>()
                .eq("delivery_date", deliveryDate)
                .eq("warehouse_id", request.getWarehouseId())
                .eq("city", request.getCity())
        );
        redisTemplate.opsForValue().set(key, estimatedArrivalDateEntity.getEstimatedArrivalDate(), 120, TimeUnit.SECONDS);
        caffeineCache.put(key, estimatedArrivalDateEntity.getEstimatedArrivalDate());
        return EstimatedArrivalDateEntity.builder().estimatedArrivalDate(estimatedArrivalDateEntity.getEstimatedArrivalDate()).build();
    }

    @DoubleCache(cacheName = "estimatedArrivalDate", key = {"#request.deliveryDate", "#request.warehouseId", "#request.city"},
            type = DoubleCache.CacheType.FULL)
    @Override
    public EstimatedArrivalDateEntity getEstimatedArrivalDate(EstimatedArrivalDateEntity request) {
        DateTime deliveryDate = DateUtil.parse(request.getDeliveryDate(), "yyyy-MM-dd");
        EstimatedArrivalDateEntity estimatedArrivalDateEntity = estimatedArrivalDateMapper.selectOne(new QueryWrapper<EstimatedArrivalDateEntity>()
                .eq("delivery_date", deliveryDate)
                .eq("warehouse_id", request.getWarehouseId())
                .eq("city", request.getCity())
        );
        return EstimatedArrivalDateEntity.builder().estimatedArrivalDate(estimatedArrivalDateEntity.getEstimatedArrivalDate()).build();
    }
}

這里的代碼本來(lái)是采用了常規(guī)的寫(xiě)法,沒(méi)有采用自定義注解的方式,注解的方式是參考了后面那位大佬的文章,加以修改實(shí)現(xiàn)的。因?yàn)槲业腃acheKey可能存在多個(gè)屬性值的組合。

Annotitions

/**
 * @author yuanhewei
 * @date 2024/7/9 14:51
 * @description
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DoubleCache {
    /**
     * 緩存名稱(chēng)
     *
     * @return
     */
    String cacheName();

    /**
     * 緩存的key,支持springEL表達(dá)式
     *
     * @return
     */
    String[] key();

    /**
     * 過(guò)期時(shí)間,單位:秒
     *
     * @return
     */
    long expireTime() default 120;

    /**
     * 緩存類(lèi)型
     *
     * @return
     */
    CacheType type() default CacheType.FULL;

    enum CacheType {
        /**
         * 存取
         */
        FULL,

        /**
         * 只存
         */
        PUT,

        /**
         * 刪除
         */
        DELETE
    }
}

Aspect

/**
 * @author yuanhewei
 * @date 2024/7/9 14:51
 * @description
 */
@Slf4j
@Component
@Aspect
public class DoubleCacheAspect {

    @Resource
    private Cache<String, Object> caffeineCache;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Pointcut("@annotation(com.itender.redis.annotation.DoubleCache)")
    public void doubleCachePointcut() {
    }

    @Around("doubleCachePointcut()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        // 拼接解析springEl表達(dá)式的map
        String[] paramNames = signature.getParameterNames();
        Object[] args = point.getArgs();
        TreeMap<String, Object> treeMap = new TreeMap<>();
        for (int i = 0; i < paramNames.length; i++) {
            treeMap.put(paramNames[i], args[i]);
        }
        DoubleCache annotation = method.getAnnotation(DoubleCache.class);
        String elResult = DoubleCacheUtil.arrayParse(Lists.newArrayList(annotation.key()), treeMap);
        String realKey = annotation.cacheName() + RedisConstants.COLON + elResult;
        // 強(qiáng)制更新
        if (annotation.type() == DoubleCache.CacheType.PUT) {
            Object object = point.proceed();
            redisTemplate.opsForValue().set(realKey, object, annotation.expireTime(), TimeUnit.SECONDS);
            caffeineCache.put(realKey, object);
            return object;
        }
        // 刪除
        else if (annotation.type() == DoubleCache.CacheType.DELETE) {
            redisTemplate.delete(realKey);
            caffeineCache.invalidate(realKey);
            return point.proceed();
        }
        // 讀寫(xiě),查詢(xún)Caffeine
        Object caffeineCacheObj = caffeineCache.getIfPresent(realKey);
        if (Objects.nonNull(caffeineCacheObj)) {
            log.info("get data from caffeine");
            return caffeineCacheObj;
        }
        // 查詢(xún)Redis
        Object redisCache = redisTemplate.opsForValue().get(realKey);
        if (Objects.nonNull(redisCache)) {
            log.info("get data from redis");
            caffeineCache.put(realKey, redisCache);
            return redisCache;
        }
        log.info("get data from database");
        Object object = point.proceed();
        if (Objects.nonNull(object)) {
            // 寫(xiě)入Redis
            log.info("get data from database write to cache: {}", object);
            redisTemplate.opsForValue().set(realKey, object, annotation.expireTime(), TimeUnit.SECONDS);
            // 寫(xiě)入Caffeine
            caffeineCache.put(realKey, object);
        }
        return object;
    }
}

因?yàn)樽⒔馍系呐渲靡С諷pring的EL表達(dá)式。

public static String parse(String elString, SortedMap<String, Object> map) {
        elString = String.format("#{%s}", elString);
        // 創(chuàng)建表達(dá)式解析器
        ExpressionParser parser = new SpelExpressionParser();
        // 通過(guò)evaluationContext.setVariable可以在上下文中設(shè)定變量。
        EvaluationContext context = new StandardEvaluationContext();
        map.forEach(context::setVariable);
        // 解析表達(dá)式
        Expression expression = parser.parseExpression(elString, new TemplateParserContext());
        // 使用Expression.getValue()獲取表達(dá)式的值,這里傳入了Evaluation上下文
        return expression.getValue(context, String.class);
    }

    public static String arrayParse(List<String> elStrings, SortedMap<String, Object> map) {
        List<String> result = Lists.newArrayList();
        elStrings.forEach(elString -> {
            elString = String.format("#{%s}", elString);
            // 創(chuàng)建表達(dá)式解析器
            ExpressionParser parser = new SpelExpressionParser();
            // 通過(guò)evaluationContext.setVariable可以在上下文中設(shè)定變量。
            EvaluationContext context = new StandardEvaluationContext();
            map.forEach(context::setVariable);
            // 解析表達(dá)式
            Expression expression = parser.parseExpression(elString, new TemplateParserContext());
            // 使用Expression.getValue()獲取表達(dá)式的值,這里傳入了Evaluation上下文
            result.add(expression.getValue(context, String.class));
        });
        return String.join(RedisConstants.COLON, result);
    }

Controller

/**
 * @author yuanhewei
 * @date 2024/7/9 14:14
 * @description
 */
@RestController
@RequestMapping("/doubleCache")
public class DoubleCacheController {

    @Resource
    private DoubleCacheService doubleCacheService;

    @PostMapping("/common")
    public EstimatedArrivalDateEntity getEstimatedArrivalDateCommon(@RequestBody EstimatedArrivalDateEntity estimatedArrivalDate) {
        return doubleCacheService.getEstimatedArrivalDateCommon(estimatedArrivalDate);
    }

    @PostMapping("/annotation")
    public EstimatedArrivalDateEntity getEstimatedArrivalDate(@RequestBody EstimatedArrivalDateEntity estimatedArrivalDate) {
        return doubleCacheService.getEstimatedArrivalDate(estimatedArrivalDate);
    }
}

代碼中演示了Redis + Caffeine實(shí)現(xiàn)兩級(jí)緩存的方式,一種是傳統(tǒng)常規(guī)的方式,另一種是基于注解的方式實(shí)現(xiàn)的。具體實(shí)現(xiàn)可以根據(jù)自己項(xiàng)目中的實(shí)際場(chǎng)景。

最后的測(cè)試結(jié)果也是兩種方式都可以實(shí)現(xiàn)查詢(xún)先走一級(jí)緩存;一級(jí)緩存不存在查詢(xún)二級(jí)緩存,然后寫(xiě)入一級(jí)緩存;二級(jí)緩存不存在,查詢(xún)MySQL然后寫(xiě)入二級(jí)緩存,再寫(xiě)入一級(jí)緩存的目的。測(cè)試結(jié)果就不貼出來(lái)了

總結(jié)

本文介紹Redis+Caffeine實(shí)現(xiàn)兩級(jí)緩存的方式。一種是常規(guī)的方式,一種的基于注解的方式。具體的實(shí)現(xiàn)可根據(jù)自己項(xiàng)目中的業(yè)務(wù)場(chǎng)景。

至于為什么要用Redis+Caffeine的方式,文章也提到了,目前我們Redis集群壓力還算挺大的,而且接口對(duì)RT的要求也是比較高的。有一點(diǎn)好的就是我們的數(shù)據(jù)是每天全量推一邊,總量也不大,實(shí)時(shí)性要求也不強(qiáng)。所以就很適合本地緩存的方式。

使用本地緩存也要注意設(shè)置容量的大小和過(guò)期時(shí)間,否則容易出現(xiàn)內(nèi)存溢出。

其實(shí)現(xiàn)實(shí)中很多的場(chǎng)景直接使用Redis就可以搞定的,沒(méi)必要硬要使用Caffeine。這里也只是簡(jiǎn)單的介紹了最簡(jiǎn)單基礎(chǔ)的實(shí)現(xiàn)方式。對(duì)于其他一些復(fù)雜的場(chǎng)景還要根據(jù)自己具體的業(yè)務(wù)進(jìn)行設(shè)計(jì)。我自己也是邊學(xué)邊用。

到此這篇關(guān)于Redis+Caffeine 實(shí)現(xiàn)兩級(jí)緩存的項(xiàng)目實(shí)踐的文章就介紹到這了,更多相關(guān)Redis+Caffeine  兩級(jí)緩存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis如何使用HyperLogLog的實(shí)現(xiàn)

    Redis如何使用HyperLogLog的實(shí)現(xiàn)

    本文主要介紹了Redis如何使用HyperLogLog的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Redis分片集群存儲(chǔ)的搭建到使用

    Redis分片集群存儲(chǔ)的搭建到使用

    這篇文章主要介紹了Redis分片集群存儲(chǔ)的搭建到使用,分片集群顧名思義,將數(shù)據(jù)分開(kāi)存儲(chǔ)到Redis集群中,這樣能夠存儲(chǔ)更多的數(shù)據(jù),避免浪費(fèi)資源,需要的朋友可以參考下
    2022-06-06
  • 使用RedisAtomicInteger計(jì)數(shù)出現(xiàn)少計(jì)問(wèn)題及解決

    使用RedisAtomicInteger計(jì)數(shù)出現(xiàn)少計(jì)問(wèn)題及解決

    這篇文章主要介紹了使用RedisAtomicInteger計(jì)數(shù)出現(xiàn)少計(jì)問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Redis6.2.6生產(chǎn)環(huán)境redis.conf單機(jī)配置

    Redis6.2.6生產(chǎn)環(huán)境redis.conf單機(jī)配置

    在實(shí)際生產(chǎn)環(huán)境中,為了保障 Redis 的穩(wěn)定性和高性能,我們往往需要對(duì)默認(rèn)配置進(jìn)行一系列優(yōu)化,本文主要介紹了Redis6.2.6生產(chǎn)環(huán)境redis.conf單機(jī)配置,感興趣的可以了解一下
    2025-04-04
  • Redis未授權(quán)訪(fǎng)問(wèn)配合SSH key文件利用詳解

    Redis未授權(quán)訪(fǎng)問(wèn)配合SSH key文件利用詳解

    這篇文章主要給大家介紹了關(guān)于Redis未授權(quán)訪(fǎng)問(wèn)配合SSH key文件利用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • Redis數(shù)據(jù)過(guò)期策略的實(shí)現(xiàn)詳解

    Redis數(shù)據(jù)過(guò)期策略的實(shí)現(xiàn)詳解

    最近項(xiàng)目當(dāng)中遇到一個(gè)需求場(chǎng)景,需要清空一些存放在Redis的數(shù)據(jù),本文對(duì)Redis的過(guò)期機(jī)制簡(jiǎn)單的講解一下,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Redis數(shù)據(jù)類(lèi)型之散列類(lèi)型hash命令學(xué)習(xí)

    Redis數(shù)據(jù)類(lèi)型之散列類(lèi)型hash命令學(xué)習(xí)

    這篇文章主要為大家介紹了Redis數(shù)據(jù)類(lèi)型之散列類(lèi)型hash命令學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • 通過(guò)redis的腳本lua如何實(shí)現(xiàn)搶紅包功能

    通過(guò)redis的腳本lua如何實(shí)現(xiàn)搶紅包功能

    這篇文章主要給大家介紹了關(guān)于通過(guò)redis的腳本lua如何實(shí)現(xiàn)搶紅包功能的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • Redis鎖的過(guò)期時(shí)間小于業(yè)務(wù)的執(zhí)行時(shí)間如何續(xù)期

    Redis鎖的過(guò)期時(shí)間小于業(yè)務(wù)的執(zhí)行時(shí)間如何續(xù)期

    本文主要介紹了Redis鎖的過(guò)期時(shí)間小于業(yè)務(wù)的執(zhí)行時(shí)間如何續(xù)期,Redisson它能給Redis分布式鎖實(shí)現(xiàn)過(guò)期時(shí)間自動(dòng)續(xù)期,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-05-05
  • 讓Redis在你的系統(tǒng)中發(fā)揮更大作用的幾點(diǎn)建議

    讓Redis在你的系統(tǒng)中發(fā)揮更大作用的幾點(diǎn)建議

    Redis在很多方面與其他數(shù)據(jù)庫(kù)解決方案不同:它使用內(nèi)存提供主存儲(chǔ)支持,而僅使用硬盤(pán)做持久性的存儲(chǔ);它的數(shù)據(jù)模型非常獨(dú)特,用的是單線(xiàn)程。另一個(gè)大區(qū)別在于,你可以在開(kāi)發(fā)環(huán)境中使用Redis的功能,但卻不需要轉(zhuǎn)到Redis
    2014-06-06

最新評(píng)論