散记网 > 科技 >

因为BitMap,白白搭进去8台服务器...

2020-09-12散记网 正體
分享到:
“ 最近,因为增加了一些风控措施,导致新人拼团订单接口的 QPS、TPS 下降了约 5%~10%,这还了得!图片来自 Pexels首先,快速解释一下【新人拼团】活动:业务简介:顾名思义,新人拼团

最近,因为增加了一些风控措施,导致新人拼团订单接口的 QPS、TPS 下降了约 5%~10%,这还了得!

图片来自 Pexels

首先,快速解释一下【新人拼团】活动:


业务简介:顾名思义,新人拼团是由新用户发起的拼团,如果拼团成功,系统会自动奖励新用户一张满 15.1 元减 15 的平台优惠券。


这相当于是无门槛优惠了。每个用户仅有一次机会。新人拼团活动的最大目的主要是为了拉新。


新用户判断标准:是否有支付成功的订单 ? 不是新用户 : 是新用户。


当前问题:由于像这种优惠力度较大的活动很容易被羊毛党、黑产盯上。因此,我们完善了订单风控系统,让黑产无处遁形!


然而由于需要同步调用风控系统,导致整个下单接口的的 QPS、TPS 的指标皆有下降,从性能的角度来看,【新人拼团下单接口】无法满足性能指标要求。因此 CTO 指名点姓让我带头冲锋……冲啊!


问题分析


风控系统的判断一般分为两种:在线同步分析和离线异步分析。在实际业务中,这两者都是必要的。


在线同步分析可以在下单入口处就拦截掉风险,而离线异步分析可以提供更加全面的风险判断基础数据和风险监控能力。


最近我们对在线同步这块的风控规则进行了加强和优化,导致整个新人拼团下单接口的执行链路更长,从而导致 TPS 和 QPS 这两个关键指标下降。


解决思路


要提升性能,最简单粗暴的方法是加服务器!然而,无脑加服务器无法展示出一个出色的程序员的能力。CTO 说了,要加服务器可以,买服务器的钱从我工资里面扣……


在测试环境中,我们简单的通过使用 StopWatch 来简单分析,伪代码如下:

@Transactional(rollbackFor = Exception.class)
public CollageOrderResponseVO colleageOrder(CollageOrderRequestVO request) {
    StopWatch stopWatch = new StopWatch();

    stopWatch.start("调用风控系统接口");
    // 调用风控系统接口, http调用方式
    stopWatch.stop();

    stopWatch.start("获取拼团活动信息"); // 
    // 获取拼团活动基本信息. 查询缓存
    stopWatch.stop();

    stopWatch.start("获取用户基本信息");
    // 获取用户基本信息。http调用用户服务
    stopWatch.stop();

    stopWatch.start("判断是否是新用户");
    // 判断是否是新用户。 查询订单数据库
    stopWatch.stop();

    stopWatch.start("生成订单并入库");
    // 生成订单并入库
    stopWatch.stop();

    // 打印task报告
    stopWatch.prettyPrint();

   // 发布订单创建成功事件并构建响应数据
    return new CollageOrderResponseVO();
}

执行结果如下:

StopWatch '新人拼团订单StopWatch': running time = 1195896800 ns
---------------------------------------------
ns         %     Task name
---------------------------------------------
014385000  021%  调用风控系统接口
010481800  010%  获取拼团活动信息
013989200  015%  获取用户基本信息
028314600  030%  判断是否是新用户
028726200  024%  生成订单并入库

在测试环境整个接口的执行时间在 1.2s 左右。其中最耗时的步骤是【判断是否是新用户】逻辑。


这是我们重点优化的地方(实际上,也只能针对这点进行优化,因为其他步骤逻辑基本上无优化空间了)。


确定方案


在这个接口中,【判断是否是新用户】的标准是是用户是否有支付成功的订单。因此开发人员想当然的根据用户 ID 去订单数据库中查询。


我们的订单主库的配置如下:

这配置还算豪华吧。然而随着业务的积累,订单主库的数据早就突破了千万级别了,虽然会定时迁移数据,然而订单量突破千万大关的周期越来越短……(分库分表方案是时候提上议程了,此次场景暂不讨论分库分表的内容)而用户 ID 虽然是索引,但毕竟不是唯一索引。因此查询效率相比于其他逻辑要更耗时。


通过简单分析可以知道,其实只需要知道这个用户是否有支付成功的订单,至于支付成功了几单我们并不关心。


因此此场景显然适合使用 Redis 的 BitMap 数据结构来解决。在支付成功方法的逻辑中,我们简单加一行代码来设置 BitMap:

// 说明:key表示用户是否存在支付成功的订单标记
// userId是long类型
String key = "order:f:paysucc"; 
redisTemplate.opsForValue().setBit(key, userId, true);

通过这一番改造,在下单时【判断是否是新用户】的核心代码就不需要查库了,而是改为:

Boolean paySuccFlag = redisTemplate.opsForValue().getBit(key, userId);
if (paySuccFlag != null && paySuccFlag) {
    // 不是新用户,业务异常
}

修改之后,在测试环境的测试结果如下:

StopWatch '新人拼团订单StopWatch': running time = 82207200 ns
---------------------------------------------
ns         %     Task name
---------------------------------------------
014113100  017%  调用风控系统接口
010193800  012%  获取拼团活动信息
013965900  017%  获取用户基本信息
014532800  018%  判断是否是新用户
029401600  036%  生成订单并入库

测试环境下单时间变成了 0.82s,主要性能损耗在生成订单入库步骤,这里涉及到事务和数据库插入数据,因此是合理的。接口响应时长缩短了 31%!相比生产环境的性能效果更明显……接着舞!

晴天霹雳


这次的优化效果十分明显,想着 CTO 该给我加点绩效了吧,不然我工资要被扣完了呀~


一边这样想着,一边准备生产环境灰度发布。发完版之后,准备来个葛优躺好好休息一下,等着测试妹子验证完就下班走人。


然而在我躺下不到 1 分钟的时间,测试妹子过来紧张的跟我说:“接口报错了,你快看看!”What?


当我打开日志一看,立马傻眼了。报错日志如下:

io.lettuce.core.RedisCommandExecutionException: ERR bit offset is not an integer or out of range
at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:135) ~[lettuce-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:108) ~[lettuce-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at io.lettuce.core.protocol.AsyncCommand.completeResult(AsyncCommand.java:120) ~[lettuce-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at io.lettuce.core.protocol.AsyncCommand.complete(AsyncCommand.java:111) ~[lettuce-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at io.lettuce.core.protocol.CommandHandler.complete(CommandHandler.java:654) ~[lettuce-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:614) ~[lettuce-core-5.2.1.RELEASE.jar:5.2.1.RELEASE]
…………

bit offset is not an integer or out of range。这个错误提示已经很明显:我们的 offset 参数 out of range。


为什么会这样呢?我不禁开始思索起来:Redis BitMap 的底层数据结构实际上是 String 类型,Redis 对于 String 类型有最大值限制不得超过 512M,即 2^32 次方 byte…………我靠!!!


恍然大悟


由于测试环境历史原因,userId 的长度都是 8 位的,最大值 99999999,假设 offset 就取这个最大值。


那么在 Bitmap 中,bitarray=999999999=2^29byte。因此 setbit 没有报错。


而生产环境的 userId,经过排查发现用户中心生成 ID 的规则变了,导致以前很老的用户的 id 长度是 8 位的,新注册的用户 id 都是 18 位的。


以测试妹子的账号 id 为例:652024209997893632=2^59byte,这显然超出了 Redis 的最大值要求。不报错才怪!


紧急回退版本,灰度发布失败~还好,CTO 念我不知道以前的这些业务规则,放了我一马~该死,还想着加绩效,没有扣绩效就是万幸的了!


本次事件暴露出几个非常值得注意的问题,值得反思:


①懂技术体系,还要懂业务体系


对于 BitMap 的使用,我们是非常熟悉的,对于多数高级开发人员而言,他们的技术水平也不差,但是因为不同业务体系的变迁而无法评估出精准的影响范围,导致无形的安全隐患。


本次事件就是因为没有了解到用户中心的 ID 规则变化以及为什么要变化从而导致问题发生。

②预生产环境的必要性和重要性


导致本次问题的另一个原因,就是因为没有预生产环境,导致无法真正模拟生产环境的真实场景,如果能有预生产环境,那么至少可以拥有生产环境的基础数据:用户数据、活动数据等。


很大程度上能够提前暴露问题并解决。从而提升正式环境发版的效率和质量。

③敬畏心


要知道,对于一个大型的项目而言,任何一行代码其背后都有其存在的价值:正所谓存在即合理。


别人不会无缘无故这样写。如果你觉得不合理,那么需要通过充分的调研和了解,确定每一个参数背后的意义和设计变更等。以尽可能降低犯错的几率。


后记


通过此次事件,本来想着优化能够提升接口效率,从而不需要加服务器。这下好了,不仅生产环境要加 1 台服务器以临时解决性能指标不达标的问题,还要另外加 7 台服务器用于预生产环境的搭建!


因为 BitMap,搭进去了 8 台服务器。痛并值得。接着奏乐,接着舞~~~


作者:浪漫先生

编辑:陶家龙

出处:https://juejin.im/post/6854573218322513933

精彩文章推荐:

飞天茅台超卖事故:Redis分布式锁请慎用!熬了一个通宵,终于把7千万个Key删完了就是要让你搞懂Nginx,这篇就够了!

相关推荐:

科目四过了怎么拿驾照,刚拿到驾照要注意什么

科目四过了怎么拿驾照,刚拿到驾照要注意什么,很多人在顺利考过科目四之后,会想要马上开车上路,但驾照又还没下来,就会不知道这样做是不是对的,那科目四过了驾照没拿可以开车...

探探怎样玩,怎样看到有多少人喜欢你?

探探是一款能让你立即脱单的交友app,向右滑照片匿名喜欢ta,向左滑照片跳过ta,如果你喜欢的人也喜欢你,就可以匿名聊天啦!那么探探怎么看喜欢我的人?下面就来讲讲探探怎么看喜...

QQ如何设置加好友问题验证

QQ是近年来一直都比较受欢迎的一款社交app,发展到现在,也有很多的功能供我们使用。那我们应该如何设置加好友问题验证呢,一起来看一下。...

QQ被盗怎么办

打开“腾讯QQ”--点击“找回密码”选项。然后会进入到“QQ安全中心”的页面,输入QQ号码和验证码,点击确定。...

5G手机是不是要开通5G套餐才能使用 5G手机什么时

5G信号目前在大部分大中城市已经普及,我们已经正式的进入了5G时代,5G也会给我们带来更多各种各样不同的机会,很多人已经开始尝鲜5G了,各大品牌也是陆续出了各种5G手机,那么...

qq会员怎么免费领取金豆?

QQ作为一款娱乐聊天工具,推出了越来越多的功能,会员的权益也越来越多了,QQ会员每天可以领金豆也是其中的权益之一。...

点击阅读全文

上一篇:调查报告显示,中国消费者在选购无线耳机时更看重这个指标

下一篇:中印外长达成五点共识,发表联合新闻稿;华为宣布了,手机将全面支持鸿蒙;普京也道歉了

相关阅读

三大策略助力线上线下融合会展新模式

2020-09-10

随着时代发展和科技进步,疫情乌云笼罩下的会展行业也开始复苏,线上展览也在会展行业内大规模的蓬勃发展起来。31会议

49岁俞飞鸿一句话刺痛无数人:中年夫妻,早就各

2020-09-02

回复【早安】送你一张专属祝福卡片文 | 顾清若 · 主播 | 亚楠有一种女人,要想在人群中脱颖而出,哪里需要美丽的皮囊,

黄奇帆:中国面临十面埋伏

2020-08-23

口述:黄奇帆 中国国际经济交流中心副理事长摘自黄奇帆最新演讲来源:光远看经济(ID:guangyuanview)在8月8日的中国寿险

国内一地通报:7人阳性,1名密接者!钟南山最新

2020-09-14

13日,浙江省岱山县新型冠状病毒感染的肺炎疫情防控工作领导小组办公室发布通报称↘9月9日中午,接舟山海关通报,在岱

做好站内站外优化,网站SEO优化效果才能一步到位

2020-09-10

其实不管是通过提高网站权重,还是提升关键词排名,又或者是采集站的形式,最终解决的都是网站引流问题。 引流虽然是

火星地表上有液态水吗 火星地表河道湖泊图片

2020-09-12

水是生命之源,近年来,关于火星地表上是否有液态水成为科学家们喜欢探讨的话题,在科学家构建的火星气候模型,没有一

280亿个晶体管,10496个核心,黄仁勋的 RTX 3090性能

2020-09-03

  新智元报道  来源:anandtech编辑:白峰、继鹏【新智元导读】今天凌晨,黄仁勋在厨房重磅发布了三款RTX 30系列显卡,性

高福谈新冠疫苗面临的最大挑战

2020-09-14

高福谈新冠疫苗面临的最大挑战。在英国明星疫苗突然被叫停后,国内疫苗的进展一下子成了大众关心的话题。近日,中国科

三星掌门人李在镕被韩国检方起诉

2020-09-02

中新网首尔9月1日电(记者 曾鼐)韩国检方1日下午称,决定起诉韩国三星电子副会长、集团实际控制人李在镕等人。此前,