解剖屎山,寻觅黄金之第二弹
程序员客栈 2023-05-08 07:51:13

大家好,我3y啊。由于去重逻辑重构了几次,好多股东直呼看不懂,于是我今天再安排一波对代码的解析吧。austin支持两种去重的类型:N分钟相同内容达到N次去重和一天内N次相同渠道频次去重。


(资料图片仅供参考)

在最开始,我的第一版实现是这样的:

publicvoidduplication(TaskInfotaskInfo){//配置示例:{"contentDeduplication":{"num":1,"time":300},"frequencyDeduplication":{"num":5}}JSONObjectproperty=JSON.parseObject(config.getProperty(DEDUPLICATION_RULE_KEY,AustinConstant.APOLLO_DEFAULT_VALUE_JSON_OBJECT));JSONObjectcontentDeduplication=property.getJSONObject(CONTENT_DEDUPLICATION);JSONObjectfrequencyDeduplication=property.getJSONObject(FREQUENCY_DEDUPLICATION);//文案去重DeduplicationParamcontentParams=DeduplicationParam.builder().deduplicationTime(contentDeduplication.getLong(TIME)).countNum(contentDeduplication.getInteger(NUM)).taskInfo(taskInfo).anchorState(AnchorState.CONTENT_DEDUPLICATION).build();contentDeduplicationService.deduplication(contentParams);//运营总规则去重(一天内用户收到最多同一个渠道的消息次数)Longseconds=(DateUtil.endOfDay(newDate()).getTime()-DateUtil.current())/1000;DeduplicationParambusinessParams=DeduplicationParam.builder().deduplicationTime(seconds).countNum(frequencyDeduplication.getInteger(NUM)).taskInfo(taskInfo).anchorState(AnchorState.RULE_DEDUPLICATION).build();frequencyDeduplicationService.deduplication(businessParams);}

那时候很简单,基本主体逻辑都写在这个入口上了,应该都能看得懂。后来,群里滴滴哥表示这种代码不行,不能一眼看出来它干了什么。于是怒提了一波pull request重构了一版,入口是这样的:

publicvoidduplication(TaskInfotaskInfo){//配置样例:{"contentDeduplication":{"num":1,"time":300},"frequencyDeduplication":{"num":5}}Stringdeduplication=config.getProperty(DeduplicationConstants.DEDUPLICATION_RULE_KEY,AustinConstant.APOLLO_DEFAULT_VALUE_JSON_OBJECT);//去重DEDUPLICATION_LIST.forEach(key->{DeduplicationParamdeduplicationParam=builderFactory.select(key).build(deduplication,key);if(deduplicationParam!=null){deduplicationParam.setTaskInfo(taskInfo);DeduplicationServicededuplicationService=findService(key+SERVICE);deduplicationService.deduplication(deduplicationParam);}});}

我猜想他的思路就是把构建去重参数和选择具体的去重服务给封装起来了,在最外层的代码看起来就很简洁了。后来又跟他聊了下,他的设计思路是这样的:考虑到以后会有其他规则的去重就把去重逻辑单独封装起来了,之后用策略模版的设计模式进行了重构,重构后的代码 模版不变,支持各种不同策略的去重,扩展性更高更强更简洁

确实牛逼。

我基于上面的思路微改了下入口,代码最终演变成这样:

publicvoidduplication(TaskInfotaskInfo){//配置样例:{"deduplication_10":{"num":1,"time":300},"deduplication_20":{"num":5}}StringdeduplicationConfig=config.getProperty(DEDUPLICATION_RULE_KEY,CommonConstant.EMPTY_JSON_OBJECT);//去重ListdeduplicationList=DeduplicationType.getDeduplicationList();for(IntegerdeduplicationType:deduplicationList){DeduplicationParamdeduplicationParam=deduplicationHolder.selectBuilder(deduplicationType).build(deduplicationConfig,taskInfo);if(Objects.nonNull(deduplicationParam)){deduplicationHolder.selectService(deduplicationType).deduplication(deduplicationParam);}}}

到这,应该大多数人还能跟上吧?在讲具体的代码之前,我们先来简单看看去重功能的代码结构(这会对后面看代码有帮助)

去重的逻辑可以统一抽象为:在X时间段内达到了Y阈值,还记得我曾经说过:「去重」的本质:「业务Key」+「存储」。那么去重实现的步骤可以简单分为(我这边存储就用的Redis):

通过Key从Redis获取记录判断该Key在Redis的记录是否符合条件符合条件的则去重,不符合条件的则重新塞进Redis更新记录

为了方便调整去重的参数,我把X时间段和Y阈值都放到了配置里{"deduplication_10":{"num":1,"time":300},"deduplication_20":{"num":5}}。目前有两种去重的具体实现:

1、5分钟内相同用户如果收到相同的内容,则应该被过滤掉

2、一天内相同的用户如果已经收到某渠道内容5次,则应该被过滤掉

从配置中心拿到配置信息了以后,Builder就是根据这两种类型去构建出DeduplicationParam,就是以下代码:

DeduplicationParamdeduplicationParam=deduplicationHolder.selectBuilder(deduplicationType).build(deduplicationConfig,taskInfo);

Builder和DeduplicationService都用了类似的写法(在子类初始化的时候指定类型,在父类统一接收,放到Map里管理)

而统一管理着这些服务有个中心的地方,我把这取名为DeduplicationHolder

/***@authorhuskey*@date2022/1/18*/@ServicepublicclassDeduplicationHolder{privatefinalMapbuilderHolder=newHashMap<>(4);privatefinalMapserviceHolder=newHashMap<>(4);publicBuilderselectBuilder(Integerkey){returnbuilderHolder.get(key);}publicDeduplicationServiceselectService(Integerkey){returnserviceHolder.get(key);}publicvoidputBuilder(Integerkey,Builderbuilder){builderHolder.put(key,builder);}publicvoidputService(Integerkey,DeduplicationServiceservice){serviceHolder.put(key,service);}}

前面提到的业务Key,是在AbstractDeduplicationService的子类下构建的:

而具体的去重逻辑实现则都在LimitService下,{一天内相同的用户如果已经收到某渠道内容5次}是在SimpleLimitService中处理使用mget和pipelineSetEX就完成了实现。而{5分钟内相同用户如果收到相同的内容}是在SlideWindowLimitService中处理,使用了lua脚本完成了实现。

LimitService的代码都来源于@caolongxiu的pull request,建议大家可以对比commit再学习一番:https://gitee.com/zhongfucheng/austin/pulls/19

1、频次去重采用普通的计数去重方法,限制的是每天发送的条数。

2、内容去重采用的是新开发的基于redis中zset的滑动窗口去重,可以做到严格控制单位时间内的频次。

3、redis使用lua脚本来保证原子性和减少网络io的损耗

4、redis的key增加前缀做到数据隔离(后期可能有动态更换去重方法的需求)

5、把具体限流去重方法从DeduplicationService抽取出来,DeduplicationService只需设置构造器注入时注入的AbstractLimitService(具体限流去重服务)类型即可动态更换去重的方法 6、使用雪花算法生成zset的唯一value,score使用的是当前的时间戳

针对滑动窗口去重,有会引申出新的问题:limit.lua的逻辑?为什么要移除时间窗口的之前的数据?为什么ARGV[4]参数要唯一?为什么要expire?

A: 使用滑动窗口可以保证N分钟达到N次进行去重。滑动窗口可以回顾下TCP的,也可以回顾下刷LeetCode时的一些题,那这为什么要移除,就不陌生了。

为什么ARGV[4]要唯一,具体可以看看zadd这条命令,我们只需要保证每次add进窗口内的成员是唯一的,那么就不会触发有更新的操作(我认为这样设计会更加简单些),而唯一Key用雪花算法比较方便。

为什么expire?,如果这个key只被调用一次。那就很有可能在redis内存常驻了,expire能避免这种情况。

推荐项目

最后再叨叨吧,很多人可能会发一段截图,跑来问我为什么要这样写,为什么要以这种方式实现,能不能以这种方式实现。这时候,我更想看到的是:你已经实现了第二种方式了,然后探讨你写的这种方案好不好,现有的代码差在哪里。

毕竟问问题很简单,我又不是客服,总不能没诚意的问题我都得一一回答吧。

如果想学Java项目的,我还是强烈推荐我的开源项目消息推送平台Austin,可以用作毕业设计,可以用作校招,可以看看生产环境是怎么推送消息的。

仓库地址(可点击阅读原文跳转):https://gitee.com/zhongfucheng/austin

我开通了股东服务内容,感兴趣可以点击下方看看,主要针对的是项目哟

VIP服务

解剖屎山,寻觅黄金之第二弹

2023-05-08 07:51:13

当前速递!最新“顶流”基金经理名单出炉:张坤反超葛兰 前三齐“掉粉”

2023-05-08 07:03:09

国家集成电路基金拟减持北方华创不超2%股份

2023-05-08 05:56:37

全球短讯!士不可不弘毅任重而道远的意思和理解_士不可不弘毅任重而道远的意思

2023-05-08 03:58:13

【环球报资讯】建德客运中心

2023-05-08 00:57:14

天天报道:冬瓜和什么菜炖着好吃?

2023-05-07 22:10:48

小区承重墙被砸怎么办?专家支招:向物业投诉!_焦点滚动

2023-05-07 21:15:55

消费品进口涵盖吃、穿、用、行多领域 助力消费升级

2023-05-07 20:18:51

每日热闻!七段小代码,玩转Java程序常见的崩溃场景!

2023-05-07 19:32:52

招商银行法务部门不能协商怎么办?逾期会产生什么后果?_世界速读

2023-05-07 18:08:13

锦州医科大学宿舍怎么走附近住条件样

2023-05-07 17:16:31

南京紫金山海拔多少米(南京紫金山海拔多少米高)

2023-05-07 16:33:43

全球关注:煤气用完,先关火还是先关气?

2023-05-07 15:54:13

天舟六号计划近日择机发射 船箭组合体转运至发射区-环球快看点

2023-05-07 14:54:47

当前观察:黄陂区税务局举办“五四”青年节“朗读者”比赛

2023-05-07 13:36:43

“南京女大学生被害案”主犯洪峤被执行死刑 视点

2023-05-07 12:03:16

世界观点:天舟六号船箭组合体完成转运 潮新闻现场直击

2023-05-07 11:15:22

“王应睐星”命名仪式在沪举行,激励科学家们勇毅前行

2023-05-07 10:54:07

每日热门:80级恶魔术士输出手法及天赋_8 2恶魔术士天赋

2023-05-07 09:59:02

正黑糖(关于正黑糖介绍)-环球实时

2023-05-07 09:14:53

武汉市观赏石协会_关于武汉市观赏石协会简述

2023-05-07 08:08:41

1死5伤 美国又一地发生派对枪击事件|世界报道

2023-05-07 06:52:32

逻辑地址由什么组成_逻辑地址 全球速讯

2023-05-07 04:57:10

断联后产生3感觉,别回头|世界报资讯

2023-05-07 02:16:21

好地段,共94亩!吉安市2宗住宅用地挂牌,楼面价仅..._热头条

2023-05-06 23:26:52

7060 高清 下载 7060手机电影网站下载

2023-05-06 22:10:38

资讯推荐:医学院的康复专业怎么样大里面上海

2023-05-06 21:07:06

宝马撞人案司机不服死刑提起上诉是什么情况 宝马撞人案司机不服死刑提起上诉具体来龙去脉是怎么样

2023-05-06 20:32:00

中国人的故事|皑皑白雪中,这些“冰墩墩”守护着铁路的“生命线”

2023-05-06 19:41:15

南方航空:火红五月,青春向党

2023-05-06 19:02:25

环球观速讯丨交口:王卫平调研乡村旅游示范村创建工作

2023-05-06 18:21:42

当前简讯:基本面软件电脑版下载_基本面

2023-05-06 17:41:45

当前速读:“五一”假期掀消费热 多项数据创新高带动中国经济回暖

2023-05-06 17:09:24

微头条丨可靠股份(301009.SZ):相信2023年随着原材料成本的逐步较低,公司毛利率将逐步回升

2023-05-06 16:26:03

每日关注!干海带怎么泡发清洗_干海带怎么泡发

2023-05-06 15:48:19

“五一”服务暖司乘

2023-05-06 15:32:22

当前讯息:漏绘南海诸岛、钓鱼岛等,东渡海关查获350套“问题地图”

2023-05-06 14:47:10

幻想神域源神殿堂召唤_幻想神域启源女神官网 环球要闻

2023-05-06 14:15:18

死亡组!伊藤美诚要与早田希娜争4强,15岁小将阻击平野美宇_全球热门

2023-05-06 13:38:38

【天天热闻】黄金一百秒2020全集_黄金一百秒在线观看

2023-05-06 12:20:01

天天播报:海关:开展《货物进口证明书(汽车、摩托车)》和《进口机动车辆随车检验单》“两证合一”改革试点

2023-05-06 11:57:01

梧州医保怎么用微信缴费 梧州医保报销这些流程你知道吗 全球热推荐

2023-05-06 11:19:04

万画影城电话 万画影城四季青店影讯

2023-05-06 10:41:36

视点!印尼4月精炼锡出口量同比下降21%

2023-05-06 10:19:21

当前视点!今日时讯:新冠不再构成国际关注突发公卫事件 新冠大流行迎来转折点世卫新决定怎么看权威专家详解

2023-05-06 09:51:36

历经1191天!世卫重磅宣布:新冠疫情不再构成“国际关注的突发公共卫生事件”_精选

2023-05-06 09:14:40

中国化学:5月5日融资净买入5864.54万元,连续3日累计净买入8564.94万元 当前聚焦

2023-05-06 08:25:14

福建漳州大学城一群人持刀斗殴引大量群众围观?警方:是普通打架

2023-05-06 07:48:13

中国声音经济数字化行业数据分析: 66.0%消费者表示看重内容丰富|世界报资讯

2023-05-06 06:01:06

汲取黑土地的文学滋养——评第六辑“野草莓丛书”

2023-05-06 04:51:02

小时候吃的零食小黄桃_小时候吃的零食

2023-05-06 02:46:34

东南枝是什么意思_东南枝是什么|观速讯

2023-05-06 00:41:18

大雪节气吃什么传统食物_大雪节气吃的传统食物简述_天天时讯

2023-05-05 23:03:23

学而思研发面向全球数学爱好者和科研机构的大模型MathGPT 计划于年内推出 全球快资讯

2023-05-05 21:57:47

美国就业和薪资增长加快 凸显劳动力市场韧性 天天速看料

2023-05-05 21:10:18

“五一”假期河南省科技馆忙 孩童争相学知识-环球今头条

2023-05-05 20:18:34

英国国王查尔斯和卡米拉王后迎来爱情故事的高潮:两人明日将一起加冕

2023-05-05 19:57:10

行为心理学读后感_行为心理学 每日快看

2023-05-05 19:18:50

厦门高新人才子女学校发布小学和初中招生通告_全球新资讯

2023-05-05 18:40:49

哪吒汽车CEO张勇:目前没有后排放显示屏的规划

2023-05-05 18:25:15

浙江理工大学:学生手绘社会发展“对比图” 环球微资讯

2023-05-05 18:02:45

要闻速递:国际锐评 | “五一”假期的人气见证中国经济的底气

2023-05-05 17:29:04

世界微速讯:白条抵库有什么危害_白条抵库违反什么规定

2023-05-05 16:51:42

天阳科技拟7000万元增资政务数据科技服务机构数喆数据

2023-05-05 16:33:29

即时看!上海闵行最大旧改小区首批楼机构封顶 首批居民最快将于5月底搬回

2023-05-05 15:59:04

环球热资讯!“五一”假期多个行业消费翻倍增长

2023-05-05 14:45:11

成都大运会MV《年轻的模样》警校生版来了

2023-05-05 14:16:14

480万辆次!嘉兴辖区高速流量创历史新高

2023-05-05 13:36:24

图书市集遍地开花,没逛书节的五一长假是不完整的|今日快讯

2023-05-05 12:49:24

加拿大威胁驱逐我外交人员?中方:若执意挑衅,将奉陪到底

2023-05-05 12:09:34

当前简讯:因为枪支暴力 每25名美国幼儿园儿童中就有一人活不到40岁

2023-05-05 12:06:58

全球要闻:华西证券:给予百济神州买入评级,目标价位206.29元

2023-05-05 11:34:23

晋江市领导开展湖漏溪巡河活动

2023-05-05 11:06:42

先惠技术(688155)盘中异动 股价振幅达7.63% 跌6.94% 报47.2元(05-05) 世界报资讯

2023-05-05 10:32:52

文化遗珠蟒河绝兰碑在山西阳城重现光彩

2023-05-05 10:24:16

环球今热点:常德:“五一”期间全市消防安全形势总体平稳

2023-05-05 10:04:46

夜之摩天楼任务好打吗(夜之摩天楼任务在哪接)|实时焦点

2023-05-05 09:29:49

国家邮政局:全国快递业务量突破400亿件

2023-05-05 09:22:22

梦见父亲出车祸_梦见父亲出车祸是啥意思

2023-05-05 08:39:48

进出口银行深入支持湖北供销 助力企业高质量发展

2023-05-05 08:03:33

从同质竞争到抱团发展 湘鄂赣三省掀起“交换游”热潮

2023-05-05 07:23:38

微软做“金主”,与AMD联手打造新款AI芯片,AMD一度飙涨10%-全球快看

2023-05-05 05:59:14

64岁58天!斯帕莱蒂是意甲最年长冠军教头|全球快看点

2023-05-05 04:54:12

全球要闻:苏文电能(300982):5月4日北向资金减持6800股

2023-05-05 03:32:33

哭泣的情人歌词_哭泣的情人|天天微速讯

2023-05-05 01:01:56

毫无底线!杭州西湖高价打捞手机为自导自演 将依法处理-焦点关注

2023-05-04 23:10:45

热议:炬光科技: 西安炬光科技股份有限公司关于以集中竞价交易方式回购公司股份的进展公告

2023-05-04 21:19:48

新动态:怀孕腹痛正常吗_怀孕初期小腹痛正常吗

2023-05-04 20:51:36

红安:庆五四 共唱《美丽中国》

2023-05-04 19:45:56

【全球独家】增城市旅游景点(增城市旅游景点大全)

2023-05-04 19:17:25

世界微资讯!今晚播出!《奔跑的青春——2023五四青年节特别节目》传递闪闪发光的青春力量

2023-05-04 18:57:50

飞机在线选座选哪个座位最好_飞机在线选座 全球观速讯

2023-05-04 18:18:59

波轮洗衣机清洗剂哪个牌子好_洗衣机清洗剂哪个牌子好 世界报资讯

2023-05-04 18:01:43

2023 年广州中考:第一梯度投档控制线划在 9%

2023-05-04 17:16:29

倩女幽魂手游点修为计算器_倩女幽魂修为计算器-世界最资讯

2023-05-04 17:04:26

在岸人民币兑美元16:30收盘报6.9162,较上一交易日涨122个基点

2023-05-04 16:31:54

index match函数和vlookup的区别_index match函数 全球实时

2023-05-04 16:20:42

天邦食品:光大证券金阳光APP显示公司股票停牌、公司可能被终止上市等事项均为不实信息

2023-05-04 15:50:37

倾注百年北欧匠心,ASKO斩获2023AWE艾普兰多项大奖

2023-05-04 15:22:37

全球今日讯!日本平均工资2022_日本平均工资

2023-05-04 15:01:38