环球消息!解剖屎山,寻觅黄金之第二弹
程序员客栈 2023-06-19 13:41:19

大家好,我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-06-19 13:41:19

热推荐:2023河北特岗教师招聘报名入口(6月26日至7月1日)

2023-06-19 12:54:32

环球微头条丨考核结果!祝贺蚌山区

2023-06-19 12:16:49

“肯定存在风险!”马斯克发出警告

2023-06-19 12:03:15

快报:确保就业形势总体稳定

2023-06-19 11:30:12

网易闪电邮怎么退出账户 网易邮箱大师APP退出账号登录方法 焦点热门

2023-06-19 11:03:59

观速讯丨金杨股份深交所公开招股

2023-06-19 10:58:46

电子表格如何复制粘贴格式不变_excel表格复制粘贴格式不变 当前快报

2023-06-19 10:11:37

MSA-2;STING激动剂

2023-06-19 10:11:55

一字千金/马斯克爱迷因币 言论左右升跌价

2023-06-19 09:17:55

【天天报资讯】神仙胡同

2023-06-19 09:56:23

【环球热闻】圆盗窃罪如何判

2023-06-19 09:30:10

路由器上再接一个无线路由器怎么设置(tplink450m无线路由器怎么设置)_播报

2023-06-19 09:29:15

海南明确:到2025年全省中小学校心理健康课程实现全面覆盖 全球今日讯

2023-06-19 08:47:51

四川:加快产业转型 建设制造强省-天天看点

2023-06-19 08:55:14

qq群关键词怎么用百度指数查询-快讯

2023-06-18 21:44:21

我想看超时空战士_超时空勇士

2023-06-18 21:12:21

【天天速看料】范曾高徒刘波学艺展在天津开幕 立体展示学者型艺术家的成长历程

2023-06-18 20:30:13

无机复合一维纳米纤维的制备及其敏感性质研究_关于无机复合一维纳米纤维的制备及其敏感性质研究介绍_每日快讯

2023-06-18 19:48:38

当前聚焦:董文祥_关于董文祥的简介

2023-06-18 18:55:33

住月子中心的利弊_请看了这些以后再做决定吧|观速讯

2023-06-18 18:08:53

@所有人 2023年端午假期四川出行分析预测报告来了!_世界短讯

2023-06-18 17:22:58

哪个瞬间,你发现爸爸不再年轻 今日快看

2023-06-18 17:03:55

2023年通化中考成绩什么时候出来

2023-06-18 16:24:02

全球观热点:tot项目模式什么意思_tot模式是什么意思

2023-06-18 15:37:31

川佛手的功效与作用(川南佛手的神奇功效)

2023-06-18 14:55:07

京城拍客丨献给所有父亲的照片

2023-06-18 13:30:07

管理层增持公司股份,长期看好公司发展_焦点观察

2023-06-18 12:33:16

焦点速递!只有天津人才知道|这所120年前对标剑桥建的大学 如今是啥样

2023-06-18 11:36:30

天天头条:广末凉子承认出轨 广告全部下架亲子专栏被终止

2023-06-18 10:51:25

全球热点评!王晶父亲叫什么名字-王晶的父亲

2023-06-18 09:42:19

当前速递!两支球队哄抢杜锋的人,广东交易一个内线,但醉翁之意不在酒

2023-06-18 09:20:27

昆曲长生殿小宴内容_赴宴 昆曲剧目相关内容简介介绍 世界快报

2023-06-18 08:52:31

采购是一种生活态度

2023-06-18 08:01:47

重点聚焦!中央气象台6月18日06时继续发布高温黄色预警

2023-06-18 07:09:16

【焦点热闻】测绘哪些学校就业好率最强的研究生前景

2023-06-18 06:05:50

武汉东湖欢乐谷_东湖欢乐谷

2023-06-18 05:14:11

环球快报:dnf背包检测怎么破_dnf背包检测

2023-06-18 01:49:47

今日热搜:安徽提升重大气象灾害(暴雨)应急响应至III级

2023-06-17 22:51:36

护航大运会 安全“大练兵”!2023年成都网络安全技能赛即将开战|环球播报

2023-06-17 22:09:04

恢复态势延续 新业态注入新动能——前五月经济数据透视 每日短讯

2023-06-17 21:18:49

当前时讯:午时三刻是几点钟下班 午时三刻是几点

2023-06-17 20:03:25

全球最新:王维图片大全高清_王维图片

2023-06-17 19:31:32

世界快资讯:彩虹西瓜在南宁上市 吃瓜群众可有新体验

2023-06-17 18:15:43

如何自查糖尿病的早期症状_怎么自查糖尿病早期症状

2023-06-17 17:54:10

世界热门:中国女排逆转保加利亚 世联赛斩获六连胜

2023-06-17 17:11:08

今日播报!中油测井国家级博士后科研工作站揭牌

2023-06-17 16:44:21

焦点滚动:fatezero百科_fatezero的作者简介介绍

2023-06-17 16:02:02

天天通讯!董擢_关于董擢的简介

2023-06-17 14:40:35

闵鹿蕾上任后第一把火!正式交易水货内线,为北控队腾出顶薪名额

2023-06-17 14:12:10

“将党的二十大精神牢记于心!”赛后参赛选手这样说

2023-06-17 13:49:24

全球快播:梅婷晒与侄子合照祝其中考加油!侄子短发干练脸庞青涩又帅气

2023-06-17 12:54:18

南方核心成长混合A基金最新净值跌幅达2.61%

2023-06-17 11:47:33

《易》、黄老之学、炼丹术—《周易参同契》的三大思想渊源(三)|全球聚焦

2023-06-17 10:59:23

世界新动态:朗逸新锐、ID.Next亮相华南 上汽大众全车系登陆粤港澳大湾区车展

2023-06-17 10:55:54

618价格真的卷!128GB雷克沙高速SD卡低至249元!

2023-06-17 10:17:07

北约防长会结束 首份区域防御计划未获通过 环球时快讯

2023-06-17 09:46:42

教师资格证改革_2024年教师资格证改革 全球热点评

2023-06-17 08:58:29

环球今日讯!港科大(广州)设立一周年引进近200名高水平学术人才 7个省市级重点实验室启用

2023-06-17 08:46:34

王者荣耀&英雄联盟——芬妮

2023-06-17 08:07:18

女子穿“联名汉服”入园被拦?上海迪士尼回应:16岁以上游客不能这样穿-每日速读

2023-06-17 07:02:29

【世界新视野】织金县水务局:筑牢群众安全用水保障

2023-06-17 06:32:05

直径符号怎么打出来的_直径符号怎么打出来|焦点速看

2023-06-17 05:43:36

都2023年了,为什么自主品牌还是改不了山寨的毛病? 当前关注

2023-06-17 03:23:20

so call me maybe歌词_call me maybe 男主角

2023-06-17 01:41:17

海里的小螃蟹怎么吃好吃_海里的小螃蟹怎么养

2023-06-17 00:56:31

形容人多的成语接踵什么_形容人多的成语

2023-06-16 23:10:44

邪王真眼是最强的是什么意思(邪王真眼是什么简介介绍) 即时看

2023-06-16 22:03:57

zodgame论坛社区_zodgame论坛us

2023-06-16 21:45:39

“千万工程”20年 | 浙江:一枝花共富一方百姓

2023-06-16 21:08:46

今日要闻!洲际船务(02409)附属以2700万美元出售船舶并回租

2023-06-16 20:48:53

每日速看!农村大病报销医保要怎么申请

2023-06-16 20:18:12

A股传媒、游戏股震荡调整,中国出版跌超8%-焦点报道

2023-06-16 19:41:18

粮库提前腾并仓容、筹备资金 确保小麦安全入库

2023-06-16 19:29:33

当蜘蛛网无情地查封了我的炉台是什么意思_当蜘蛛网无情地查封了我的炉台_今日热搜

2023-06-16 19:08:28

首批基础设施公募REITs扩募项目上市 看热讯

2023-06-16 18:23:54

山东路桥购买济南晶石中心A栋房产已完成产权初始登记

2023-06-16 18:08:32

鬼头脱皮是什么原因_鬼头炎脱皮症状图片

2023-06-16 17:40:03

圃田乡开展高层住宅火灾疏散演练

2023-06-16 17:27:30

“这麦子地毯,比什么装修都好看!”_关注

2023-06-16 17:13:57

2023福州社保缴费标准是多少钱一个月 福州社保费用表

2023-06-16 16:41:26

全球快看点丨建议大兴这个村整体拆迁?!反馈意见来了!10公里的步道也安排上了!

2023-06-16 16:17:45

【天天新视野】探店凯迪拉克GT4:优惠3万,顶配最值得买?

2023-06-16 16:01:13

图集丨中山沙溪厚山村:荷花盛开,惊艳一夏|环球快讯

2023-06-16 15:29:38

世界动态:齐齐哈尔市建华区第二十七届职工学生田径运动会启幕

2023-06-16 15:18:51

天天精选!大连小窑湾约4000平米工业用地使用权挂牌 将于7月6日交易

2023-06-16 14:56:16

香港上市公司联席董事长,传同意引渡美国,将面临刑事指控_天天快报

2023-06-16 14:18:20

山东青岛宝石鉴定机构谈谈欧洲皇室为什么喜欢珍珠

2023-06-16 14:09:40

金鸡独立不足10秒,可预测死亡风险|最新

2023-06-16 13:22:47

2023年6月中国文化遗产研究院招聘考试安排是什么?

2023-06-16 12:56:56

每日讯息!焦点访谈:“机器人+”加速前行

2023-06-16 12:57:08

荒地变身绿意盎然的“后花园” ,背后有他们的付出_世界看热讯

2023-06-16 12:17:46

大地海洋拟9.1亿元买虎哥环境被否 为国金证券项目|今日热文

2023-06-16 11:53:50

环球热点评!第十四届海峡两岸船政文化研讨会举行两场分论坛

2023-06-16 11:54:16

德媒:普京接受埃尔多安访土邀请_当前热讯

2023-06-16 11:23:25

焦点速递!华北电力大学文科生能进国家电网吗_我是安徽今年的文科生 今年考了456 请问能进滁洲学院的专科学院吗

2023-06-16 11:02:38

【世界独家】七雄争霸武将招募_七雄争霸武将选择

2023-06-16 11:02:45

重庆垫江县可提供双喜电压力锅维修服务地址在哪_世界速递

2023-06-16 10:47:21

2023中考期间唐山曹妃甸城区部分路段将实施交通管制

2023-06-16 10:22:14

cf图标怎么点亮的(cf图标怎么点亮)_世界热议

2023-06-16 10:14:55