頭條項目的文章延遲發布功能

最近做的頭條項目其中有個功能是創作者發表的文章可以設置在未來某個時間發表,在實現這個功能的時候就在想該怎么實現呢?剛開始想的是利用Spring的定時任務定時的去數據庫中查詢,可以這個查詢頻率該怎么設置,每次從數據庫中需要查詢文章延遲發布表的全部信息,未免有點太消耗時間了,況且MySQL還是存在本地磁盤的,讀取成本過高。

這個時候我就想既然遇到了讀寫速度問題,就要找緩存來解決了,利用Redis存儲在內存的特性,將馬上就要發布的文章信息存進Redis中,利用定時任務一分鐘查詢一次緩存,查看是否有要發布的文章,拉取對應的文章信息進行審核發布

我在redis中使用兩種數據結構來存儲文章發布信息

list?是一個簡單的字符串列表,按照插入順序排序。你可以在列表的頭部(左邊)或尾部(右邊)插入元素。

?使用list存儲發布時間小于等于當前時間也就是立刻就要發布的文章,每次都從列表的左邊插入文章信息,定時任務消費的時候從右邊拉取數據,以形成一定的時間順序

?zset?是一種特殊的集合,它和普通集合一樣,成員都是唯一的,但每個成員都會關聯一個分數(score),Redis 會根據分數對成員進行從小到大的排序。

zset和list的區別就是元素唯一,并且每個元素綁定一個分數, 該集合會根據分數的大小進行排序,正好就可以把文章的預發布時間當作score,這樣每次取score最小的文章也就是最早要發布的文章,符合業務邏輯

延遲發布任務的存儲處理

處理流程如上圖所示,當有用戶發起文章發布請求時

1 先將文章相關的信息存入本地數據庫中做備份(防止因為系統或斷電導致緩存丟失)

2 然后判斷文章的預發布時間

????????如果小于等于當前時間,直接放入list中等待定時任務消費

??????? 否則如果發布時間在未來五分鐘以內,放入zset中

    public long addTask(Task task) {//先存儲進本地數據庫boolean success=addTaskToDb(task);//存進緩存if(success){addTaskToCache(task);}return task.getTaskId();}/*** 把任務添加到redis中** @param task*/private void addTaskToCache(Task task) {String key = task.getTaskType() + "_" + task.getPriority();//獲取5分鐘之后的時間  毫秒值Calendar calendar = Calendar.getInstance();calendar.add(Calendar.MINUTE, 5);long nextScheduleTime = calendar.getTimeInMillis();//2.1 如果任務的執行時間小于等于當前時間,存入listif (task.getExecuteTime() <= System.currentTimeMillis()) {cacheService.lLeftPush(ScheduleConstants.TOPIC + key, JSON.toJSONString(task));} else if (task.getExecuteTime() <= nextScheduleTime) {//2.2 如果任務的執行時間大于當前時間 && 小于等于預設時間(未來5分鐘) 存入zset中cacheService.zAdd(ScheduleConstants.FUTURE + key, JSON.toJSONString(task), task.getExecuteTime());}}//MySQL數據private boolean addTaskToDb(Task task) {//用來標記是否存儲成功boolean flag = false;try {//保存任務表Taskinfo taskinfo = new Taskinfo();BeanUtils.copyProperties(task, taskinfo);taskinfo.setExecuteTime(new Date(task.getExecuteTime()));taskinfoMapper.insert(taskinfo);//設置taskIDtask.setTaskId(taskinfo.getTaskId());//保存任務日志數據TaskinfoLogs taskinfoLogs = new TaskinfoLogs();BeanUtils.copyProperties(taskinfo, taskinfoLogs);taskinfoLogs.setVersion(1);taskinfoLogs.setStatus(ScheduleConstants.SCHEDULED);taskinfoLogsMapper.insert(taskinfoLogs);flag = true;} catch (Exception e) {e.printStackTrace();}return flag;}

以上僅僅只是請求到來后初步的處理,當消費列表list中的文章發布任務處理完畢后怎么辦呢?

Redis數據處理

針對Redis中zset的數據(未來五分鐘內發布的文章),需要每分鐘查詢是否有發布時間小于等于當前時間的,然后從zset中移動到list中

這就涉及到Redis列表的搜索算法了,目前常用的匹配對應元素的方法有keys 的模糊匹配、Scan掃描,由于keys模糊匹配非常占用CPU的時間,所以一般使用SCAN掃描符合要求的數據

當用戶數據量較大是,如果從zset中一條一條的將文章發布任務移動到list中也很占用時間,恰好Redis提供了Pipeline請求服務,可以一次傳送大量數據,大大節省時間

(同時,基于分布式的軟件架構下可能有多個端同時處理文章預發布信息,這里使用redis的分布式鎖,占用時間三十秒)

定時任務代碼如下

    @Scheduled(cron = "0 */1 * * * ?")public void refresh() {//使用redis的分布式鎖,三十秒后結束String token= cacheService.tryLock("FUTURE_TASK_SYNC", 1000 * 30);if(StringUtils.isNotBlank(token)){System.out.println(System.currentTimeMillis() / 1000 + "執行了定時任務");// 獲取所有未來數據集合的key值,使用scan而非keysSet<String> futureKeys = cacheService.scan(ScheduleConstants.FUTURE + "*");// future_*for (String futureKey : futureKeys) { // future_250_250String topicKey = ScheduleConstants.TOPIC + futureKey.split(ScheduleConstants.FUTURE)[1];//獲取該組key下當前需要消費的任務數據Set<String> tasks = cacheService.zRangeByScore(futureKey, 0, System.currentTimeMillis());if (!tasks.isEmpty()) {//將這些任務數據添加到消費者隊列中cacheService.refreshWithPipeline(futureKey, topicKey, tasks);System.out.println("成功的將" + futureKey + "下的當前需要執行的任務數據刷新到" + topicKey + "下");}}}}

普通redis客戶端和服務器交互模式

Pipeline請求模型

官方測試結果數據對比

延遲發布任務的消費

上面已經解決了文章預發布任務的處理,下面就是從緩存中定時的拉取任務進行文章發布了

在自媒體段使用Feign接口遠程調用任務模塊的poll方法拉取緩存中的任務

    @Scheduled(fixedRate = 1000)@SneakyThrows@Overridepublic void scanNewsByTask() {log.info("文章審核---消費任務執行---begin---");//從緩存中拉取文章發布任務ResponseResult responseResult = scheduleClient.poll(TaskTypeEnum.NEWS_SCAN_TIME.getTaskType(),TaskTypeEnum.NEWS_SCAN_TIME.getPriority());if(responseResult.getCode().equals(200) && responseResult.getData() != null){String json_str = JSON.toJSONString(responseResult.getData());Task task = JSON.parseObject(json_str, Task.class);byte[] parameters = task.getParameters();WmNews wmNews = ProtostuffUtil.deserialize(parameters, WmNews.class);//審核文章內容wmNewsAutoScanService.autoScanWmNews(wmNews.getId());}log.info("文章審核---消費任務執行---end---");}

?任務模塊的poll

    public Task poll(int type,int priority) {Task task = null;try {String key = type+"_"+priority;String task_json = cacheService.lRightPop(ScheduleConstants.TOPIC + key);if(StringUtils.isNotBlank(task_json)){task = JSON.parseObject(task_json, Task.class);//更新數據庫信息updateDb(task.getTaskId(),ScheduleConstants.EXECUTED);}}catch (Exception e){e.printStackTrace();log.error("poll task exception");}return task;}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/73673.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/73673.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/73673.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Celery 全面指南:Python 分布式任務隊列詳解

Celery 全面指南&#xff1a;Python 分布式任務隊列詳解 Celery 是一個強大的分布式任務隊列/異步任務隊列系統&#xff0c;基于分布式消息傳遞&#xff0c;專注于實時處理&#xff0c;同時也支持任務調度。本文將全面介紹 Celery 的核心功能、應用場景&#xff0c;并通過豐富…

OpenHarmony NativeC++應用開發speexdsp噪聲消除案例

隨著5.0的版本的迭代升級&#xff0c;筆者感受到了開源鴻蒙前所未有大的版本更替速度。5.0出現了越來越多的C API可以調用&#xff0c;極大的方便了native c應用的開發。筆者先將speexdsp噪聲消除的案例分享&#xff0c;老規矩&#xff0c;還是開源&#xff01;&#xff01;&am…

nuxt3 seo優化

在 Nuxt3 中&#xff0c;通過 nuxtjs/seo、nuxtjs/sitemap 和 nuxtjs/robots 模塊可以生成包含動態鏈接的站點地圖&#xff08;sitemap.xml&#xff09;&#xff0c;但具體是“實時生成”還是“部署時生成”&#xff0c;取決于你的配置方式和數據更新頻率。以下是具體分析&…

es6的100個問題

基礎概念 解釋 let、const 和 var 的區別。什么是塊級作用域&#xff1f;ES6 如何實現它&#xff1f;箭頭函數和普通函數的主要區別是什么&#xff1f;解釋模板字符串&#xff08;Template Literals&#xff09;的用途&#xff0c;并舉例嵌套變量的寫法。解構賦值的語法是什么…

【機器學習】什么是決策樹?

什么是決策樹&#xff1f; 決策樹是一種用于分類和回歸問題的模型。它通過一系列的“決策”將數據逐步分裂&#xff0c;最終得出預測結果。可以把它看作是一個“樹”&#xff0c;每個節點表示一個特征的判斷&#xff0c;而每個分支代表了可能的判斷結果&#xff0c;最終的葉子…

Java面試黃金寶典15

1. 請找出增序排列中一個數字第一次和最后一次出現的數組下標 定義 由于數組是增序排列的&#xff0c;我們可以利用二分查找的特性來高效地定位目標數字。對于查找第一次出現的位置&#xff0c;當中間元素等于目標數字時&#xff0c;我們需要繼續向左搜索&#xff0c;以確保找…

CentOS 7安裝 mysql

CentOS 7安裝 mysql 1. yum 安裝 mysql 配置mysql源 yum -y install mysql57-community-release-el7-10.noarch.rpm安裝MySQL服務器 yum -y install mysql-community-server啟動MySQL systemctl start mysqld.service查看MySQL運行狀態&#xff0c;運行狀態如圖&#xff…

科軟25機試

題目: 2025科軟復試上機題&#xff08;回憶版&#xff09;題解_嗶哩嗶哩_bilibili 1. 字符串反轉 #include<bits/stdc.h> using namespace std;void solve(string& a, int CurN) {if (!(CurN % 2)) {int right a.size() - 1;int left 0;while (left < right)…

Oracle相關的面試題

以下是150道Oracle相關的面試題&#xff0c;涵蓋了Oracle的基礎概念、架構、SQL與PL/SQL、性能調優、高可用性、備份與恢復、安全、分區與索引、存儲與內存管理、網絡與連接、版本與升級等方面&#xff0c;希望對你有所幫助。 Oracle基礎概念 1. 什么是Oracle數據庫&#xff1…

docker安裝,鏡像,常用命令,Docker容器卷,Docker應用部署,自定義鏡像,Docker服務編排,創建私有倉庫

1.為什么使用docker 如果開發環境和測試環境的允許軟件版本不一致&#xff0c;可能會導致項目無法正常啟動 把環境和項目一起打包發送給測試環境 1.1docker的概念 開源的應用容器引擎&#xff0c;完全使用沙箱機制&#xff0c;相互隔離&#xff0c;容器性能開銷極低 一種容…

ES 字段的映射定義了字段的類型及其行為

在 Elasticsearch 中&#xff0c;字段的映射定義了字段的類型及其行為。你提供的 content_answer 字段映射如下&#xff1a; Json 深色版本 "content_answer": { "type": "text", "fields": { "keyword": { …

Manus的開源替代者之一:OpenManus通用AI智能體框架解析及產品試用

引言 在AI智能體領域&#xff0c;Monica團隊近期發布的Manus被譽為全球首個通用型AI智能體。該項目推出后迅速爆紅&#xff0c;邀請碼一號難求&#xff0c;隨之而來的是各路開發者快速構建了眾多類似的開源替代方案。其中&#xff0c;MetaGPT團隊的5位工程師僅用3小時就開發完…

Linux MariaDB部署

1&#xff1a;查看Linux系統版本 cat /etc/os-release#返回結果&#xff1a; NAME"CentOS Linux" VERSION"7 (Core)" ID"centos" ID_LIKE"rhel fedora" VERSION_ID"7" PRETTY_NAME"CentOS Linux 7 (Core)" ANSI…

PHP MySQL 預處理語句

PHP MySQL 預處理語句 引言 在PHP中與MySQL數據庫進行交互時,預處理語句是一種非常安全和高效的方法。預處理語句不僅可以防止SQL注入攻擊,還可以提高數據庫查詢的效率。本文將詳細介紹PHP中預處理語句的用法,包括其基本概念、語法、優勢以及在實際開發中的應用。 預處理…

算法 | 2024最新算法:鳑鲏魚優化算法原理,公式,應用,算法改進研究綜述,matlab代碼

2024最新鳑鲏魚優化算法(BFO)研究綜述 鳑鲏魚優化算法(Bitterling Fish Optimization, BFO)是2024年提出的一種新型群智能優化算法,受鳑鲏魚獨特的繁殖行為啟發,通過模擬其交配、產卵和競爭機制進行全局優化。該算法在多個領域展現出優越性能,尤其在解決復雜非線性問題中…

HDR(HDR10/ HLG),SDR

以下是HDR&#xff08;HDR10/HLG&#xff09;和SDR的詳細解釋&#xff1a; 1. SDR&#xff08;Standard Dynamic Range&#xff0c;標準動態范圍&#xff09; ? 定義&#xff1a;SDR是傳統的動態范圍標準&#xff0c;主要用于8位色深的視頻顯示&#xff0c;動態范圍較窄&…

uni-app頁面怎么設計更美觀

頂部 頁面最頂部要獲取到手機設備狀態欄的高度&#xff0c;避免與狀態欄重疊或者被狀態欄擋住 // 這是最頂部的父級容器 <view :style"{ paddingTop: ${statusBarHeight extraPadding}px }">.... </view> export default {data() {return {statusBarH…

江西核威環保科技:打造世界前沿的固液分離設備高新企業

隨著市場經濟的不斷發展&#xff0c;消費者的需求越來越大&#xff0c;為了更好的服務廣大新老客戶&#xff0c;作為知名品牌的“江西核威環保科技有限公司&#xff08;以下簡稱江西核威環保科技&#xff09;”&#xff0c;將堅持以“服務為企業宗旨&#xff0c;全力打造世界前…

Ethernet(以太網)詳解

一、Ethernet的定義與核心特性 以太網&#xff08;Ethernet&#xff09;是一種 基于IEEE 802.3標準的局域網&#xff08;LAN&#xff09;技術&#xff0c;用于設備間通過有線或光纖介質進行數據通信。其核心特性包括&#xff1a; 標準化&#xff1a;遵循IEEE 802.3系列協議&am…

JBDev - Theos下一代越獄開發工具

JBDev - Theos下一代越獄開發工具 自越獄誕生以來&#xff0c;Theos一直是越獄開發的主流工具&#xff0c;大多數開發者使用Theos編譯代碼&#xff0c;再用lldb手動調試。JBDev簡化了這個過程&#xff0c;項目地址https://github.com/lich4/JBDev 簡介 JBDev用于Xcode越獄開…