美文网首页
缓存架构实战-08-多级缓存架构

缓存架构实战-08-多级缓存架构

作者: 西海岸虎皮猫大人 | 来源:发表于2020-10-22 19:37 被阅读0次
三级缓存

nginx本地缓存 + redis分布式缓存 + tomcat堆缓存
时效要求高的数据如库存等,redis\数据库双写
商品基本信息时效性要求不高,异步
nginx + lua脚本,作为第一层
nginx -> redis -> tomcat
nginx缓存是为了抗热数据,内存有限
redis缓存抗海量离散数据
tomcat堆缓存是抗redis宕机的场景

cache aside pattern

读数据先读缓存
更新时先删除缓存,再更新数据库
删除而非更新的原因是,缓存有大量冷数据,频繁更新没有必要

双写一致性

写数据库删除redis缓存,可能数据不一致,如数据库修改成功,但缓存删除失败
初级解决思路,先删除缓存,再修改数据库
高并发场景,更新库存数据库与读取缓存并发发生,读取数据加载到缓存,数据库修改后与缓存不一致
解决思路,队列串行化,商品id hash取值对内存队列数量取模,路由到队列,上述读请求进入队列
优化点,同一数据短时间进入多个读请求,可以做排重优化,设置hang时长
缓存是空的,如果队列中没有更新操作即数据库中没有,则没必要hang
如果一个内存队列积压多个商品更新操作,会导致长时阻塞,需根据实际情况压测,加机器解决
如果读和写操作路由到不同的内存队列,也会不一致
可以使用nginx hash路由的功能
热点商品路由问题,某商品读写请求特别高,全部打到相同机器,可能导致某台机器压力过大

linux部署mysql
yum install -y mysql-server
service mysqld start
chkconfig mysqld on
yum install -y mysql-connector-java
spring boot整合jedis

依赖

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

入口类注入bean

    @Bean
    public JedisCluster JedisClusterFactory() {
        Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
        jedisClusterNodes.add(new HostAndPort("192.168.68.103", 7005));
        jedisClusterNodes.add(new HostAndPort("192.168.68.101", 7002));
        jedisClusterNodes.add(new HostAndPort("192.168.68.103", 7007));
        jedisClusterNodes.add(new HostAndPort("192.168.68.102", 7003));
        JedisCluster jedisCluster = new JedisCluster(jedisClusterNodes);
        return jedisCluster;
    }

redis测试类

@Repository
public class RedisDaoImpl implements RedisDao {
    @Resource
    private JedisCluster jedisCluster;

    @Override
    public void set(String key, String value) {
        jedisCluster.set(key, value);
    }

    @Override
    public String get(String key) {
        return jedisCluster.get(key);
    }
}

数据库脚本

create database if not exists eshop;
grant all privileges on eshop.* to 'eshop'@'%' identified by 'eshop';
use eshop;
create table user(name varchar(255), age int)
insert into user values('zhangsan', 25)

mapper service controller略.

内存队列实现

内存队列-RequestQueue

/**
 * 请求的内存队列
 */
public class RequestQueue {
    private List<ArrayBlockingQueue<Request>> queues = new ArrayList<>();

    private static class Singleton {
        private static RequestQueue instance;

        static {
            instance = new RequestQueue();
        }

        public static RequestQueue getInstance() {
            return instance;
        }
    }

    public static RequestQueue getInstance() {
        return RequestQueue.Singleton.getInstance();
    }

    public void addQueue(ArrayBlockingQueue<Request> queue) {
        this.queues.add(queue);
    }
}

工作线程-RequestProcessorThread

/**
 * 执行请求的工作线程
 */
public class RequestProcessorThread implements Callable {
    /**
     * 自己监控的内存队列
     */
    private ArrayBlockingQueue<Request> queue;

    public RequestProcessorThread(ArrayBlockingQueue queue) {
        this.queue = queue;
    }

    @Override
    public Boolean call() throws Exception {
        while(true) {
            break;
        }
        return true;
    }
}

线程池-RequestProcessorThreadPool

public class RequestProcessorThreadPool {
    /**
     * 线程池
     * 实际项目中线程池大小,每个线程监控的内存队列大小可以写到内存队列中
     * 此处方便起见写死
     */
    private ExecutorService threadPool = Executors.newFixedThreadPool(10);

    public RequestProcessorThreadPool() {
        RequestQueue requestQueue = RequestQueue.getInstance();
        for (int i = 0; i < 10; i++) {
            ArrayBlockingQueue<Request> queue = new ArrayBlockingQueue(100);
            requestQueue.addQueue(queue);
            threadPool.submit(new RequestProcessorThread(queue));
        }
    }

    /**
     * 静态内部类单例,绝对线程安全
     */
    private static class Singleton {
        private static RequestProcessorThreadPool instance;

        static {
            instance = new RequestProcessorThreadPool();
        }

        public static RequestProcessorThreadPool getInstance() {
            return instance;
        }
    }

    public static RequestProcessorThreadPool getInstance() {
        return Singleton.getInstance();
    }

    public static void init() {
        getInstance();
    }
}

相关文章

网友评论

      本文标题:缓存架构实战-08-多级缓存架构

      本文链接:https://www.haomeiwen.com/subject/iqsjsktx.html