Hash一致性闭环算法 - ( 适用于Redis扩容、Nginx多级缓存 等等 )

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: Hash一致性闭环算法 - ( 适用于Redis扩容、Nginx多级缓存 等等 )模拟Redis扩容做的Hash一致性闭环算法

模拟Redis扩容做的Hash一致性闭环算法

前置条件

Java语言 采用Map 模拟Redis环境

适用场景

Redis扩容采用Hash闭环、Nginx多级缓存采用Hash闭环+Lua手动负载器 等等其他需要做扩容的方案

一致性hash解决的问题

分布式缓存中如果使用简单hash,节点增加和减少对于系统影响非常大。而一致性hash则高效地解决了这个问题。一致性hash不是说节点增加和减少完全没有影响,而是相比简单hash大大降低了这个影响。

一致性hash算法

一致性hash算法也是通过hash取模,只不过取模的值不再是节点个数这样一个可变的量,而是一个相对而言比较大的不变值,例如int型最大值。我们将0和int型最大值首尾相连这样就形成了一个闭环,我们称其为hash环

如果当前有某个节点宕机,那么受影响的数据,只是当前那一个区间的数据

只需要将这一个区间内的数据 重新

源码

import org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.regex.Pattern;
/**
 * Created Date by 2019/12/27 0027.
 * 模拟 一致性hash算法 前半部分 redis 分布区域选择
 * 这里用随机数代替hash
 *
 * @author Parker
 */
public class TestHash {
    private static String default2 = "default2";
/** 生成所有指令 */
    private static Map<String, Map<String, String>> instructions = new HashMap<>();
/**上下文指令 */
    private static Stack<String> contextKeys = new Stack<>();
/**上下文指令 */
    private static Stack<String> instructionKeys = new Stack<>();
/** redis 集合 */
    private static Map<Integer, String> redisMap = new TreeMap<>(new Comparator<Integer>() {
        @Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
        }
    });
/** redis 仓库 */
    private static Map<String, List<Integer>> redisRepository = new HashMap<>();
/**
     * 静态块
     */
    static{
        contextKeys.add("system");
        instructions = TestHash.createInstructions();
        // 添加三台redis服务器 在一个闭环
        TestHash.createRedisMap("xxoo1-redis",1456);
        TestHash.createRedisMap("xxoo2-redis",5437);
        TestHash.createRedisMap("xxoo3-redis",8524);
        // 初始化数据
        TestHash.addNum(1000);
        TestHash.addNum(2000);
        TestHash.addNum(5000);
        TestHash.addNum(6000);
        TestHash.addNum(7000);
        TestHash.addNum(8000);
        TestHash.addNum(10000);
        TestHash.addNum(15000);
        TestHash.addNum(20000);
        TestHash.addNum(25000);
        TestHash.addNum(40000);
    }
public static void main(String[] args) {
System.out.println("欢迎使用 redis一致性hash算法 模拟系统 !");
System.out.println();
        // 输入检测
        TestHash.invokeScanner(contextKeys,null,false);
    }
/**
     * 生成Redis 仓库
     *
     * 生成仓库 则 锁定类 这里用 synchronized 代替
     * ☆☆☆☆☆☆☆☆☆☆☆☆☆
     *  现实环境中 需要￿做分布式锁 避免在迁移数据过程中 又有新的数据 做改动 ****** ☆
     * @return
     */
public synchronized static void createRedisMap(String redisCode,Integer num) {
Set<Integer> integers = redisMap.keySet();
        Iterator<Integer> iterator = integers.iterator();
        List<Integer> keys = new ArrayList<>(integers.size());
while (iterator.hasNext()){
            keys.add(iterator.next());
        }
        //正序
        keys.sort(new Comparator<Integer>() {
            @Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
            }
        });
        // 调用闭环算法
Integer key = null;
if(keys != null && !keys.isEmpty()){
            key = TestHash.closedLoopAlgorithm(num,keys);
        }
        // 根据 闭环算法 获得数据
        List<Integer> datas = null;
if(null != key){
            datas = redisRepository.get(redisMap.get(key));
        }
        // 创建集合
        List<Integer> list = new ArrayList<>();
        redisRepository.put(redisCode,list);
        redisMap.put(num,redisCode);
        // 因为上方有新增redis 获取 新的 keys
        integers = redisMap.keySet();
        iterator = integers.iterator();
        List<Integer> keysT = new ArrayList<>(integers.size());
while (iterator.hasNext()){
            keysT.add(iterator.next());
        }
        // 数据迁移
if(datas != null && !datas.isEmpty()){
            List<Integer> newDatas = new ArrayList<>();
            // 循环所有数据 查找出 要存放在新容器里的数据
for (Integer data : datas) {
                // 调用闭环算法
Integer keyT = TestHash.closedLoopAlgorithm(data,keysT);
if(keyT.equals(num)){
                    newDatas.add(data);
                }
            }
            // 删除 旧数据
for (Integer newData : newDatas) {
                // 传入keys 因为 keys已做更改 传入旧keys
                TestHash.deleteOldData(newData,keys);
            }
            // 添加新数据
            List<Integer> newQueue = redisRepository.get(redisMap.get(num));
for (Integer newData : newDatas) {
                newQueue.add(newData);
            }
        }
    }
/**
     * 生成Redis 数据
     * @return
     */
public static void addNum(Integer num) {
Integer key = 0;
Set<Integer> integers = redisMap.keySet();
        Iterator<Integer> iterator = integers.iterator();
        List<Integer> keys = new ArrayList<>(integers.size());
while (iterator.hasNext()){
            keys.add(iterator.next());
        }
        //正序
        keys.sort(new Comparator<Integer>() {
            @Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
            }
        });
        // 调用闭环算法
        key = TestHash.closedLoopAlgorithm(num,keys);
        List<Integer> datas = redisRepository.get(redisMap.get(key));
        datas.add(num);
        List<Integer> nums = new ArrayList<>();
for (Integer integer : keys) {
if(redisRepository.get(redisMap.get(integer)) != null){
                nums.addAll(redisRepository.get(redisMap.get(integer)));
            }
        }
System.out.println();
System.out.println("当前数据:");
System.out.println(nums.toString());
for (Integer integer : keys) {
if(redisRepository.get(redisMap.get(integer)) != null){
System.out.println(redisMap.get(integer)+":"+redisRepository.get(redisMap.get(integer)).toString());
            }
        }
System.out.println();
    }
/**
     * 查看Redis 所有数据
     * @return
     */
public static void findAll() {
Set<Integer> integers = redisMap.keySet();
        Iterator<Integer> iterator = integers.iterator();
        List<Integer> keys = new ArrayList<>(integers.size());
while (iterator.hasNext()){
            keys.add(iterator.next());
        }
        //正序
        keys.sort(new Comparator<Integer>() {
            @Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
            }
        });
        List<Integer> nums = new ArrayList<>();
for (Integer integer : keys) {
if(redisRepository.get(redisMap.get(integer)) != null){
                nums.addAll(redisRepository.get(redisMap.get(integer)));
            }
        }
System.out.println();
System.out.println("当前数据:");
System.out.println(nums.toString());
for (Integer integer : keys) {
if(redisRepository.get(redisMap.get(integer)) != null){
System.out.println(redisMap.get(integer)+":"+redisRepository.get(redisMap.get(integer)).toString());
            }
        }
System.out.println();
    }
/**
     * 删除Redis数据
     * @return
     */
public static void deleteData(Integer num) {
Integer key = 0;
Set<Integer> integers = redisMap.keySet();
        Iterator<Integer> iterator = integers.iterator();
        List<Integer> keys = new ArrayList<>(integers.size());
while (iterator.hasNext()){
            keys.add(iterator.next());
        }
        //正序
        keys.sort(new Comparator<Integer>() {
            @Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
            }
        });
        // 调用闭环算法
        key = TestHash.closedLoopAlgorithm(num,keys);
        List<Integer> datas = redisRepository.get(redisMap.get(key));
boolean deFlag = false;
int count = 0;
for (int i = 0; i < datas.size(); i++) {
if(num.equals(datas.get(i))){
                deFlag = true;
                count = i;
                break;
            }
        }
if(deFlag){
            datas.remove(count);
        }
        List<Integer> nums = new ArrayList<>();
for (Integer integer : keys) {
if(redisRepository.get(redisMap.get(integer)) != null){
                nums.addAll(redisRepository.get(redisMap.get(integer)));
            }
        }
System.out.println();
System.out.println("当前数据:");
System.out.println(nums.toString());
for (Integer integer : keys) {
if(redisRepository.get(redisMap.get(integer)) != null){
System.out.println(redisMap.get(integer)+":"+redisRepository.get(redisMap.get(integer)).toString());
            }
        }
System.out.println();
    }
/**
     * 删除Redis数据
     * @return
     */
public synchronized static void deleteOldData(Integer num,List<Integer> keys) {
Integer key = 0;
        //正序
        keys.sort(new Comparator<Integer>() {
            @Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
            }
        });
        // 调用闭环算法
        key = TestHash.closedLoopAlgorithm(num,keys);
        List<Integer> datas = redisRepository.get(redisMap.get(key));
boolean deFlag = false;
int count = 0;
for (int i = 0; i < datas.size(); i++) {
if(num.equals(datas.get(i))){
                deFlag = true;
                count = i;
                break;
            }
        }
if(deFlag){
            datas.remove(count);
        }
        List<Integer> nums = new ArrayList<>();
for (Integer integer : keys) {
if(redisRepository.get(redisMap.get(integer)) != null){
                nums.addAll(redisRepository.get(redisMap.get(integer)));
            }
        }
    }
/**
     * 闭环算法 核心算法
     * ☆☆☆☆☆☆☆☆☆☆
     * @param num
     * @param keys
     * @return
     */
public static Integer closedLoopAlgorithm(Integer num,List<Integer> keys){
Integer key = 0;
if(num > keys.get(keys.size()-1) || num <= keys.get(0)){
    key = keys.get(0);
  }else {
    for (int i = keys.size() - 2; i >= 0; i--) {
      if(num > keys.get(i)){
        key = keys.get(i+1);
        break;
      }
    }
  }
return key;
    }
/**
     * 下方代码 是输入 相关 与 一致性算法无关
     */
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
/**
     * 创建随机数
     * @param
     */
public static int createRandom(){
        // 最大数
Integer max = 10000;
return new Random().nextInt(max);
    }
/**
     * 输入方案
     */
public static void invokeScanner(Stack<String> contextKey,String instruction,boolean errorF){
        try{
            String key = contextKey.peek();
            String[] keys = key.split("_");
            List<String> keyList = Arrays.asList(keys);
            // 如果输入错误 进行排查
boolean errorFlag = true;
if(errorF && keyList.size() > 1){
                List<String> tempList = new ArrayList<>();
for (int i = 0; i < keyList.size()-1; i++) {
                    tempList.add(keyList.get(i));
                }
                keyList = tempList;
                errorFlag = false;
            }
            // 顶级
if("system".equals(keys[0])){
                // 一级
if(keyList.size() == 1){
if(errorFlag){
                        contextKey.add(contextKey.peek()+"_top");
                    }
                    instruction = TestHash.validataScanner(instructions.get(TestHash.createInstructionKey()));
                    // 验证指令输入
                    String instructionKeyTemp = null;
if(instructionKeys.size() > 0){
                        instructionKeyTemp = instructionKeys.peek();
                    }
                    TestHash.invokeScanner(contextKey,instructionKeyTemp,false);
                }else{
                    // 一级
if("top".equals(keyList.get(1))){
                        // 查询当前所有redis集群
if("1".equals(instruction)){
if(errorFlag){
                                contextKey.add(contextKey.peek()+"_getRedis");
                            }
                            // 打印当前 redis 服务器数量
                            TestHash.printRedis(redisMap);
                            // 发起二次输入
                            // 验证指令输入
if(errorFlag){
                                contextKey.add(contextKey.peek()+"_back");
                            }
                            instruction = TestHash.validataScanner(instructions.get(default2));
                            TestHash.invokeScanner(contextKey,instruction,false);
                        }
                        // 增加redis集群
else if("2".equals(instruction)){
if(errorFlag){
                                contextKey.add(contextKey.peek()+"_addRedis");
                            }
                            String code = "";
Integer num = 0;
System.out.println();
System.out.println("------------------------------");
System.out.println("请输入redis编号:");
boolean fl = true;
while (fl){
                                // 开启输入模式
                                Scanner scanner = new Scanner(System.in);
                                String str = scanner.nextLine();
                                String pattern = "[\\w\\d]+";
boolean matches = Pattern.matches(pattern, str);
if(matches){
                                    List<Integer> integers = redisRepository.get(str);
if(integers != null){
System.out.println("------------------------------");
System.out.println();
System.out.println("[ "+str+" ] 编号已存在");
System.out.println();
System.out.println("请输入redis编号:");
System.out.println();
continue;
                                    }
                                    code = str;
                                    fl = false;
                                }else{
System.out.println("------------------------------");
System.out.println();
System.out.println("[ "+str+" ] 只能包含字母、数字与_");
System.out.println();
System.out.println("请输入redis编号:");
System.out.println();
                                }
                            }
System.out.println();
System.out.println("------------------------------");
System.out.println("请输入redis数据范围:");
boolean fl1 = true;
while (fl1){
                                // 开启输入模式
                                Scanner scanner = new Scanner(System.in);
                                String str = scanner.nextLine();
                                String pattern = "[\\d]+";
boolean matches = Pattern.matches(pattern, str);
if(matches){
                                    num = Integer.parseInt(str);
                                    String s = redisMap.get(num);
if(!StringUtils.isEmpty(s)){
System.out.println("------------------------------");
System.out.println();
System.out.println("[ "+str+" ] 数据范围已存在");
System.out.println();
System.out.println("请输入redis数据范围:");
System.out.println();
continue;
                                    }
                                    fl1 = false;
                                }else{
System.out.println("------------------------------");
System.out.println();
System.out.println("[ "+str+" ] 只能包含数字");
System.out.println();
System.out.println("请输入redis数据范围:");
System.out.println();
                                }
                            }
                            TestHash.createRedisMap(code,num);
                            // 打印当前 redis 服务器数量
                            TestHash.printRedis(redisMap);
                            // 发起二次输入
                            // 验证指令输入
if(errorFlag){
                                contextKey.add(contextKey.peek()+"_add");
                            }
                            instruction = TestHash.validataScanner(instructions.get(default2));
                            TestHash.invokeScanner(contextKey,instruction,false);
                        }
                        // 增加redis数据
else if("3".equals(instruction)){
if(errorFlag){
                                contextKey.add(contextKey.peek()+"_addRedisData");
                            }
System.out.println();
System.out.println("------------------------------");
System.out.println("请输入数值:");
Integer num = 0;
boolean fl = true;
while (fl){
                                // 开启输入模式
                                Scanner scanner = new Scanner(System.in);
                                String str = scanner.nextLine();
                                String pattern = "[\\d]+";
boolean matches = Pattern.matches(pattern, str);
if(matches){
                                    num = Integer.parseInt(str);
                                    fl = false;
                                }else{
System.out.println("------------------------------");
System.out.println();
System.out.println("[ "+str+" ] 只能包含数字");
System.out.println();
System.out.println("请输入数值:");
System.out.println();
                                }
                            }
                            TestHash.addNum(num);
                            // 打印当前 redis 数值
                            //TestHash.printRedisData();
                            // 发起二次输入
                            // 验证指令输入
if(errorFlag){
                                contextKey.add(contextKey.peek()+"_add");
                            }
                            instruction = TestHash.validataScanner(instructions.get(default2));
                            TestHash.invokeScanner(contextKey,instruction,false);
                        }
                        // 查询当前所有redis数据
if("4".equals(instruction)){
if(errorFlag){
                                contextKey.add(contextKey.peek()+"_findAll");
                            }
                            // 打印当前 redis 所有数据
                            TestHash.findAll();
                            // 发起二次输入
                            // 验证指令输入
if(errorFlag){
                                contextKey.add(contextKey.peek()+"_findAll");
                            }
                            instruction = TestHash.validataScanner(instructions.get(default2));
                            TestHash.invokeScanner(contextKey,instruction,false);
                        }
                        // 删除redis数据
else if("5".equals(instruction)){
if(errorFlag){
                                contextKey.add(contextKey.peek()+"_deleteRedisData");
                            }
System.out.println();
System.out.println("------------------------------");
System.out.println("请输入数值:");
Integer num = 0;
boolean fl = true;
while (fl){
                                // 开启输入模式
                                Scanner scanner = new Scanner(System.in);
                                String str = scanner.nextLine();
                                String pattern = "[\\d]+";
boolean matches = Pattern.matches(pattern, str);
if(matches){
                                    num = Integer.parseInt(str);
                                    fl = false;
                                }else{
System.out.println("------------------------------");
System.out.println();
System.out.println("[ "+str+" ] 只能包含数字");
System.out.println();
System.out.println("请输入数值:");
System.out.println();
                                }
                            }
                            TestHash.deleteData(num);
                            // 打印当前 redis 数值
                            //TestHash.printRedisData();
                            // 发起二次输入
                            // 验证指令输入
if(errorFlag){
                                contextKey.add(contextKey.peek()+"_delete");
                            }
                            instruction = TestHash.validataScanner(instructions.get(default2));
                            TestHash.invokeScanner(contextKey,instruction,false);
                        }
else{
                            //二级
if(keyList.size() > 2){
                                // 查询当前所有redis集群
if("getRedis".equals(keyList.get(2))){
                                    // 返回上一层
if("0".equals(instruction)){
                                        // 取两次 包含本次的正确 指令
                                        contextKey.pop();
                                        contextKey.pop();
                                        instructionKeys.pop();
                                        instructionKeys.pop();
                                        String instructionKeyTemp = null;
if(instructionKeys.size() > 0){
                                            instructionKeyTemp = instructionKeys.peek();
                                        }
                                        TestHash.invokeScanner(contextKey,instructionKeyTemp,true);
                                    }
                                }else if("addRedis".equals(keyList.get(2))){
                                    // 返回上一层
if("0".equals(instruction)){
                                        // 取两次 包含本次的正确 指令
                                        contextKey.pop();
                                        contextKey.pop();
                                        instructionKeys.pop();
                                        instructionKeys.pop();
                                        String instructionKeyTemp = null;
if(instructionKeys.size() > 0){
                                            instructionKeyTemp = instructionKeys.peek();
                                        }
                                        TestHash.invokeScanner(contextKey,instructionKeyTemp,true);
                                    }
                                }else if("addRedisData".equals(keyList.get(2))){
                                    // 返回上一层
if("0".equals(instruction)){
                                        // 取两次 包含本次的正确 指令
                                        contextKey.pop();
                                        contextKey.pop();
                                        instructionKeys.pop();
                                        instructionKeys.pop();
                                        String instructionKeyTemp = null;
if(instructionKeys.size() > 0){
                                            instructionKeyTemp = instructionKeys.peek();
                                        }
                                        TestHash.invokeScanner(contextKey,instructionKeyTemp,true);
                                    }
                                }else if("findAll".equals(keyList.get(2))){
                                    // 返回上一层
if("0".equals(instruction)){
                                        // 取两次 包含本次的正确 指令
                                        contextKey.pop();
                                        contextKey.pop();
                                        instructionKeys.pop();
                                        instructionKeys.pop();
                                        String instructionKeyTemp = null;
if(instructionKeys.size() > 0){
                                            instructionKeyTemp = instructionKeys.peek();
                                        }
                                        TestHash.invokeScanner(contextKey,instructionKeyTemp,true);
                                    }
                                }else if("deleteRedisData".equals(keyList.get(2))){
                                    // 返回上一层
if("0".equals(instruction)){
                                        // 取两次 包含本次的正确 指令
                                        contextKey.pop();
                                        contextKey.pop();
                                        instructionKeys.pop();
                                        instructionKeys.pop();
                                        String instructionKeyTemp = null;
if(instructionKeys.size() > 0){
                                            instructionKeyTemp = instructionKeys.peek();
                                        }
                                        TestHash.invokeScanner(contextKey,instructionKeyTemp,true);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            // 如果没有拦截到 则狗咬狗尾巴
            String instructionKeyTemp = null;
if(instructionKeys.size() > 0){
                instructionKeyTemp = instructionKeys.peek();
            }
            TestHash.invokeScanner(contextKey,instructionKeyTemp,true);
        }catch (Exception e){
            //e.printStackTrace();
System.out.println(e.getMessage());
            // 错误
            TestHash.errorScanner(e.getMessage());
        }
    }
/**
     * 判断输入
     * @param map 指令集合
     */
public static String validataScanner(Map<String, String> map) throws Exception{
        // 打印指令
        TestHash.printScannerKeys(map);
        // 开启输入模式
        Scanner scanner = new Scanner(System.in);
        String str = scanner.nextLine();
        String obj = map.get(str);
if(obj != null){
            instructionKeys.add(str);
return str;
        }
        // 否则就报错
        throw new Exception(str);
    }
/**
     * 生成指令Key
     * @return
     */
public static String createInstructionKey() {
return contextKeys.peek();
    }
/**
     * 生成所有指令
     * @return
     */
public static Map<String,Map<String, String>> createInstructions() {
        //总 指令
        Map<String, Map<String, String>> map = new HashMap<>();
        //第一层指令
        Map<String, String> allMap = new TreeMap<>(new Comparator<String>() {
            @Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
            }
        });
        allMap.put("1","查询当前所有redis集群");
        allMap.put("2","增加集群");
        allMap.put("3","添加数据");
        allMap.put("4","查看所有数据");
        allMap.put("5","删除数据");
        map.put("system_top",allMap);
        //默认二级命令
        Map<String, String> default2Map = new TreeMap<>(new Comparator<String>() {
            @Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
            }
        });
        default2Map.put("0","返回上级菜单");
        map.put("default2",default2Map);
return map;
    }
/**
     * 输入错误
     */
public static void errorScanner(String str) {
        String strT = "";
if(!StringUtils.isEmpty(str)){
            strT = "[ "+str+" ] ";
        }
System.out.println();
System.out.println();
System.out.println();
System.out.println();
System.out.println();
System.out.println();
System.out.println(strT + "输入参数有误,请重新输入!");
System.out.println();
        String instructionKeyTemp = null;
if(instructionKeys.size() > 0){
            instructionKeyTemp = instructionKeys.peek();
        }
        // 回调
        TestHash.invokeScanner(contextKeys,instructionKeyTemp,true);
    }
/**
     * 打印指令
     */
public static void printScannerKeys(Map<String, String> map) {
        // 打印命令
Set<String> keySet = map.keySet();
        Iterator<String> iter = keySet.iterator();
System.out.println();
System.out.println("------------------------------");
while (iter.hasNext()) {
            String key = iter.next();
System.out.println("指令 [ "+key+" ]" + " " + map.get(key));
        }
System.out.println();
System.out.println("请输入指令:");
    }
/**
     * 打印当前redis服务器
     * @param map
     */
public static void printRedis(Map<Integer, String> map){
Set<Integer> keySet = map.keySet();
        Iterator<Integer> iter = keySet.iterator();
System.out.println();
while (iter.hasNext()) {
Integer key = iter.next();
System.out.println(key + ":" + map.get(key));
        }
System.out.println();
    }
}
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
7天前
|
存储 缓存 NoSQL
解决Redis缓存数据类型丢失问题
解决Redis缓存数据类型丢失问题
132 85
|
5天前
|
缓存 监控 NoSQL
Redis经典问题:缓存穿透
本文详细探讨了分布式系统和缓存应用中的经典问题——缓存穿透。缓存穿透是指用户请求的数据在缓存和数据库中都不存在,导致大量请求直接落到数据库上,可能引发数据库崩溃或性能下降。文章介绍了几种有效的解决方案,包括接口层增加校验、缓存空值、使用布隆过滤器、优化数据库查询以及加强监控报警机制。通过这些方法,可以有效缓解缓存穿透对系统的影响,提升系统的稳定性和性能。
|
1月前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
1月前
|
存储 缓存 NoSQL
【赵渝强老师】基于Redis的旁路缓存架构
本文介绍了引入缓存后的系统架构,通过缓存可以提升访问性能、降低网络拥堵、减轻服务负载和增强可扩展性。文中提供了相关图片和视频讲解,并讨论了数据库读写分离、分库分表等方法来减轻数据库压力。同时,文章也指出了缓存可能带来的复杂度增加、成本提高和数据一致性问题。
【赵渝强老师】基于Redis的旁路缓存架构
|
1月前
|
缓存 NoSQL Redis
Redis 缓存使用的实践
《Redis缓存最佳实践指南》涵盖缓存更新策略、缓存击穿防护、大key处理和性能优化。包括Cache Aside Pattern、Write Through、分布式锁、大key拆分和批量操作等技术,帮助你在项目中高效使用Redis缓存。
281 22
|
1月前
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
43 5
|
1月前
|
缓存 NoSQL 中间件
redis高并发缓存中间件总结!
本文档详细介绍了高并发缓存中间件Redis的原理、高级操作及其在电商架构中的应用。通过阿里云的角度,分析了Redis与架构的关系,并展示了无Redis和使用Redis缓存的架构图。文档还涵盖了Redis的基本特性、应用场景、安装部署步骤、配置文件详解、启动和关闭方法、systemctl管理脚本的生成以及日志警告处理等内容。适合初学者和有一定经验的技术人员参考学习。
214 7
|
1月前
|
存储 缓存 监控
利用 Redis 缓存特性避免缓存穿透的策略与方法
【10月更文挑战第23天】通过以上对利用 Redis 缓存特性避免缓存穿透的详细阐述,我们对这一策略有了更深入的理解。在实际应用中,我们需要根据具体情况灵活运用这些方法,并结合其他技术手段,共同保障系统的稳定和高效运行。同时,要不断关注 Redis 缓存特性的发展和变化,及时调整策略,以应对不断出现的新挑战。
71 10
|
1月前
|
缓存 监控 NoSQL
Redis 缓存穿透的检测方法与分析
【10月更文挑战第23天】通过以上对 Redis 缓存穿透检测方法的深入探讨,我们对如何及时发现和处理这一问题有了更全面的认识。在实际应用中,我们需要综合运用多种检测手段,并结合业务场景和实际情况进行分析,以确保能够准确、及时地检测到缓存穿透现象,并采取有效的措施加以解决。同时,要不断优化和改进检测方法,提高检测的准确性和效率,为系统的稳定运行提供有力保障。
58 5
|
1月前
|
缓存 监控 NoSQL
Redis 缓存穿透及其应对策略
【10月更文挑战第23天】通过以上对 Redis 缓存穿透的详细阐述,我们对这一问题有了更深入的理解。在实际应用中,我们需要根据具体情况综合运用多种方法来解决缓存穿透问题,以保障系统的稳定运行和高效性能。同时,要不断关注技术的发展和变化,及时调整策略,以应对不断出现的新挑战。
53 4