美文网首页
Redis系列之初出茅庐

Redis系列之初出茅庐

作者: 油馍头_V | 来源:发表于2017-02-28 19:37 被阅读0次

    首先,给大家讲一个关于小明的故事。

    小明的一天

    小明是一名应届生,从大一接触C语言后就励志要做一名凭借自己双手改变世界的程序员。经过4年的努力,他也如愿以偿地拿到了某个特别火热的UGC平台的研发offer。在经过短暂的实习后,他正式步入工作岗位。

    小明哭了

    有一天晚上,在小明正准备回家的时候,产品MM来找他说要做一个排行榜功能:“要在一个页面中展示发表评论最多的Top10用户”,还说是老板提的,明天就要上线。小明一听不敢怠慢,心想是时候展现自己的才华了,便立刻在工位上陷入了沉思。

    评论表的定义是这样的:

    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 '评论内容',
      `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 '赞数',
      PRIMARY KEY (`id`),
      KEY `idx_news_id` (`news_id`),
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评论表'
    

    第一个想法很快诞生,不就是要Top10吗,直接从db把结果查出来不就行了嘛。 group by order by一句sql搞定。同时作为一个在学校就做了很多项目的他,一下就想到了可以通过在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;
    

    又然后,经过了短暂时间的啪啪啪啪,全部搞定!接下来怎么办?肯定是上线啊。 不行,还是要先在线下测一下�吧,怎么测呢?

    首先,他很聪明的想到要先借助一个简单的存储过程在线下库mock一批数据

    (PS:如果大家看不懂下面的存储过程,可以先忽略,你只要知道我们这一步是往我们的线下库插入了1000W数据即可。)

    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, '评论内容', NOW());
          set i=i+1;
      end while;
    end
    

    然后,调用这个存储过程来为mock数据

    call add_data(10000000)
    

    伴随着一万匹草泥马路过,数据终于造好了(PS:过程比较慢,大家可以在自己的机器上跑一下)。

    最后,到了最关键的一步了,调下接口看看成果吧~ 要下班啦要下班啦

    只听回车键啪的一声,1s过去了... 2s过去了... 等了N秒之后结果才展示出来。此时此刻,小明的内心是崩溃的。

    一定是网络原因,紧接着又是一声回车键,然后~

    网络看不下去了,大喊道:“这锅我不背!”。小明不得不承认,这不是网络原因。

    怎么办?赶紧查原因吧,先从最底层查起,看看查询sql用了多长时间。小明得到了下面的结果

    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:想知道为什么这么慢?请关注我后面的文章哦,如果你已经知道了可以忽略)

    小明笑了

    哭是没用的,小明告诉自己要振作起来。马上又陷入了新一轮思考。

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

    1. 通过定时Task,每5s从db中查询出top10结果,放到固定的存储空间中。
    2. 用户请求top10结果时,可以直接从该存储空间中读取返回给用户。

    但该方案有两个要解决的问题。

    1. 由于top10结果是定时Task每5s计算一次,也就意味在第N个任务执行后,第N+1个任务执行前的这段时间内,读取的结果都是基于“第N次计算时的数据集合”计算出来的。所以存在一定的误差。
    2. 由于我们的核心诉求就是降低响应时间,所以存储空间的读取性能一定要非常高。

    首先第一个问题,在跟PM说明问题后,PM很爽快的就答应了。那么第二个问题,就要靠自己来解决了。

    突然,小明灵光一现,想到了一个存储空间,那就是Redis!

    前方高能!前方高能!
    (PS:一篇讲Redis的文章,到现在才提到,也是没谁了,大家再忍耐一下继续看完)

    1. Redis是一个由C语言编写的开源的key-value数据库。
    2. Redis将所有的数据都保存到内存中。
    3. Redis性能极高,由于将数据保存在内存中,再加上内部独特的设计和实现,读QPS能达到11W,写QPS能到达8W。

    当然,这些只是Redis的其中一部分特性,但已经完全可以满足我们的需求。

    解决了存储问题,一条完整的解决方案出现在小明的脑海里。

    1. 异步任务计算Top10,计算结果放到Redis,key = authorIds,value = #{计算出来的结果},并且该任务5秒钟重新计算一次并更新value。
    2. 用户请求Top10展示,直接从Redis中读取key = authorIds 的值,返回给用户即可。

    接下来,又伴随着一大波啪啪啪啪的键盘声,小明终于搞定了这个需求。

    小明抬头一看,此时正好4点钟。他想起了自己偶像说过的一句话:“你见过凌晨4点钟的洛杉矶吗?”

    “是的,那时候我刚下班”,小明情不自禁的说。

    (PS:我真的是科密)

    Ending

    整个故事结束了。从这个故事中我们可以看到,当数据量达到一定的量级的时候,传统的关系型数据库就会暴露出一些问题,而这些问题必须通过其他的方式去解决,比如我们提到的Redis。

    其实这篇文章关于Redis的知识很少,但我想任何一个刚接触Redis的人都不想一开始就学习他的语法,而是想知道Redis到底有什么用?有哪些场景可以用到?他能给我们带来什么?从上面小明的例子中,我想大家或多或少能对Redis有了一个初步的认识,如果你因此对Redis产生了兴趣,那就好好学下去吧~

    接下来,我会根据这个故事中提到的关于Redis点,来跟大家进行深一步的探讨。

    相关文章

      网友评论

          本文标题:Redis系列之初出茅庐

          本文链接:https://www.haomeiwen.com/subject/nucfgttx.html