Redis系列之初出茅廬

首先,給大家講一個關(guān)于小明的故事。

小明的一天

小明是一名應(yīng)屆生,從大一接觸C語言后就勵志要做一名憑借自己雙手改變世界的程序員。經(jīng)過4年的努力,他也如愿以償?shù)啬玫搅四硞€特別火熱的UGC平臺的研發(fā)offer。在經(jīng)過短暫的實習(xí)后,他正式步入工作崗位。

小明哭了

有一天晚上,在小明正準(zhǔn)備回家的時候,產(chǎn)品MM來找他說要做一個排行榜功能:“要在一個頁面中展示發(fā)表評論最多的Top10用戶”,還說是老板提的,明天就要上線。小明一聽不敢怠慢,心想是時候展現(xiàn)自己的才華了,便立刻在工位上陷入了沉思。

評論表的定義是這樣的:

CREATE TABLE `news_comment` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `author_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '作者Id',
  `news_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '新聞Id',
  `content` text NOT NULL COMMENT '評論內(nèi)容',
  `created` datetime NOT NULL,
  `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `up_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '贊數(shù)',
  PRIMARY KEY (`id`),
  KEY `idx_news_id` (`news_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='評論表'

第一個想法很快誕生,不就是要Top10嗎,直接從db把結(jié)果查出來不就行了嘛。 group by order by一句sql搞定。同時作為一個在學(xué)校就做了很多項目的他,一下就想到了可以通過在author_id上加個索引以提升查詢效率。

首先,建索引:

alter table news_comment add index `idx_author_id` (`author_id`);

接著,寫出查詢sql:

select author_id, count(*) as comment_count from news_comment group by author_id order by comment_count desc limit 10;

又然后,經(jīng)過了短暫時間的啪啪啪啪,全部搞定!接下來怎么辦?肯定是上線啊。 不行,還是要先在線下測一下?吧,怎么測呢?

首先,他很聰明的想到要先借助一個簡單的存儲過程在線下庫mock一批數(shù)據(jù)

(PS:如果大家看不懂下面的存儲過程,可以先忽略,你只要知道我們這一步是往我們的線下庫插入了1000W數(shù)據(jù)即可。)

create procedure add_data(num int)
begin
  declare i int;
  declare news_id int;
  declare author_id int;
  set i=0;
  while i<num do
      SET news_id = MOD(i, 10000) + 1;
      SET author_id = MOD(i, 100000) + 1;
      insert into news_comment(author_id, news_id, content, created) values(author_id, news_id, '評論內(nèi)容', NOW());
      set i=i+1;
  end while;
end

然后,調(diào)用這個存儲過程來為mock數(shù)據(jù)

call add_data(10000000)

伴隨著一萬匹草泥馬路過,數(shù)據(jù)終于造好了(PS:過程比較慢,大家可以在自己的機器上跑一下)。

最后,到了最關(guān)鍵的一步了,調(diào)下接口看看成果吧~ 要下班啦要下班啦

只聽回車鍵啪的一聲,1s過去了... 2s過去了... 等了N秒之后結(jié)果才展示出來。此時此刻,小明的內(nèi)心是崩潰的。

一定是網(wǎng)絡(luò)原因,緊接著又是一聲回車鍵,然后~

網(wǎng)絡(luò)看不下去了,大喊道:“這鍋我不背!”。小明不得不承認(rèn),這不是網(wǎng)絡(luò)原因。

怎么辦?趕緊查原因吧,先從最底層查起,看看查詢sql用了多長時間。小明得到了下面的結(jié)果

mysql> select author_id, count(*) as comment_count from news_comment group by author_id order by comment_count limit 10;
+-----------+---------------+
| author_id | comment_count |
+-----------+---------------+
|     59206 |           100 |
|     63302 |           100 |
|     40004 |           100 |
|     44100 |           100 |
|     63975 |           100 |
|     68071 |           100 |
|     72072 |           100 |
|     76168 |           100 |
|     88106 |           100 |
|     92202 |           100 |
+-----------+---------------+
10 rows in set (2.09 sec)

水落石出!怪不得請求這么慢,光花在db的查詢時間就這么久,得趕緊想辦法解決了。
這時,小明落下了委屈的淚水:”我想回家~~~“
(PS:想知道為什么這么慢?請關(guān)注我后面的文章哦,如果你已經(jīng)知道了可以忽略)

小明笑了

哭是沒用的,小明告訴自己要振作起來。馬上又陷入了新一輪思考。

很快,小明又想到了第二種方案。

  1. 通過定時Task,每5s從db中查詢出top10結(jié)果,放到固定的存儲空間中。
  2. 用戶請求top10結(jié)果時,可以直接從該存儲空間中讀取返回給用戶。

但該方案有兩個要解決的問題。

  1. 由于top10結(jié)果是定時Task每5s計算一次,也就意味在第N個任務(wù)執(zhí)行后,第N+1個任務(wù)執(zhí)行前的這段時間內(nèi),讀取的結(jié)果都是基于“第N次計算時的數(shù)據(jù)集合”計算出來的。所以存在一定的誤差。
  2. 由于我們的核心訴求就是降低響應(yīng)時間,所以存儲空間的讀取性能一定要非常高。

首先第一個問題,在跟PM說明問題后,PM很爽快的就答應(yīng)了。那么第二個問題,就要靠自己來解決了。

突然,小明靈光一現(xiàn),想到了一個存儲空間,那就是Redis!

前方高能!前方高能!
(PS:一篇講Redis的文章,到現(xiàn)在才提到,也是沒誰了,大家再忍耐一下繼續(xù)看完)

  1. Redis是一個由C語言編寫的開源的key-value數(shù)據(jù)庫。
  2. Redis將所有的數(shù)據(jù)都保存到內(nèi)存中。
  3. Redis性能極高,由于將數(shù)據(jù)保存在內(nèi)存中,再加上內(nèi)部獨特的設(shè)計和實現(xiàn),讀QPS能達(dá)到11W,寫QPS能到達(dá)8W。

當(dāng)然,這些只是Redis的其中一部分特性,但已經(jīng)完全可以滿足我們的需求。

解決了存儲問題,一條完整的解決方案出現(xiàn)在小明的腦海里。

  1. 異步任務(wù)計算Top10,計算結(jié)果放到Redis,key = authorIds,value = #{計算出來的結(jié)果},并且該任務(wù)5秒鐘重新計算一次并更新value。
  2. 用戶請求Top10展示,直接從Redis中讀取key = authorIds 的值,返回給用戶即可。

接下來,又伴隨著一大波啪啪啪啪的鍵盤聲,小明終于搞定了這個需求。

小明抬頭一看,此時正好4點鐘。他想起了自己偶像說過的一句話:“你見過凌晨4點鐘的洛杉磯嗎?”

“是的,那時候我剛下班”,小明情不自禁的說。

(PS:我真的是科密)

Ending

整個故事結(jié)束了。從這個故事中我們可以看到,當(dāng)數(shù)據(jù)量達(dá)到一定的量級的時候,傳統(tǒng)的關(guān)系型數(shù)據(jù)庫就會暴露出一些問題,而這些問題必須通過其他的方式去解決,比如我們提到的Redis。

其實這篇文章關(guān)于Redis的知識很少,但我想任何一個剛接觸Redis的人都不想一開始就學(xué)習(xí)他的語法,而是想知道Redis到底有什么用?有哪些場景可以用到?他能給我們帶來什么?從上面小明的例子中,我想大家或多或少能對Redis有了一個初步的認(rèn)識,如果你因此對Redis產(chǎn)生了興趣,那就好好學(xué)下去吧~

接下來,我會根據(jù)這個故事中提到的關(guān)于Redis點,來跟大家進(jìn)行深一步的探討。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容