踩坑,Redis缓存使用Jackson2JsonRedisSerializer管理序列化,未设置disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES),上线中新代码写入了新的缓存字段结构,旧代码读到新结构报错UnrecognizedPropertyException

背景

a服务上线,在b表新增字段c

bDTO为缓存对象且对其他服务暴露。对象结构如下:

1
2
3
4
5
{
    name string
    id   int
    c    int ```新增字段```
}

上线两台实例,发现有报错:

Could not read JSON: Unrecognized field "c"

nested exception is com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "c"

第一步动作:先回滚。

分析

第二步动作:查具体原因。

可以看到报了一个jackson解析的异常。

对应的查询接口为: /url/d

迅速拉当时的rd了解一下接口背景:

  • 前两个月增加了此读缓存接口;
  • 接口会在登录某系统处调用,影响范围较大;

调用缓存大概是这样的:

1
2
3
4
@Cacheable(cacheNames = PREFIX_KEY, key = "#key")
public BDTO query(String key) {
    return mapper.query(key);
}

接口通过@Cacheable加了一层缓存,逻辑为查b表信息。

关联变更:本次上线 b 上新增了 c 字段。

根据报错,看下jackson的设计: https://stackoverflow.com/questions/4486787/jackson-with-json-unrecognized-field-not-marked-as-ignorable

所以问题是这样产生的:

  1. 新的代码发布,缓存写入了带新字段的json
  2. 旧的代码读缓存,报错
    • 原因1:旧代码的b结构是旧的;
    • 原因2:cacheable使用的redis序列化方式为 Jackson2JsonRedisSerializer ,对应objectMapper未设置 disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)

解决

第三步动作:解决问题。

  1. cacheable redis 序列化设置,增加 disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES),反序列化时会忽略class中没有的属性;
    • 作用是:防止以后报此类错;
  2. queryBusinessInfo 缓存key更名,防止发布中老代码读到新写入的数据;
    • 作用是:防止发布中报此错;