Redis的安装和使用

——CentOS7+Redis4.0.1

Posted by Zwx on November 6, 2018

前言

  上一篇写到在Nginx配置负载均衡服务器集群时会出现session不一致的问题,其中解决问题的最好方案就是session外置,集中管理,放在缓存中。而缓存最常用的有Memcache和Redis,两者都可以看做是key/value型的nosql数据库, 但是Memcache的value只能存String类型,而Redis的value里可以存5种数据类型,我之前又在windows环境下使用过Redis,所以就写一篇在Linux环境下安装配置使用Redis的笔记。最后再用Redis解决下负载均衡的session不一致性问题。


什么是Redis?

  Redis是用C语言开发的高性能的键值对存储的非关系数据库,运行在内存中。Redis存储的数据类型有以下几种:字符(String)、散列(Hash)、列表(List)、集合(Set)、有序集合(ZSet)。


安装

#下载压缩包 在哪个目录下运行的命令就下载到哪个目录下
wget http://download.redis.io/releases/redis-4.0.1.tar.gz
#解压
tar -zxvf redis-4.0.1.tar.gz
#进入解压目录并编译Redis
cd redis-4.0.1
#进行编译
make
#安装Redis  PREFIX后是安装路径
make install PREFIX=/usr/local/redis

配置

  复制redis-4.0.1目录下的redis.conf至/usr/local/redis/bin下,为了使Redis可以远程连接,修改redis.conf下的内容:

  • bind 127.0.0.1改为 #bind 127.0.0.1
  • protected-mode yes 改为 protected-mode no
  • 加入 daemonize no(这个是是否在后台启动不占用一个主程窗口)

启动

  在redis的安装目录下的bin目录,

./redis-server redis.conf

看到如下界面说明启动成功:

19063:C 05 Nov 16:59:22.841 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
19063:C 05 Nov 16:59:22.841 # Redis version=4.0.1, bits=64, commit=00000000, modified=0, pid=19063, just started
19063:C 05 Nov 16:59:22.842 # Configuration loaded
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 4.0.1 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 19063
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

19063:M 05 Nov 16:59:22.843 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
19063:M 05 Nov 16:59:22.843 # Server initialized
19063:M 05 Nov 16:59:22.843 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
19063:M 05 Nov 16:59:22.843 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
19063:M 05 Nov 16:59:22.843 * Ready to accept connections
19063:M 05 Nov 17:14:23.027 * 1 changes in 900 seconds. Saving...
19063:M 05 Nov 17:14:23.027 * Background saving started by pid 19159
19159:C 05 Nov 17:14:23.031 * DB saved on disk
19159:C 05 Nov 17:14:23.031 * RDB: 0 MB of memory used by copy-on-write
19063:M 05 Nov 17:14:23.127 * Background saving terminated with success

   —

远程连接Redis

  • java中的Jedis
  • 可视化工具RedisDesktopManager

Jedis

引入maven依赖

<!--redis-->
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
</dependency>

新建测试类:

@Test
public void redis(){
	Jedis jedis=new Jedis("xx.xx.xx.80",6379);
	jedis.set("laozhang","zhenshuai");		
	System.out.println(jedis.get("laozhang"));
}

运行测试类,控制台输出结果:

...
2018-11-05 18:08:36.423  INFO 5308 --- [           main] s.d.spring.web.caching.CachingAspect     : Caching aspect applied for cache operations with key /hello.com.zwx.demo.controller.HelloController.hello.DefaultGenericTypeNamingStrategy
2018-11-05 18:08:36.446  INFO 5308 --- [           main] s.w.ClassOrApiAnnotationResourceGrouping : Group for method hello was 这是一个hello类
2018-11-05 18:08:36.450  INFO 5308 --- [           main] s.w.ClassOrApiAnnotationResourceGrouping : Group for method hello was 这是一个hello类
2018-11-05 18:08:36.479  INFO 5308 --- [           main] com.zwx.demo.DemoApplicationTests        : Started DemoApplicationTests in 9.247 seconds (JVM running for 10.846)
zhenshuai
2018-11-05 18:08:36.713  INFO 5308 --- [       Thread-2] o.s.w.c.s.GenericWebApplicationContext   : Closing org.springframework.web.context.support.GenericWebApplicationContext@2d52216b: startup date [Mon Nov 05 18:08:28 CST 2018]; root of context hierarchy
   
Process finished with exit code 0

成功输出key为laozhang对应的value。

可视化工具

直接百度下载RedisDesktopManager,打开后点击Connect to Redis Server,输入相关信息直接可以连接。


Redis数据类型

参考Redis中文网,都是写好的方法,一看就懂,拿来用就好


Session外置 Redis管理

  • 这里要摆脱狭义的Session,Session不只是Servlet里的HttpSession对象的那个Session。要把Session看做是保存用户信息的东西,不管是什么都行,哪怕一串字符串都行,只要能从中提取到用户信息,那这个东西就是Session。(自己的理解,有可能有歧义)。 为了好理解,还是用的HttpSession的sessionid演示。

修改接口:

   @RequestMapping(value = "/hello", method= RequestMethod.GET)
    public String hello(int i, HttpSession session){
        String sessinId=SessionUtils.setSession(i,session);
        System.out.println(i+"_"+sessinId);
        return "Hello!!!!"+"_"+i+"_"+sessinId;
    }

新建Session工具类:

/**
*@Auther z
*@Date 2018-11-06 16:08
*@Describe
*/
public class SessionUtils {
    public static String setSession(int i,HttpSession session){
        /**连接redis*/
        Jedis jedis=new Jedis("47.93.236.80",6379);
        /**判断该键为i的缓存是否存在*/
        if(jedis.exists(String.valueOf(i))){
            /**如果存在,返回value中key为sessionId的值*/
            return jedis.hmget(String.valueOf(i),"sessionId").get(0);
        }else {
            /**如果不存在,新建map保存至redis中*/
            Map<String,String> map=new HashMap<>();
            map.put("sessionId",session.getId());
            jedis.hmset(String.valueOf(i), map);
            jedis.expire(String.valueOf(i),60);
            /**返回sessionId的值*/
            String sessinId=jedis.hmget(String.valueOf(i),"sessionId").get(0);
            return sessinId;
        }
    }
}

重新部署到两台服务器上,负载均衡规则设置为轮询,发送10次请求:

看日志: 80服务器:

2018-11-06 16:43:11.923  WARN 22030 --- [nio-7080-exec-1] o.a.c.util.SessionIdGeneratorBase        : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [86,624] milliseconds.
2018-11-06 16:43:11.935  WARN 22030 --- [nio-7080-exec-2] o.a.c.util.SessionIdGeneratorBase        : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [35,004] milliseconds.
1_98E9900584A442AF8E0C97D6D0C7545F
1_98E9900584A442AF8E0C97D6D0C7545F
1_98E9900584A442AF8E0C97D6D0C7545F
3_1331DE63752324B6A7252E6ECE2C542D
1_C3E8058CBE6B26AB997C8B9AD3CBE7C7
1_C3E8058CBE6B26AB997C8B9AD3CBE7C7
1_C3E8058CBE6B26AB997C8B9AD3CBE7C7
1_C3E8058CBE6B26AB997C8B9AD3CBE7C7
1_C3E8058CBE6B26AB997C8B9AD3CBE7C7

201服务器:

1_98E9900584A442AF8E0C97D6D0C7545F
2_E6872BE5F93126A5831B8A998EBB7C0E
3_1331DE63752324B6A7252E6ECE2C542D
1_C3E8058CBE6B26AB997C8B9AD3CBE7C7
1_C3E8058CBE6B26AB997C8B9AD3CBE7C7
1_C3E8058CBE6B26AB997C8B9AD3CBE7C7
1_C3E8058CBE6B26AB997C8B9AD3CBE7C7
1_C3E8058CBE6B26AB997C8B9AD3CBE7C7

发现最后10次请求每个服务器各接受了5次,参数为1时sessionId相同,解决了负载均衡下的Session不一致性问题。


后记

  session里只存一个Servlet里的HttpSession的sessionId其实啥用都没有,就是为了演示保存了相同的用户信息。在真正项目中,session中一般保存的是通过一定加密或编码方式 保存的用户名和密码啥的,是可以确定这个用户登陆过的信息的内容。