您好
欢迎访问

优惠券怎么制作(一个租房房源平台发布C端曝光获客功能(图))

背景

部门是租房平台,为各类商家提供挂牌挂牌、C端曝光获客的功能。 现在需要在各个节假日节点为商户营销活动搭建优惠券系统。 该形式主要是为商家在B端参与活动,为房屋绑定优惠券,以出租价格打折吸引用户在C端租房。

一、业务回顾

理清了大致的业务背景之后,我们来梳理一下整体的业务流程,如下图所示。

首先,平台建立活动,在商户B端展示可报名的活动,商户通过报名对应折扣力度的活动,创建折扣对应的优惠券。

然后,通过建立房源与对应的优惠券的绑定关系,为房源数据打上优惠券标识。 这样,在C端展示房源时,可以筛选出对应的优惠房源,用户可以在房源上领取某类优惠券。

最后,用户在C端领取优惠券后,可以联系商家进行上门看房。 如果双方达成一致,可以在线签订合同。 可在签约时使用相应的优惠券,实现相应的价格优惠。

至此,就是整个系统的完整正过程。

2、技术设计

下面是各个环节对应的技术设计。

2.1 构建活动 2.1.1 数据表

活动信息需要以下数据项

下面是活动信息数据表的具体设计

CREATE TABLE `t_activity` (
  `activeId` bigint(20) NOT NULL COMMENT '活动ID',
  `title` varchar(256) NOT NULL COMMENT '活动名称',
  `applyStartTime` timestamp NULL DEFAULT NULL COMMENT '报名开始时间',
  `applyEndTime` timestamp NULL DEFAULT NULL COMMENT '报名停止时间',
  `activityStartTime` timestamp NULL DEFAULT NULL COMMENT '活动开始时间',
  `activityEndTime` timestamp NULL DEFAULT NULL COMMENT '活动结束时间',
  `cityIds` varchar(256) NOT NULL COMMENT '覆盖城市,多个逗号分隔',
  `couponType` tinyint(4) NOT NULL DEFAULT '0' COMMENT '优惠类型,1 直减;2 折扣;3免费住N天;4免押金;5特价房',
  `lowerLimit` int NOT NULL DEFAULT 0 COMMENT '优惠数值下限',
  `upperLimit` int NOT NULL DEFAULT 0 COMMENT '优惠数值上限',
  `description` text COMMENT '活动描述',
  `cubeType` smallint(6) NOT NULL DEFAULT '1001' COMMENT '活动类型',
  `foreignId` bigint(20) NOT NULL DEFAULT '0' COMMENT '外部ID',
  `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '活动状态',
  `createTime` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  `updateTime` timestamp NULL DEFAULT NULL COMMENT '更新时间',
  `recordStatus` tinyint(4) NOT NULL DEFAULT '0' COMMENT '数据状态',
  PRIMARY KEY (`activeId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='活动信息表';

2.1.2 数据读取

商户端可以通过status字段和cityIds字段显示可以注册的活动。

在C端读取的展示代码中,可以使用设计模式中的代理模式,增加一层缓存,正在进行的活动会将数据推送到缓存层。

2.1.3 活动状态流

通过crontab定时任务,每分钟检查时间段,更新相应的状态字段,完成活动状态的流转。

2.1.4 数据读取

可以在设计模式中使用代理模式,增加一层缓存。 非强实时的查询去缓存,缓存中不存在的或者需要实时数据的去db。

2.2 商家注册创建优惠券 2.2.1 数据表

CREATE TABLE `t_couponmeta` (
  `couponMetaId` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '券id',
  `appId` int(11) NOT NULL DEFAULT '1' COMMENT '区分建立来源',
  `activeId` bigint(20) NOT NULL DEFAULT '0' COMMENT '活动ID',
  `companyId` bigint(20) NOT NULL COMMENT '公司编号',
  `cityId` int(11) NOT NULL COMMENT '城市id',
  `companyName` varchar(255) DEFAULT NULL COMMENT '公司名称',
  `companyShortName` varchar(255) DEFAULT NULL COMMENT '公司简称',
  `couponType` tinyint(4) NOT NULL COMMENT '优惠券类型',

  `title` varchar(256) NOT NULL COMMENT '优惠券名称',
  `directDiscount` int(11) NOT NULL DEFAULT '0' COMMENT '直减券优惠力度',
  `discount` int(11) NOT NULL DEFAULT '0' COMMENT '折扣力度',
  `freeLive` int(11) NOT NULL DEFAULT '0' COMMENT '免费住n天券',
  `threshold` varchar(256) NOT NULL COMMENT '使用门槛',
  `deduction` tinyint(4) NOT NULL DEFAULT '1' COMMENT '抵扣说明 1首月抵扣,2 平摊到月',
  `totalAmount` int(11) NOT NULL DEFAULT '0' COMMENT '券总数',
  `applyAmount` int(11) NOT NULL DEFAULT '0' COMMENT '已领取总数',
  `activityStartTime` timestamp NULL DEFAULT NULL COMMENT '活动开始时间',
  `activityEndTime` timestamp NULL DEFAULT NULL COMMENT '活动结束时间',
  `startTime` timestamp NULL DEFAULT NULL COMMENT '券使用开始时间',
  `expireTime` timestamp NULL DEFAULT NULL COMMENT '券使用结束时间',
  `status` int(11) NOT NULL DEFAULT '10' COMMENT '10:新建未启用,20:已启用,30:过期, 40 已结束 50 已中止',
  `expireType` tinyint(4) NOT NULL DEFAULT '1' COMMENT '类型:1固定有效期类型,2浮动有效期类型',
  `validPeriod` tinyint(4) NOT NULL DEFAULT '0' COMMENT '浮动有效期(单位:天)',
  `tenantRange` tinyint(1) NOT NULL DEFAULT '1' COMMENT '租客范围枚举值',
  `customScope` varchar(256) NOT NULL DEFAULT '' COMMENT '自定义租客范围',
  `comment` varchar(50) DEFAULT NULL COMMENT '备注',
  `cubeType` smallint(6) NOT NULL DEFAULT '1001' COMMENT '活动类型',
  `updateTime` timestamp NULL DEFAULT NULL COMMENT '更新时间',
  `createTime` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  `recordStatus` tinyint(4) DEFAULT '0' COMMENT '状态 0默认 -1删除',
  PRIMARY KEY (`couponMetaId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='优惠券表';

2.2.2 数据读取

也可以在设计模式中使用代理模式,增加一层缓存。 对于C端读取大量优惠券信息的场景,需要尽量让读取的请求在缓存层处理,减少db的压力。

2.2.3 状态转换

优惠券状态流程如图

大部分状态取决于活动的状态(暂停和过期除外),所以在活动状态的crontab任务中,当发现活动状态发生变化时,会通过MQ发出下面的优惠券状态变化任务, 折扣将异步修改优惠券的状态。 优惠券状态的变化也会涉及联动数据的更新,例如:

可以想象,在每次状态转换期间,有许多操作要执行。 为了保证业务逻辑的清晰,我使用了状态模式来实现状态流。 类图如下:

状态更新后,C端房屋指标数据/B端基本房屋数据/缓存中的数据,这些数据的更新使用观察者模式监听状态的变化,数据更新由在observer中异步发送mq,类图如下:

通过在CouponStateMachine中注册需要的观察者,在实际的doChangeStatus操作之后,通知所有的观察者,保证联动数据的正确性。

2.3 绑定优惠券 2.3.1 数据表

将商户b端绑定的全量优惠券(新创建/激活/未过期)数据存储在MySQL数据表中。 表结构比较简单,如下图:

CREATE TABLE `t_bindcoupon` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `couponMetaId` int(11) NOT NULL COMMENT '券id',
  `companyId` bigint(20) NOT NULL COMMENT '公司编号',
  `activityStatus` tinyint(4) NOT NULL COMMENT '状态 0 准备中 1 活动中 2 活动结束 券未失效 3活动结束券失效',
  `houseId` bigint(20) NOT NULL DEFAULT '0' COMMENT '房源id',
  `recordStatus` tinyint(4) NOT NULL COMMENT '数据状态 0 有效,-1 失效',
  `createTime` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  `updateTime` timestamp NULL DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_companyId_couponMetaId` (`companyId`,`couponMetaId`),
  KEY `idx_planeId` (`planeId`),
  KEY `idx_houseid_activitystatus` (`houseId`,`activityStatus`)
) ENGINE=InnoDB AUTO_INCREMENT=17379 DEFAULT CHARSET=utf8 COMMENT='优惠券绑定范围表'

优惠券怎么制作(一个租房房源平台发布C端曝光获客功能(图))

该表主要记录了listing和coupon的绑定关系,记录了当前的绑定状态。 该状态用于限制同一个listing绑定过多的有效优惠券,限制商家增加c端曝光,随意操作。

操作listing绑定优惠券时,会使用分布式锁,避免并发绑定操作造成的超限

2.3.2 数据显示

数据的展示依赖于C端的索引数据。 有效状态的优惠券信息存储在索引数据中。 字段用于结合业务场景进行筛选展示,如下:

优惠券 ID(多值) 事件 ID(多值) 参加的事件类型(多值)

通过索引过滤条件获取listing数据后,可以获取listing的完整数据,获取listing绑定了哪些优惠券,并展示优惠券数据。

2.3.3 状态转换

绑定关系状态的实时更新有两个触发动作,根据情况更新数据的status和recordStatus两个字段:

当2.2.3中基于优惠券状态的MQ消息db的绑定数据发生变化(变化/增加/减少)时,也会发送MQ异步更新索引中的数据。

2.4 C端用户领取优惠券

是C端用户领取优惠券比较重要的地方。 核心要求是不能多领优惠券,尽量避免少领优惠券。 具体设计流程图如下:

过程大致分为三步:

请求验证redis库存扣减和取货记录更新库存任务以事务的形式写入MySQL

下面逐步说明如图

2.4.1 数据读取

由于在C端浏览优惠券详情&领取优惠券可能是一个高并发操作,所以尽量从缓存中读取数据,包括以下数据:

活动信息优惠券信息优惠券库存

活动开始前五分钟禁止编辑活动信息和优惠券信息。 事件开始时,上述数据会被压入缓存,不会设置过期时间,事件状态变化到结束时,数据会被清空。

同时在web服务集群中,对这1 2个数据项做一个短期的本地缓存,以减少请求redis集群的网络开销。

2.4.2 验证

首先,服务器收到用户领取优惠券的请求后,会检查redis中是否有领取记录缓存。 这可以使用布隆过滤器来实现。 关键是优惠券 ID。 如果其中存在用户id,则直接返回。

然后,将检查优惠券的状态。 优惠券数据会在活动开始时推送到redis中,可以直接使用redis中的数据查看。

最后优惠券怎么制作,它会检查优惠券的库存数据是否存在。 为了提高容错性和可用性,如果不存在,则发送一个MQ初始化盘点任务,然后直接返回。 MQ 将异步重新初始化库存数据以避免缓存命中。 穿着问题。

2.4.3 库存扣除

使用乐观锁直接操作db扣库存。 MySQL的库存更新操作会成为并发热点,请求会在争抢行锁中被阻塞。 支持的并发数有限,会给db带来压力。 由于redis可以保证操作的原子性,而且数据在内存中,适合高并发场景,所以使用redis来完成库存的扣减。

db inventory 更新操作通过db message task table 异步序列化,避免阻塞,减少锁争用。

但是如果是基于redis进行库存的扣减,可以分为以下几种情况:

redis扣款成功优惠券怎么制作,但是db collection record和update inventory任务写入失败,执行回滚,增加库存数量。 redis扣款失败(缺货/redis宕机),不会进行db操作。 redis扣费成功。 db事务执行时,业务运行机器重启或宕机,库存未回滚,导致理赔不足。 redis扣费成功后,redis主库宕机,数据成功写入DB,但是扣费数据没有同步到从库,从库使用时出现过领现象扣除。

1 2 正常,3 4 异常。

对于case 3,当redis中的库存耗尽时,可以触发一个异步任务来比对库存数据。 如果还有可用的库存,更新redis的库存信息,避免出现欠收的情况。

对于case 4,由于redis不能保证主从强一致性,在数据操作丢失的情况下,可能会出现过领情况。

我的想法是有以下几种方式:

如果在更新库存操作中已经出现超收情况,删除或冻结用户收到的优惠券数据淘宝打折,以免造成损失。 剩余库存每变化5%,就会执行一个异步任务,冻结优惠券的状态,使C端无法收到优惠券。 然后在处理完当前消息事务表中db的扣账任务后,再进行redis和db的数据校验和同步。 同步完成后,优惠券解冻,恢复正常领取。 由于redis属于AP,如果要保证数据的强一致性,就需要牺牲可用性,改用CP存储。 核销联票时,检查核销数量是否超过总数量。 如果达到阈值,会提示优惠券不可用。 根据发放的优惠券总数,生成一批优惠券id,同时存入db和redis队列,通过pop id生成优惠券领取记录,根据是否领取限制重复领取id 相同,以防止过度收集。

第一种方式,当用户成功领取优惠券并执行更新db库存的任务时,在中间时间窗口很小的情况下,尽可能避免过度领取和使用的情况.

第二种方法并不能完全解决超额问题,只能在少量时间牺牲索赔功能,在索赔请求没有激增的情况下纠正数据不一致。

第三种方法不再详细描述。

第四种方式是被动核对数量,确保使用的优惠券不会超过发放的总量。 个人认为是比较软的处理方式,影响最小,但是可能会引起客户投诉,(为什么?我收到后还是不能用!!!)

第五种方式,根据发券总数在db中生成一批收藏记录,但收藏用户id和收藏时间为空。 将这批记录的id存入redis队列,扣库存时弹出队列。 获取到id后,通过乐观锁更新id对应的数据行(其中id=x,userId=0),如果更新失败则接收。 这样可以有效防止第四种情况的发生。 需要考虑的是,如果分发的金额太大,而实际收到的却很少,活动结束后需要清理占用的数据表空间。 插入db的数据需要事先预热,未绑定userId的数据需要事后清理。

在我的业务场景中,经过考虑,我主要选择了第四种方式。 第二种方法选择每天早上4点做一次。 第一种方法不删除,只报警。

如果有更好的方法,希望大神指点。

2.5 优惠券注销

以微服务的形式,提供用户优惠券获取接口和状态变化接口,供调用方使用。 状态流分为三种状态:未使用、锁定和使用。

当客户下签单时,相应的优惠券将被锁定。 如果订单完成,会调用该接口将状态更改为已使用。 如果订单被取消,回滚券的状态将变为未使用。

未来可以优化方向用户的优惠券数据分库和分表,数据可以水平拆分,提高读写db的能力。 Redis 集群分片部署,以提高可用性和容量。 集群拆分,每个集群只处理部分优惠券请求,通过网关将请求拆分到不同的pod。 引入jd-hotkey组件,hot key实时同步到集群本地缓存,减少对分布式缓存的访问。 引入canal组件,通过binlog同步db更新信息,更新缓存,进行数据联动更新。总结

至此,一个完整的优惠券系统已经构建完成。

遵循读多写少缓存,写多读少队列的原则。

对于显示的活动数据,代码尽可能采用代理方式通过缓存读取。 在使用多级缓存的同时,为了避免缓存崩溃的场景,主动将activity中的数据推送到redis。

对于activity->coupon->housing联动数据的写操作,代码通过状态模式+观察者模式实现,MQ控制并发的异步更新。

Redis用于库存扣减,依赖于它的原子性,但是redis不保证集群内的数据强一致性。 为避免套领造成的损失问题,在取消优惠券时进行数量阈值检查。

对于热点的db inventory更新,使用了db事务消息表。 通过事务保证当记录插入成功后,一定会落入更新库存的任务中,从而做到库存更新异步串行进行。

赞(0)
转载请注明出处:0512打折网 » 优惠券怎么制作(一个租房房源平台发布C端曝光获客功能(图))
分享到: 更多 (0)