IT袋

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

多级缓存设计和实战应用

多级缓存设计和实战应用 多层次缓存设计和实际应用(7)

时间:2024-01-27 21:00:21 来源: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进程中,以加快数据访问速度,并减少对外部存储的依赖。

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

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

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

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

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

相关阅读

  • 编写一个简单的网页结构 网页设计作业html成品

    编写一个简单的网页结构 网页设计作业html成品

    小编为网友们解答编写一个简单的网页结构和网页设计作业html成品方面的介绍,具体详情如下: HTML(HyperText Markup Language)是一种简单、通用的超文本标记语言,Web服务器返回给客户端的最常

  • access数据库的对象是什么 了解access数据库的结构层次

    access数据库的对象是什么 了解access数据库的结构层次

    下面为网友们详细介绍access数据库的对象是什么和了解access数据库的结构层次方面的内容,接下来分享详细内容。 说到数据处理,大家首先想到的是Excel,其实,Office中的数据处理软件除了E

  • web服务器怎么配置 免费个人web服务器推荐

    web服务器怎么配置 免费个人web服务器推荐

    对于许多网友来说web服务器怎么配置和免费个人web服务器推荐方面的内容,具体详情如下: 回想一下一个http请求的过程,你在浏览器输入xxx.com,经过域名解析 发起tcp的3次握手 建立tcp连接后

  • 信息加密、解密与常用算法的基本概念和相关知识

    信息加密、解密与常用算法的基本概念和相关知识

    本文为您带来的是信息加密、解密与常用算法的基本概念和相关知识的话题,请看下面详细的介绍。 一、信息加密概念 信息加密技术是对信息进行伪装,使得信息非法窃取者无法理解信息的真