java互聯網編程—redis應用場景及應用實例詳解

概述

Redis在很多方面與其他數據庫解決方案不同:它使用內存提供主存儲支持,而僅使用硬盤做持久性的存儲;它的數據模型非常獨特,用的是單線程。另一個大區別在於,你可以在開發環境中使用Redis的功能,但卻不需要轉到Redis。

轉向Redis當然也是可取的,許多開發者從一開始就把Redis作為首選數據庫;但設想如果你的開發環境已經搭建好,應用已經在上面運行了,那麼更換數據庫框架顯然不那麼容易。另外在一些需要大容量數據集的應用,Redis也並不適合,因為它的數據集不會超過系統可用的內存。所以如果你有大數據應用,而且主要是讀取訪問模式,那麼Redis並不是正確的選擇。

然而我喜歡Redis的一點就是你可以把它融入到你的系統中來,這就能夠解決很多問題,比如那些你現有的數據庫處理起來感到緩慢的任務。這些你就可以通過 Redis來進行優化,或者為應用創建些新的功能。

一丶顯示最新的項目列表

下面這個語句常用來顯示最新項目,隨著數據多了,查詢毫無疑問會越來越慢。

SELECT * FROM foo WHERE … ORDER BY time DESC LIMIT 10

在Web應用中,“列出最新的回覆”之類的查詢非常普遍,這通常會帶來可擴展性問題。這令人沮喪,因為項目本來就是按這個順序被創建的,但要輸出這個順序卻不得不進行排序操作。

類似的問題就可以用Redis來解決。比如說,我們的一個Web應用想要列出用戶貼出的最新20條評論。在最新的評論邊上我們有一個“顯示全部”的鏈接,點擊後就可以獲得更多的評論。

我們假設數據庫中的每條評論都有一個唯一的遞增的ID字段。

我們可以使用分頁來製作主頁和評論頁,使用Redis的模板,每次新評論發表時,我們會將它的ID添加到一個Redis列表:

LPUSH latest.comments

我們將列表裁剪為指定長度,因此Redis只需要保存最新的5000條評論:

LTRIM latest.comments 0 5000

每次我們需要獲取最新評論的項目範圍時,我們調用一個函數來完成(使用偽代碼):

FUNCTION get_latest_comments(start, num_items):

id_list = redis.lrange(“latest.comments”,start,start+num_items – 1)

IF id_list.length < num_items

id_list = SQL_DB(“SELECT … ORDER BY time LIMIT …”)

END

RETURN id_list

END

這裡我們做的很簡單。在Redis中我們的最新ID使用了常駐緩存,這是一直更新的。但是我們做了限制不能超過5000個ID,因此我們的獲取ID函數會一直詢問Redis。只有在start/count參數超出了這個範圍的時候,才需要去訪問數據庫。

我們的系統不會像傳統方式那樣“刷新”緩存,Redis實例中的信息永遠是一致的。SQL數據庫(或是硬盤上的其他類型數據庫)只是在用戶需要獲取“很遠”的數據時才會被觸發,而主頁或第一個評論頁是不會麻煩到硬盤上的數據庫了。

二丶刪除與過濾

我們可以使用LREM來刪除評論。如果刪除操作非常少,另一個選擇是直接跳過評論條目的入口,報告說該評論已經不存在。

有些時候你想要給不同的列表附加上不同的過濾器。如果過濾器的數量受到限制,你可以簡單的為每個不同的過濾器使用不同的Redis列表。畢竟每個列表只有5000條項目,但Redis卻能夠使用非常少的內存來處理幾百萬條項目。

三丶排行榜相關

另一個很普遍的需求是各種數據庫的數據並非存儲在內存中,因此在按得分排序以及實時更新這些幾乎每秒鐘都需要更新的功能上數據庫的性能不夠理想。

典型的比如那些在線遊戲的排行榜,比如一個Facebook的遊戲,根據得分你通常想要:

– 列出前100名高分選手

– 列出某用戶當前的全球排名

這些操作對於Redis來說小菜一碟,即使你有幾百萬個用戶,每分鐘都會有幾百萬個新的得分。

模式是這樣的,每次獲得新得分時,我們用這樣的代碼:

ZADD leaderboard

你可能用userID來取代username,這取決於你是怎麼設計的。

得到前100名高分用戶很簡單:

ZREVRANGE leaderboard 0 99。

用戶的全球排名也相似,只需要:

ZRANK leaderboard。

四丶按照用戶投票和時間排序

排行榜的一種常見變體模式就像Reddit或Hacker News用的那樣,新聞按照類似下面的公式根據得分來排序:

score = points / time^alpha

因此用戶的投票會相應的把新聞挖出來,但時間會按照一定的指數將新聞埋下去。下面是我們的模式,當然算法由你決定。

模式是這樣的,開始時先觀察那些可能是最新的項目,例如首頁上的1000條新聞都是候選者,因此我們先忽視掉其他的,這實現起來很簡單。

每次新的新聞貼上來後,我們將ID添加到列表中,使用

LPUSH + LTRIM,確保只取出最新的1000條項目。

有一項後臺任務獲取這個列表,並且持續的計算這1000條新聞中每條新聞的最終得分。計算結果由ZADD命令按照新的順序填充生成列表,老新聞則被清除。這裡的關鍵思路是排序工作是由後臺任務來完成的。

五丶計數

Redis是一個很好的計數器,這要感謝INCRBY和其他相似命令。

我相信你曾許多次想要給數據庫加上新的計數器,用來獲取統計或顯示新信息,但是最後卻由於寫入敏感而不得不放棄它們。

好了,現在使用Redis就不需要再擔心了。有了原子遞增(atomic increment),你可以放心的加上各種計數,用GETSET重置,或者是讓它們過期。

例如這樣操作:

INCR user: EXPIRE

user: 60

你可以計算出最近用戶在頁面間停頓不超過60秒的頁面瀏覽量,當計數達到比如20時,就可以顯示出某些條幅提示,或是其它你想顯示的東西。

六丶特定時間內的特定項目

另一項對於其他數據庫很難,但Redis做起來卻輕而易舉的事就是統計在某段特點時間裡有多少特定用戶訪問了某個特定資源。比如我想要知道某些特定的註冊用戶或IP地址,他們到底有多少訪問了某篇文章。

每次我獲得一次新的頁面瀏覽時我只需要這樣做:

SADD page:day1:

當然你可能想用unix時間替換day1,比如time()-(time()%3600*24)等等。

想知道特定用戶的數量嗎?只需要使用SCARD page:day1:。

需要測試某個特定用戶是否訪問了這個頁面?SISMEMBER page:day1: 。

七丶實時分析正在發生的情況,用於數據統計與防止垃圾郵件等

我們只做了幾個例子,但如果你研究Redis的命令集,並且組合一下,就能獲得大量的實時分析方法,有效而且非常省力。使用Redis原語命令,更容易實施垃圾郵件過濾系統或其他實時跟蹤系統。

八丶隊列

你應該已經注意到像list push和list pop這樣的Redis命令能夠很方便的執行隊列操作了,但能做的可不止這些:比如Redis還有list pop的變體命令,能夠在列表為空時阻塞隊列。

現代的互聯網應用大量地使用了消息隊列(Messaging)。消息隊列不僅被用於系統內部組件之間的通信,同時也被用於系統跟其它服務之間的交互。消息隊列的使用可以增加系統的可擴展性、靈活性和用戶體驗。非基於消息隊列的系統,其運行速度取決於系統中最慢的組件的速度(注:短板效應)。而基於消息隊列可以將系統中各組件解除耦合,這樣系統就不再受最慢組件的束縛,各組件可以異步運行從而得以更快的速度完成各自的工作。

此外,當服務器處在高併發操作的時候,比如頻繁地寫入日誌文件。可以利用消息隊列實現異步處理。從而實現高性能的併發操作。

九丶緩存

Redis的緩存部分值得寫一篇新文章,我這裡只是簡單的說一下。Redis能夠替代memcached,讓你的緩存從只能存儲數據變得能夠更新數據,因此你不再需要每次都重新生成數據了。

總結

到這裡java互聯網編程—redis應用場景及應用實例詳解結束了,不足之處還望大家多多包涵!!覺得收穫的話可以點個關注收藏轉發一波喔,謝謝大佬們支持。(吹一波,233~~)

下面和大家交流幾點編程的經驗:

1、多寫多敲代碼,好的代碼與紮實的基礎知識一定是實踐出來的

2丶 測試、測試再測試,如果你不徹底測試自己的代碼,那恐怕你開發的就不只是代碼,可能還會聲名狼藉。

3丶 簡化算法,代碼如惡魔,在你完成編碼後,應回頭並且優化它。從長遠來看,這裡或那裡一些的改進,會讓後來的支持人員更加輕鬆。

最後,每一位讀到這裡的網友,感謝你們能耐心地看完。希望在成為一名更優秀的Java程序員的道路上,我們可以一起學習、一起進步。

想了解學習以上內容可加群469717771 驗證:(009)

概述

Redis在很多方面與其他數據庫解決方案不同:它使用內存提供主存儲支持,而僅使用硬盤做持久性的存儲;它的數據模型非常獨特,用的是單線程。另一個大區別在於,你可以在開發環境中使用Redis的功能,但卻不需要轉到Redis。

轉向Redis當然也是可取的,許多開發者從一開始就把Redis作為首選數據庫;但設想如果你的開發環境已經搭建好,應用已經在上面運行了,那麼更換數據庫框架顯然不那麼容易。另外在一些需要大容量數據集的應用,Redis也並不適合,因為它的數據集不會超過系統可用的內存。所以如果你有大數據應用,而且主要是讀取訪問模式,那麼Redis並不是正確的選擇。

然而我喜歡Redis的一點就是你可以把它融入到你的系統中來,這就能夠解決很多問題,比如那些你現有的數據庫處理起來感到緩慢的任務。這些你就可以通過 Redis來進行優化,或者為應用創建些新的功能。

一丶顯示最新的項目列表

下面這個語句常用來顯示最新項目,隨著數據多了,查詢毫無疑問會越來越慢。

SELECT * FROM foo WHERE … ORDER BY time DESC LIMIT 10

在Web應用中,“列出最新的回覆”之類的查詢非常普遍,這通常會帶來可擴展性問題。這令人沮喪,因為項目本來就是按這個順序被創建的,但要輸出這個順序卻不得不進行排序操作。

類似的問題就可以用Redis來解決。比如說,我們的一個Web應用想要列出用戶貼出的最新20條評論。在最新的評論邊上我們有一個“顯示全部”的鏈接,點擊後就可以獲得更多的評論。

我們假設數據庫中的每條評論都有一個唯一的遞增的ID字段。

我們可以使用分頁來製作主頁和評論頁,使用Redis的模板,每次新評論發表時,我們會將它的ID添加到一個Redis列表:

LPUSH latest.comments

我們將列表裁剪為指定長度,因此Redis只需要保存最新的5000條評論:

LTRIM latest.comments 0 5000

每次我們需要獲取最新評論的項目範圍時,我們調用一個函數來完成(使用偽代碼):

FUNCTION get_latest_comments(start, num_items):

id_list = redis.lrange(“latest.comments”,start,start+num_items – 1)

IF id_list.length < num_items

id_list = SQL_DB(“SELECT … ORDER BY time LIMIT …”)

END

RETURN id_list

END

這裡我們做的很簡單。在Redis中我們的最新ID使用了常駐緩存,這是一直更新的。但是我們做了限制不能超過5000個ID,因此我們的獲取ID函數會一直詢問Redis。只有在start/count參數超出了這個範圍的時候,才需要去訪問數據庫。

我們的系統不會像傳統方式那樣“刷新”緩存,Redis實例中的信息永遠是一致的。SQL數據庫(或是硬盤上的其他類型數據庫)只是在用戶需要獲取“很遠”的數據時才會被觸發,而主頁或第一個評論頁是不會麻煩到硬盤上的數據庫了。

二丶刪除與過濾

我們可以使用LREM來刪除評論。如果刪除操作非常少,另一個選擇是直接跳過評論條目的入口,報告說該評論已經不存在。

有些時候你想要給不同的列表附加上不同的過濾器。如果過濾器的數量受到限制,你可以簡單的為每個不同的過濾器使用不同的Redis列表。畢竟每個列表只有5000條項目,但Redis卻能夠使用非常少的內存來處理幾百萬條項目。

三丶排行榜相關

另一個很普遍的需求是各種數據庫的數據並非存儲在內存中,因此在按得分排序以及實時更新這些幾乎每秒鐘都需要更新的功能上數據庫的性能不夠理想。

典型的比如那些在線遊戲的排行榜,比如一個Facebook的遊戲,根據得分你通常想要:

– 列出前100名高分選手

– 列出某用戶當前的全球排名

這些操作對於Redis來說小菜一碟,即使你有幾百萬個用戶,每分鐘都會有幾百萬個新的得分。

模式是這樣的,每次獲得新得分時,我們用這樣的代碼:

ZADD leaderboard

你可能用userID來取代username,這取決於你是怎麼設計的。

得到前100名高分用戶很簡單:

ZREVRANGE leaderboard 0 99。

用戶的全球排名也相似,只需要:

ZRANK leaderboard。

四丶按照用戶投票和時間排序

排行榜的一種常見變體模式就像Reddit或Hacker News用的那樣,新聞按照類似下面的公式根據得分來排序:

score = points / time^alpha

因此用戶的投票會相應的把新聞挖出來,但時間會按照一定的指數將新聞埋下去。下面是我們的模式,當然算法由你決定。

模式是這樣的,開始時先觀察那些可能是最新的項目,例如首頁上的1000條新聞都是候選者,因此我們先忽視掉其他的,這實現起來很簡單。

每次新的新聞貼上來後,我們將ID添加到列表中,使用

LPUSH + LTRIM,確保只取出最新的1000條項目。

有一項後臺任務獲取這個列表,並且持續的計算這1000條新聞中每條新聞的最終得分。計算結果由ZADD命令按照新的順序填充生成列表,老新聞則被清除。這裡的關鍵思路是排序工作是由後臺任務來完成的。

五丶計數

Redis是一個很好的計數器,這要感謝INCRBY和其他相似命令。

我相信你曾許多次想要給數據庫加上新的計數器,用來獲取統計或顯示新信息,但是最後卻由於寫入敏感而不得不放棄它們。

好了,現在使用Redis就不需要再擔心了。有了原子遞增(atomic increment),你可以放心的加上各種計數,用GETSET重置,或者是讓它們過期。

例如這樣操作:

INCR user: EXPIRE

user: 60

你可以計算出最近用戶在頁面間停頓不超過60秒的頁面瀏覽量,當計數達到比如20時,就可以顯示出某些條幅提示,或是其它你想顯示的東西。

六丶特定時間內的特定項目

另一項對於其他數據庫很難,但Redis做起來卻輕而易舉的事就是統計在某段特點時間裡有多少特定用戶訪問了某個特定資源。比如我想要知道某些特定的註冊用戶或IP地址,他們到底有多少訪問了某篇文章。

每次我獲得一次新的頁面瀏覽時我只需要這樣做:

SADD page:day1:

當然你可能想用unix時間替換day1,比如time()-(time()%3600*24)等等。

想知道特定用戶的數量嗎?只需要使用SCARD page:day1:。

需要測試某個特定用戶是否訪問了這個頁面?SISMEMBER page:day1: 。

七丶實時分析正在發生的情況,用於數據統計與防止垃圾郵件等

我們只做了幾個例子,但如果你研究Redis的命令集,並且組合一下,就能獲得大量的實時分析方法,有效而且非常省力。使用Redis原語命令,更容易實施垃圾郵件過濾系統或其他實時跟蹤系統。

八丶隊列

你應該已經注意到像list push和list pop這樣的Redis命令能夠很方便的執行隊列操作了,但能做的可不止這些:比如Redis還有list pop的變體命令,能夠在列表為空時阻塞隊列。

現代的互聯網應用大量地使用了消息隊列(Messaging)。消息隊列不僅被用於系統內部組件之間的通信,同時也被用於系統跟其它服務之間的交互。消息隊列的使用可以增加系統的可擴展性、靈活性和用戶體驗。非基於消息隊列的系統,其運行速度取決於系統中最慢的組件的速度(注:短板效應)。而基於消息隊列可以將系統中各組件解除耦合,這樣系統就不再受最慢組件的束縛,各組件可以異步運行從而得以更快的速度完成各自的工作。

此外,當服務器處在高併發操作的時候,比如頻繁地寫入日誌文件。可以利用消息隊列實現異步處理。從而實現高性能的併發操作。

九丶緩存

Redis的緩存部分值得寫一篇新文章,我這裡只是簡單的說一下。Redis能夠替代memcached,讓你的緩存從只能存儲數據變得能夠更新數據,因此你不再需要每次都重新生成數據了。

總結

到這裡java互聯網編程—redis應用場景及應用實例詳解結束了,不足之處還望大家多多包涵!!覺得收穫的話可以點個關注收藏轉發一波喔,謝謝大佬們支持。(吹一波,233~~)

下面和大家交流幾點編程的經驗:

1、多寫多敲代碼,好的代碼與紮實的基礎知識一定是實踐出來的

2丶 測試、測試再測試,如果你不徹底測試自己的代碼,那恐怕你開發的就不只是代碼,可能還會聲名狼藉。

3丶 簡化算法,代碼如惡魔,在你完成編碼後,應回頭並且優化它。從長遠來看,這裡或那裡一些的改進,會讓後來的支持人員更加輕鬆。

最後,每一位讀到這裡的網友,感謝你們能耐心地看完。希望在成為一名更優秀的Java程序員的道路上,我們可以一起學習、一起進步。

想了解學習以上內容可加群469717771 驗證:(009)

java互聯網編程—redis應用場景及應用實例詳解

相關推薦

推薦中...