初识 Redis

4,043 阅读4分钟

这两天项目中遇到一个问题,思来想去觉得还是用Redis来解决比较合适,如果朋友们有更合理的解决方案,欢迎不吝赐教。

功能背景及需求

在我们的生活中,QQ、微信等社交产品变得越来越重要,它们集成了越来越多的功能,比如服务号就是其中一个重要的功能,我们可以通过它接收对应的服务消息,QQ、微信也可以通过官方的服务号向每一个用户推送广告、新闻等信息。如图所示:

QQ服务号

作为一个带有社交属性的软件来说,我们深切知道服务号带来的好处,所以在我们自己的App中,也包含了一套服务号系统,只不过我们没有服务号订阅这一功能,但是需要在服务号上标识未读消息数。

产生的问题

说到这,问题就TM来了。

由于我们不含订阅功能,所以服务消息大体包含两类:

  1. 所有用户都能收到的消息,例如一起来记录你的七夕节等
  2. 触发型的消息,例如打赏的通知等

对于类型 2 来说,当有人打赏时,往数据库添加一条对应的打赏记录,然后推送给APP端,一切行云流水。

对于类型 1 来说,就有问题了。比如我们推送七夕活动时,要记录每个人的阅读状态,并且跨设备访问的时候,阅读状态也要同步。我们很容易就能想到在推送活动的时候,为每一个用户都增加一条活动记录,这样就很容易可以获取到每个人的阅读状态及消息数。

但是,假设你有100W用户,你每推一次消息时,就意味着你要产生100W条数据,并且当用户阅读后,还得更新信息的阅读状态,这样会对数据库造成一定的压力

思考的解决方案

既然是担心对数据库造成压力,那么我们可以考虑,能否在数据库和服务器之间存在一个中间层,每次服务器从那个中间层去获取数据,然后中间层再异步更新到数据库中。

我能想到的中间层大概有三种

  1. 缓存(在这里显然不适合)
  2. 消息队列(这里也不合适)
  3. 使用 Redis 来实现(这个可以有)

其实还有一种方案:

用第三方的推送服务,比如个推的推送,有新的活动消息,就发推送给APP,然后未阅读数量就可以放在本地,只不过如果用户换了设备的话,那这个是否阅读及消息未读量就会丢失。

了解 Redis 从安装开始

既然想到用 Redis 来解决这个问题,那么首先得安装 Redis!

安装

CentOS 用户

yum install redis

yum 安装的 Redis 不是最新版本的,所以要想安装最新的稳定版,那么可以

wget http://download.redis.io/releases/redis-3.2.3.tar.gz

tar xzf redis-3.2.3.tar.gz

cd redis-3.2.3

make

Mac 用户

brew install redis

安装下来的是最新稳定版

启动服务

src/redis-server

启动 Redis 的过程中还会出现一些警告,大部分警告可以根据系统提供的解决方案来进行解决,不能解决的上网查资料也很容易解决。

测试

test-redis

设置外网访问

上面我们测试的是在本机上直接访问,但是更多的时候,我们需要外网访问。

首先 确保 6379(Redis 默认端口号) 可被监听

  • 6379端口号已经开启监听(netstat -nat |grep :6379) 查看监听状态 如图所示,表明已经在监听,如果显示的是 ENABLE 状态,则需要开启监听。

  • 开启6379端口号,我所用的系统是 CentOS7 ,其他版本可能会有不同(/sbin/iptables -I INPUT -p tcp --dport 6379 -j ACCEPT) 开启监听

其次 编辑 redis.conf 配置文件,将 bind 一栏注释掉,默认绑定的是127.0.0.1

如果还是不能访问,试试以下解决方案:

access-problem

使用 Jedis 连接 Redis

下载 jar 包

在 Java 语言中,一般用 Jedis 进行操作 Redis .点击进入 Jedis 的 GitHub 主页.你可以参照文档使用它。这里我已经将最新的 jedis-2.9.0.jar 放入云端,方便大家下载使用。

项目中导入 jedis-2.9.0.jar 包后,就可以试着连接 Redis 服务器了。

编写测试类

创建 RedisTest.java

import redis.clients.jedis.Jedis;
public class RedisTest {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("xxx.xx.xxx.xxx");
        jedis.set("foo", "bar");
        String value = jedis.get("foo");
        System.out.println(value);
    }
    }

不出意外的话,结果会打印出 bar !

这里千万不要在IP地址后面跟端口号,例如:localhost:6379,这样是不可取的,debug 我们会发现,在 jedis 去操作 redis 的时候,它会去创建连接,并且会把默认的端口号传入进去。

6379

yuanma

如果要改端口号的话,则应该这样写:

Jedis jedis = new Jedis("xxx.xx.xxx.xxx",port);

这是我的血泪教训,一时没看清,瞎忙活几个小时!

最后

写到这,好像都和项目离远了,等这个小需求完成后,再继续更新,以上都是很浅显的知识,如果有错误或者思路不对的地方,还希望能得到指正。