IT袋

当前位置:主页 > 经验教程 > 建站编程 >

多级缓存设计和实战应用

多级缓存设计和实战应用 多级缓存的设计与应用(7)

时间:2024-01-27 18:00:34 来源:IT袋 作者:马勇
导读:多级缓存设计和实战应用,5、编写监听器 通过实现 EntryHandlerT 接口编写监听器,监听Canal消息。注意两点: 实现类通过 @CanalTable("tb_item") 指定监听的表信息 EntryHandler的泛型是与表对

多级缓存设计和实战应用

多级缓存设计和实战应用

5、编写监听器

通过实现EntryHandler<T>接口编写监听器,监听Canal消息。注意两点:

  • 实现类通过@CanalTable("tb_item")指定监听的表信息
  • EntryHandler的泛型是与表对应的实体类
@CanalTable("tb_item")
@Component
public class ItemHandler implements EntryHandler<Item> {
    @Autowired
    private RedisHandler redisHandler;
    @Autowired
    private Cache<Long, Item> itemCache;
    @Override
    public void insert(Item item) {
        // 写数据到JVM进程缓存
        itemCache.put(item.getId(), item);
        // 写数据到redis
        redisHandler.saveItem(item);
    }
    @Override
    public void update(Item before, Item after) {
        // 写数据到JVM进程缓存
        itemCache.put(after.getId(), after);
        // 写数据到redis
        redisHandler.saveItem(after);
    }
    @Override
    public void delete(Item item) {
        // 删除数据到JVM进程缓存
        itemCache.invalidate(item.getId());
        // 删除数据到redis
        redisHandler.deleteItemById(item.getId());
    }
}

6、演示效果 比如:我们将id = 10002 脱脂牛奶 价格(price)变为998.

修改前:

mysql> select t.id,t.name,t.price from mydb.tb_item t where t.id = '10002' ;
+-------+--------------+-------+
| id    | name         | price |
+-------+--------------+-------+
| 10002 | 脱脂牛奶     | 68600 |
+-------+--------------+-------+
1 row in set (0.00 sec)

执行修改: 访问:http://localhost:8081/item  更新id=10002 对应价格998. 请求参数:

{
    "id":10002,
    "name":"脱脂牛奶",
    "title":"安佳脱脂牛奶 新西兰进口轻欣脱脂250ml*24整箱装*2",
    "price":998,
    "image":"https://m.360buyimg.com/mobilecms/s720x720_jfs/t25552/261/1180671662/383855/33da8faa/5b8cf792Neda8550c.jpg!q70.jpg.webp",
    "category":"牛奶",
    "brand":"安佳",
    "spec":"{\"数量\": 30}",
    "status":1,
    "createTime":"2024-01-25T16:00:00.000+00:00",
    "updateTime":"2024-01-25T16:00:00.000+00:00",
    "stock":99999,
    "sold":54981
}

修改后:

查看数据库:

mysql> select t.id,t.name,t.price from mydb.tb_item t where t.id = '10002' ;
+-------+--------------+-------+
| id    | name         | price |
+-------+--------------+-------+
| 10002 | 脱脂牛奶     |   998 |
+-------+--------------+-------+
1 row in set (0.00 sec)

查看redis:

多级缓存设计和实战应用

查看控制台:

11:14:28:980  INFO 19916 --- [l-client-thread] t.j.c.client.client.AbstractCanalClient  : 获取消息 Message[id=2,entries=[header {
  version: 1
  logfileName: "mysql-bin.000005"
  logfileOffset: 978
  serverId: 1000
  serverenCode: "UTF-8"
  executeTime: 1706325266000
  sourceType: MYSQL
  schemaName: ""
  tableName: ""
  eventLength: 31
}

说明Canal同步缓存数据生效,验证通过。

基于OpenResty的Nginx本地缓存

OpenResty为Nginx提供了shard dict的功能,可以在nginx的多个worker之间共享数据,实现缓存功能。

这里粗略给出OpenResty安装后的目录结构:

多级缓存设计和实战应用

从目录结构可以看到:OpenResty 内置Nginx + Lua模块

1)定义共享字典,在nginx.conf的http下添加配置:

 # 共享字典,也就是本地缓存,名称叫做:item_cache,大小150m
 lua_shared_dict item_cache 150m; 

2)使用共享字典:

-- 获取本地缓存对象
local item_cache = ngx.shared.item_cache
-- 存储, 指定key、value、过期时间,单位s,默认为0代表永不过期
item_cache:set('key', 'value', 1000)
-- 读取
local val = item_cache:get('key')

3)实现本地缓存查询

修改/usr/local/openresty/lua/item.lua文件,添加本地缓存逻辑:

设置了缓存过期时间,过期后nginx缓存会自动删除,下次访问即可更新缓存。

这里给商品基本信息设置超时时间为30分钟。因为库存更新频率较高,如果缓存时间过长,可能与数据库差异较大。

完整的item.lua文件:

-- 导入common函数库
local common = require('common')
local read_http = common.read_http
local read_redis = common.read_redis
-- 导入cjson库
local cjson = require('cjson')
-- 导入共享词典,本地缓存
local item_cache = ngx.shared.item_cache
-- 封装查询函数
function read_data(key, expire, path, params)
    -- 查询本地缓存
    local val = item_cache:get(key)
    if not val then
        ngx.log(ngx.ERR, "本地缓存查询失败,尝试查询Redis, key: ", key)
        -- 查询redis
        val = read_redis("1.XXX.XXX.47", 6379, key)
        -- 判断查询结果
        if not val then
            ngx.log(ngx.ERR, "redis查询失败,尝试查询http, key: ", key)
            -- redis查询失败,去查询http
            val = read_http(path, params)
        end
    end
    -- 查询成功,把数据写入本地缓存
    item_cache:set(key, val, expire)
    -- 返回数据
    return val
end
-- 获取路径参数
local id = ngx.var[1]
-- 查询商品信息
local itemJSON = read_data("item:id:" .. id, 1800 ,  "/item/" .. id, nil)
-- JSON转化为lua的table
local item = cjson.decode(itemJSON)
-- 把item序列化为json 返回结果
ngx.say(cjson.encode(item))

关于OpenResty 的使用和语法结构,读者请自行查阅。由于笔者属于后端领域,这里暂时简单介绍。

感兴趣的可以深究。

官网地址:https://openresty.org/cn/

总结

当考虑不同的缓存设计方案时,需要根据具体的应用场景和需求来选择。

这里给出项目链路上关于缓存设计的应用场景和建议:

  1. 浏览器缓存:
    • 应用场景:适用于静态资源如图片、CSS和JavaScript等的缓存,以减少服务器负载和加快页面加载速度。
    • 建议:使用HTTP标头控制缓存策略,如Cache-Control和Expires,确保资源在客户端浏览器上被有效地缓存,减少对服务器的请求次数。
  2. 基于OpenResty的Nginx本地缓存:
    • 应用场景:适用于对频繁请求的动态数据进行本地缓存,如API响应数据、网页片段等。
    • 建议:使用OpenResty结合Nginx的本地缓存功能,通过Lua脚本实现对特定请求响应的本地缓存,可以有效减少后端服务器的负载和提高响应速度。
  3. Redis缓存:
    • 应用场景:适用于需要分布式缓存、高并发读写、数据结构丰富(如哈希、列表、集合等)的场景,如会话管理、页面片段缓存、数据缓存等。
    • 建议:使用Redis作为分布式缓存,结合其丰富的数据结构和高性能特性,可以实现高效的缓存管理和数据处理。
  4. JVM进程缓存:
    • 应用场景:适用于对应用程序内部数据进行缓存,如对象缓存、方法结果缓存等。
    • 建议:使用基于内存的缓存库,如Caffeine、ConcurrentHashMap、Guava Cache等,将需要频繁访问的数据缓存在JVM进程中,以加快数据访问速度,并减少对外部存储的依赖。

综上,缓存设计方案能极大提高应用程序的性能和可扩展性。

需要说明的是:后台系统最好注意对缓存的管理、监控和更新。

此外,我们知道任何的设计都是根据需要的,因为引入新的技术就会带来新的问题,所以也要避免过度设计。

这里讲的是生产实践中的一些思路,可以说多一种选择、多一种可能。

上述就是多级缓存设计和实战应用的相关内容,希望对您有所帮助!

相关阅读

  • 服务器优化的重要性 服务器优化方法

    服务器优化的重要性 服务器优化方法

    如果想了解服务器优化的重要性的IT小经验,一定能解决您的问题的,一起来了解吧! 服务器优化是指通过对服务器硬件、软件和网络进行调整和优化,以提高服务器的性能和稳定性,从而提

  • 怎么创建网络平台账号 创建网站免费注册

    怎么创建网络平台账号 创建网站免费注册

    关于这个怎么创建网络平台账号和创建网站免费注册方面的知识,具体详情如下: 在当下,传统的线下营销渠道已经无法满足消费者的多样化需求,所以很多企业商家都会选择搭建一个网站平

  • 创建一个网站要多少钱 自己做一个网站需要的费用

    创建一个网站要多少钱 自己做一个网站需要的费用

    对于大多数网友来说创建一个网站要多少钱和自己做一个网站需要的费用的方法内容,继续往下看吧! 想搞一个网站,我们先了解一下搞个网站需要多少钱?网站建设费用主要包括:网站搭建

  • OSI七层网络模型传输层详解 传输层使用的协议有哪些

    OSI七层网络模型传输层详解 传输层使用的协议有哪些

    今日重点为您介绍OSI七层网络模型传输层详解的IT知识,接下来小编为网友介绍。 传输层是OSI七层网络模型中的第四层,主要负责为应用层提供端到端的数据传输服务,同时也可以对网络层提