冷湘宇 Coldxiangyu's blog

银保通Redis升级方案

2017-06-23
coldxiangyu

背景:

银保通作为银行与保险公司交换数据的平台,随着业务量的增长,压力逐渐增大。如何在高并发的情况下保证TPS显得尤为重要。随着本次银保通系统升级,Redis是其中一个非常重要的优化方向。Redis以其本身强大的数据处理能力以及惊人的效率,非常适合银保通这种单纯的数据校验,不涉及复杂逻辑的系统。

新增项目如下:

  • Redis服务器(Linux):建议多个,主从配置。如果考虑使用redis cluster集群配置,至少需要3主3从。
  • Jedis客户端代码(jedis-2.9.0.jar)
  • JedisPool连接池(commons-pool2-2.4.2.jar)

说明:由于目前银保通工程jdk版本为1.5,而Jedis以及JedisPool本身并不兼容1.5版本。

有以下两种解决方案:
一、升级银保通jdk版本(推荐,根据jdk版本向下兼容性,理论上升级JDK不会有太多问题,我在本地把银保通工程升级为1.7重新部署tomcat是可行的。如采用此方式,还需考虑生产环境weblogic服务器对升级JDK的兼容性。)
二、独立工程单独部署,建议jdk版本为1.7以上,使用spring+maven,方便配置以及使用spring-redis相关类库。此外还要考虑成本与实现的问题,与银保通如何交互,是否采用微服务的方式(目前银保通是不支持作为微服务消费端的,需要对架构进行改造)

应用业务场景:

缓存

适用于银保通本次优化的界面化功能:

产品规则定义

产品规则大部分定义之后是很少进行变动的,比较适合以缓存的形式进行统一拉取。
我们选用String类型作为产品规则的存储,理论上产品规则这种定义比较适用于Hash类型,但是如果采用Hash类型的话,需要设计的field非常多。这里我们把产品定义转换为json作为String的value,也可以非常明确的进行产品规则的存储以及获取。

命名规则:rules:riskcode

产品规则是由界面进行定义或者修改的:

1.新增产品规则:

新的产品规则定义完成之后,提交页面,我们将页面的产品规则转换为json,并新建对应rules:riskcode 的key,存储json为value。
2.修改产品规则:

修改产品规则的时候,选择完产品代码,我们需要在redis缓存中拉取对应rules:riskcode的json出来,将json转换为list,并对页面对应域赋值。如果redis缓存中不存在,则查询数据库。将数据库中的数据赋值给页面,同时,将这条数据转换为json,set到缓存中。

权限管理

权限管理也是通过页面进行设置的,与产品规则一样,可以通过redis作为缓存。
相对于产品规则定义,权限管理的数据类型比较简单,采用String类型存储,value也无需转换为json,直接存储角色(role)即可。

命名规则:user:role(前提:user可以唯一标识登陆用户)

具体的新增和修改,与产品规则实现思路保持一致。

说明:银保通目前使用的是中科软的前端架构,实现起来比较困难。可以考虑通过json与VData转换,接入redis。

数据库

限额管理

产品限额分为日限额与月限额

涉及限额的数据建议单独进行持久化,因为限额数据是实时变动的,如果仅仅作为缓存,需要频繁的更新数据库或从数据库获取值,redis的价值得不到体现,反而变得臃肿。理论上不需要单独设计限额表,只需redis进行持久化读写就可以了。如果非要实体表存储的话,通过日终或者月终的方式,跑批从redis数据库拉取数据存表就可以了。

如果限额采用限制份数机制,redis本身的incrby(自增)decrby(自减)运算就可以满足需求。如果需要限制保额或者保费,需要单独逻辑控制。
产品限额控制条件众多,大致包括银行、渠道、险种,考虑采用String或Hash类型。

此处需要进行权衡:

采用String类型的话,命名方式大概如下:daily-limit/month-limit:riskcode:bankcode:channel

下面展示一下以险种50022,银行02,渠道17,限制日额,份数1000为例:

127.0.0.1:6379> set daily-limit:50022:02:17 1000
OK
127.0.0.1:6379> decrby daily-limit:50022:02:17 15
(integer) 985
127.0.0.1:6379> decrby daily-limit:50022:02:17 8
(integer) 977
127.0.0.1:6379> decrby daily-limit:50022:02:17 23
(integer) 954
127.0.0.1:6379>

每日签发保单的同时,对redis存储的相关key值对应的日额减相应份数即可。

如果采用Hash类型存储的话,控制条件依然众多,虽然部分条件可以转为field存储,但是Hash key值的命名并不会因此获得很大的简化,反而增加操作量。Key值命名:limit:riskcode:bank:channel field包括:daily、month

以险种50022,银行02,渠道17,限制日额份数1000,月额份数20000为例:

127.0.0.1:6379> hmset limit:50022:02:17 daily 1000 month 20000
OK
127.0.0.1:6379> hgetall limit:50022:02:17
1) "daily"
2) "1000"
3) "month"
4) "20000"
127.0.0.1:6379> hincrby limit:50022:02:17 daily -15
(integer) 985
127.0.0.1:6379> hincrby limit:50022:02:17 daily -8
(integer) 977
127.0.0.1:6379> hincrby limit:50022:02:17 daily -23
(integer) 954
127.0.0.1:6379>

此时对两种方式进行权衡:

  • String类型:日额、月额需要设置两个key值,但是使用简单。
  • Hash类型:日额、月额同一hash,分别存储为不同field,省去了额外key的开销,但是jedis操作相对繁琐。

此时需要对安邦实际的险种、银行、渠道数量进行统计,如果需要制定的key值量很大,采用Hash类型,如果量不大,采用String类型。当然,除了着眼当前,还要考虑将来的业务扩展。

产品接入

产品接入功能,也不建议再设计实体表,因为此功能只涉及产品代码的转换功能,整体的量也不会很大,对内存的占用可以忽略不计,且数据K-V形式明显,采用redis单独持久化,也省去了与Oracle进行交互获取缓存,最大限度提升处理效率。
命名规则:trans:riskcode
例:

127.0.0.1:6379> mset trans:122001 2001 trans:122002 2002 trans:122003 2003
OK
127.0.0.1:6379> get trans:122001
"2001"
127.0.0.1:6379> get trans:122002
"2002"
127.0.0.1:6379>

封装Redis转换产品代码方法,可以通过XSL直接通过select方式调用,使得redis可以无缝接入。

持久化方式:个人感觉通过redis默认的rdb快照的持久化方式就可以满足需要,通过设置持久化的频率,最大限度的规避redis服务器down机的风险。

XSL所有的字典转换

与产品代码转换相同,XSL中需要将银行数据转换为保险公司数据需要通过字典转换的地方有很多,比较典型的类似国籍转换,动辄几百行,显得十分冗余。 将字典转换为redis K-V存储,可以大大减少代码量。

  • 命名规则:trans:dic-type:riskcode

  • 国籍:trans:nation:riskcode

  • 职业代码:trans:jobcode:riskcode

总结

由于银保通系统相对比较传统,升级Redis并不像想象的那样简单。不过还是要提出一个方案,至于采纳不采纳,就是领导的事情了。


Similar Posts

上一篇 Redis总结

下一篇 AES加密算法

Comments