为了文档的简洁性特,下面为文档的关键词说明:

  • 文中的系统若无特殊说明一律表示三方b2b系统
  • 文中的活动泛指三方b2b系统中所有支持的活动

活动背景介绍

目前系统支持秒杀套餐满减优惠券4种活动,活动都有活动范围的配置,而活动范围又分为:商品范围客户范围。每种活动范围都支持黑名单白名单一个活动必须要配置这个活动的商品范围和客户范围来确定可以参加活动的用户和商品。

活动范围介绍

活动范围分为商品范围和客户范围,具体支持如下:

商品范围 范围类型描述 Redis中的标识符 数据库中的字段名称
一个商品 M (Merchandise) store_prod_no(店铺商品编码)
一个商品标签对应的所有商品 L (Label) label_id(标签ID)
一个店铺下所有的商品 S (Store) store_no(店铺编码)
客户范围 一个客户 C (Cust) cust_id(客户ID)
一种客户类型对应的所有客户 T (Type) cust_type_id(客户类型ID)
一个客户区域下所有客户 A (Area) ad_code(区域编码)
一个客户标签对应的所有客户 B label_id(标签ID)

黑白名单介绍

上面介绍的活动范围中整个范围可能是黑名单范围,也可能是白名单范围。本质上黑白名单就是活动范围的一种属性,一个活动范围要么是黑名单,要么是白名单。在Redis中使用+表示白名单,使用-表示黑名单。下面简单介绍一下黑白名单的配置数据在Redis中的表示:

黑白名单场景 Redis中的表示方式
一个商品在黑名单中 -M{store_prod_no}
一个店铺下所有的商品在白名单中 +S{store_no}
商品黑名单为空 +ALL
一个客户区域下所有客户在黑名单中 -A{ad_code}
一个客户标签对应的所有客户在白名单中 +B{label_id}
客户黑名单为空 +ALL

注意: +ALL是一种特殊情况,即配置使用黑名单范围但是黑名单为空。但是这里没有-ALL的情况,因为如果使用了白名单,那么这个白名单至少要有一条白名单记录,否则这个活动范围没有意义(因为没有商品或者没有用户能参加这个活动)

Redis缓存结构设计

这里的所有缓存结构都使用的是Redis的key -> SET数据结构,特殊数据处理时逻辑如下:

  • store_no为空表示站点活动
  • 匿名用户的cust_id值使用-1

设计目标

设计Redis缓存结构的目的是能根据一个用户(cust_id)和一批商品(store_prod_no集合)能快速的到这个用户能在每种商品上参加的活动集合(Map<store_prod_no, Set<activity_id>>)。以这个设计目标我们设计出三种Redis缓存key结构,下面开始具体讲解。

三种Redis Key结构介绍

Redis key value 的数据结构表达方式或者语法如下:
变量: 变量使用大括号包裹,如 {变量名}
枚举: 使用中括号包裹,使用”/“分割各种选项(必须要选择一个选项),如 [可选项1/可选项2/可选项3]
内容块: 使用小括号包裹(没有特殊含义,仅仅方便阅读),如 (内容块)
上述使用的大括号中括号小括号只是为了表达 key value 的数据结构,并不在数据中,例如: -A{ad_code} 当ad_code=420100,表示字符串-A420100

第一种结构

  • key结构: activity:all
  • value结构: {activity_id}|{store_no}

第一种结构的key的是个字符串常量,所以只有一条记录,主要用于管理所有活动的缓存数据

第二种结构

  • key结构: activity:key:{activity_id}|{store_no}
    • 这个结构中变化部分{activity_id}|{store_no}就是第一种结构的value
  • value结构: activity:[([+/-]M{store_prod_no})/([+/-]L{label_id})/(+ALL|[+/-]S{store_no})/+ALL]:([+/-]C{cust_id})/([+/-]T{cust_type_id})/[([+/-]A{ad_code})/([+/-]B{label_id})/+ALL]
    • 不要被这个看似复杂的结构吓到,其实这个结构的本质就是 activity:{商品范围}:{客户范围}
    • [([+/-]M{store_prod_no})/([+/-]L{label_id})/(+ALL|[+/-]S{store_no})/+ALL]就是商品范围部分(商品范围配置数据),详细如下:
      • ([+/-]M{store_prod_no}): (黑/白名单中的)一个商品
      • ([+/-]L{label_id}): (黑/白名单中的)一个商品标签对应的所有商品
      • (+ALL|[+/-]S{store_no}): (黑/白名单中的)一个店铺下所有的商品
      • +ALL: 所有商品在白名单中
    • 同样[([+/-]C{cust_id})/([+/-]T{cust_type_id})/([+/-]A{ad_code})/([+/-]B{label_id})/+ALL]就是客户范围部分(客户范围配置数据),详细如下:
      • ([+/-]C{cust_id}): (黑/白名单中的)一个客户
      • ([+/-]T{cust_type_id}): (黑/白名单中的)一种客户类型对应的所有客户
      • ([+/-]A{ad_code}): (黑/白名单中的)一个客户区域下所有客户
      • ([+/-]B{label_id}): (黑/白名单中的)一个客户标签对应的所有客户
      • +ALL:所有客户在白名单中
    • 这里的value集合的业务含义是:存储了当前活动的所有活动范围配置

第二种结构就是以活动为维度,把一个活动的商品范围和客户范围进行笛卡尔运算,得到当前活动的所有活动范围配置,然后把笛卡尔运算的结果存进Redis中。

第三种结构

  • key结构: activity:[([+/-]M{store_prod_no})/([+/-]L{label_id})/(+ALL|[+/-]S{store_no})/+ALL]:([+/-]C{cust_id})/([+/-]T{cust_type_id})/[([+/-]A{ad_code})/([+/-]B{label_id})/+ALL]
    • 这个key结构就是第二种结构中的value结构(一模一样)
  • value结构: {activity_id}|{store_no}
    • 这里的value集合的业务含义是:拥有当前活动范围配置的所有活动(activity_id)

活动范围的笛卡尔运算介绍

上面已经说过+表示白名单-表示黑名单,如果活动范围使用的是黑名单在进行笛卡尔运算之前需要加入ALL元素。下面我们用一个示例讲解笛卡尔运算规则

一个活动配置如下:

  • 商品范围(使用白名单)
    • 001_store_prod_no (一个商品)
    • 001_prod_label_id (一个商品标签对应的所有商品)
  • 客户范围(使用黑名单)
    • 001_cust_id (一个客户)
    • 001_ad_code (区域编码)

笛卡尔运算的原数据如下:

  • 商品范围(使用白名单)

    • +M001_store_prod_no
    • +L001_prod_label_id
  • 客户范围(使用黑名单)

    • +ALL(因为使用的是黑名单)
    • -C001_cust_id
    • -A001_ad_code

笛卡尔运算的结果如下(activity:{商品范围}:{客户范围}):

  • activity:+M001_store_prod_no:+ALL
  • activity:+M001_store_prod_no:-C001_cust_id
  • activity:+M001_store_prod_no:-A001_ad_code
  • activity:+L001_prod_label_id:+ALL
  • activity:+L001_prod_label_id:-C001_cust_id
  • activity:+L001_prod_label_id:-A001_ad_code

注意: 当商品范围和客户范围都使用黑名单时做笛卡儿积会出现 activity:-xxx:-xxx的结果,类似这样的结果不需要保存(因为这类数据的业务含义重复了),当然保存了也不会有啥影响只是多存储一些数据而已

Redis活动缓存的初始化流程

上面讲完三种Redis Key结构之后,接下来就需要把数据库里面的活动范围配置数据加载到刚刚设计的缓存结构中,其加载流程图如下:

Redis活动缓存的初始化流程

这个流程图只是一个大致的流程,具体代码实现逻辑比这个要复杂的多

Redis缓存使用流程

现在我们通过一个流程图来看看Redis缓存是如何实现我们的设计目标的。
根据一个用户(cust_id)和一批商品(store_prod_no集合)能快速的到这个用户能在每种商品上参加的活动集合(Map<store_prod_no, Set<activity_id>>)

Redis缓存使用流程

完整用例说明

上面讲解了Redis缓存实现根据cust_id和store_prod_no快速搜索activity_id的原理和具体逻辑,现在我们来构造一个具体的示例来描述整个过程,让你更好的理解前面的讲解。

活动配置

Redis活动缓存数据

Redis缓存使用

文档更新时间: 2019-08-24 12:54   作者:lizw