linux redis安装及JAVA使用jedis

一、redis 安装

可能遇到的错:

(1).zmalloc.h:50:31: 致命错误:jemalloc/jemalloc.h: 没有那个文件或目录。

解决方案:make MALLOC=libc

(2). 应在安装前确保安装了 gcc:yum install -y gcc 

1. 安装 redis
  将 redis 安装包放到指定目录下。并用 tar -zxvf redis.*****.tar.gz 解压
2. 想把 redis 安装到哪里,就在哪里创建 redis 文件夹。
  如 mkdir /home/chx/allSoftCert/redis
2. 进入解压后的目录内,如 redis4.0.0
3.cd src
4.sudo make install PREFIX=/home/chx/allSoftCert/redis
5.cp ../redis.conf /home/allSoft/redis/
6. 运行测试:./home/chx/allSoftCert/redis/bin/redis-server /home/chx/allSoftCert/redis/redis.conf
  错误: 如果发生 make[1]: Entering directory 错误,则执行 make distclean 后再次安装
7. 开启远程的端口
  iptables -I INPUT -p tcp --dport 6379 -j ACCEPT
  iptables save
8. 修改密码
  vi /home/chx/allSoftCert/redis/redis.conf

注释 bind 127.0.0.1
修改 daemonize no 为 daemonize yes
解注释 requirepass foobared 并修改为 requirepass 123456

有密码时关闭脚本:./home/chx/allSoftCert/redis/bin/redis-cli -a 123456 shutdown

9. 接下里就可以进行 java 测试了

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class MainJedis {

private static final String REDIS_IP = "192.168.0.156";
private static final String REDIS_AUTH = "123456";
private static final int MAX_TOTAL = 100;// 最大连接数
private static final int MAX_ID_LE = 10;// 最大空闲数
private static final int REDIS_DUAN_KOU = 6379;

public static void main(String[] args) {

JedisPoolConfig config = new JedisPoolConfig();

config.setMaxTotal(MAX_TOTAL);// 设置最大连接数

config.setMaxIdle(MAX_ID_LE);// 设置最大空闲数

JedisPool pool = null;

Jedis jedis =null;

try {

pool = new JedisPool(config,REDIS_IP,REDIS_DUAN_KOU);

jedis = new Jedis(REDIS_IP,6379);

jedis.auth(REDIS_AUTH);

jedis.set("chx", "boy");

System.out.println(jedis.get("chx"));

}catch (Exception e) {

e.printStackTrace();

}finally {

if(jedis!=null) {

jedis.close();

}
if(pool!=null) {

pool.close();

}

}

}

}

pom.xml 对应如下:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>JedisTest</groupId>
<artifactId>firstJedis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>firstJedis</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
</project>

 二、JAVA 中使用 redis

1.java 对象存储在 redis 内。

两种方式:

(1). 序列化和反序列化。

(2). 转换为 json 存储。

2.redis 的几种数据结构

String: 字符串

Hash: 散列

List: 列表

Set: 集合

Sorted Set: 有序集合

3.Jedis 基础命令

jedis.del("key","key2");// 删除 key

jedis.auth(REDIS_AUTH);// 操作密码

jedis.set("chx", "boy");// 放入普通的 key-value

jedis.exists("chx");// 判断是否存在某个 key

System.out.println("系统中所有键如下:");

// 查询系统所有 key 值

Set<String> keys = jedis.keys("*");

Iterator<String> it=keys.iterator();

while(it.hasNext()){

  System.out.println(it.next());

}

// 设置 key 值的储存时间,单位秒

jedis.expire("chx", 2);

// 获取 key 的存储时间,永久生存或者不存在的都返回 -1

jedis.ttl("chx");

// 移除 key 的生存时间

jedis.ttl("chx");

jedis.type("chx"));// 查看 key 所储存的值的类

jedis.rename("old", "new");// 修改 key 值

jedis.mset("chx2", "value2", "chx3", "value3");// 一次性增加多个 key-value

List<String> mget = jedis.mget("chx","chx1","chx2","chx3");// 一次性获取多个 value

jedis.setnx("chx", "change");// 放入 key-value 时防止覆盖旧值的方法

jedis.flushDB();// 清空 DB 所有数据

 

Jedis 列表 (List):

jedis.rpush("myList", "1","2","3","a");// 从右边添加,即尾插入

jedis.lrange("myList", 0, -1);// 从左边获取

jedis.lrem("myList", 2, "1");// 从左侧删除 2 个值为 1 的数据

 

Jedis 集合 Set

System.out.println("清空库中所有数据:" + jedis.flushDB());

jedis.sadd("mySet", "1","2","3");

System.out.println(jedis.smembers("mySet"));


Jedis hash

System.out.println("清空库中所有数据:" + jedis.flushDB());

jedis.hset("myHash", "name", "chx");

Map<String, String> users = new HashMap<String, String>();

users.put("age", "18");

jedis.hmset("myHash", users)

System.out.println(jedis.hgetAll("myHash"));

  4. 切片和非切片连接池的概念

    JedisPool 连一台 Redis,ShardedJedisPool 连 Redis 集群,通过一致性哈希算法决定把数据存到哪台上。

5.redis 有密码的情况下关闭 redis-server 服务

  ./redis-cli -a 123456 shutdown

6. 集群下使用 reids:

  查看此文章

三、常用 redis 数据类型

1. 字符串:

在 Redis 中字符串类型的 Value 最多可以容纳的数据长度是 512M。

set xx(key) xx(value),返回 OK,如果 key 存在会覆盖。

get xx(key),只能获取 String 类型的,不是 String 会报错。

append key value:在原有的 value 后追加;如果该 key 不存在,则重新创建一个 key/value。

msetnx key1 value1 key2 value2:如果 key1 存在,则 key2 也放不进去。只有都不存在时才能放进去。

2.list:

lset xx(key) index xx(value):设置链表中的 index 的脚标的元素值,0- 链表的头元素,-1- 链表的尾元素。

lrem key count value:删除 count 个值为 value 的元素,count>0,从头向尾删除 count 个值为 value 的元素,count<0,则从尾向头删除。如果 count=0,则删除链表中所有等于 value 的元素。

linsert key before|after pivot value:在 pivot 元素前 | 后插入 value。

3.set:

Set 集合中不允许出现重复的元素。

smembers xx(key):获取 set 中所有的成员。

scard xx(key):获取 set 中成员的数量。

sismember xx(setX) xxv(value):判断 xxv 是否在 setX 中,1 存在,0 不存在。

srem xx(setX) xxv(value):删除 value。

sdiff set1 set2:返回 set1 中 set2 没有的数据 (既差集,按顺序返回)。

4.Hash:

结构为 hash(key)-field(多个)-value(多个)。

每一个 Hash 可以存储 232 - 1 键值对(40 多亿)。

hset hash field value:为指定的 hash 设定 field/value 对 (键值对)。如果哈希表不存在,将创建 HASH 并进行操作。设置成功返回 1,覆盖返回 0。

hget hash field:返回指定 hash 的 key 的值。

hexists hash field:判断指定的 hash 中的 field 是否存在。

hlen hash:hash 中 field 的数量。

四、分布式情况下存储用户状态

当单台机器不能满足性能提升时,大多采用分布式,但是 session 是基于 cookie 进行获取的,导致不同机器的 jsessionid 会不同,而导致用户访问不同机器时会重新登入。

所以一般用 redis 等内存存储的数据库进行 session 存储。原理是将 sessionid 为 key 值,用户信息为 value 进行存储。每次访问先去 redis 获取用户信息,没有说明是非法登入。同时 redis 可以设置数据的过期时间,由此可以基本实现原 session 功能。

五、Redis 面试相关

Redis 是高可用,NoSQL(not-only sql,泛指非关系型数据库)的数据库。

1. 缓存穿透:就是由于大量访问不在 redis 的数据 (比如非法传入 ID 为 -1),导致每次都需要去数据库查询,导致数据库无法承载而崩溃。此时重启都无法解决,因为新的访问仍会导致崩溃。这里可以用布隆过滤器做处理,布隆过滤器是一个 bit 向量或者说 bit 数组,数据的 hash 的每个数值位(如 Hash 值等于 147) 散落在 bit 数组内。所以查询时如果 1、4、7 位有值说明此数据可能存在(之所以不是一定存在是因为 Hash 冲突),1、4、7 位不存在的则一定不存在。参考此文,非常不错

2. 缓存雪崩:由于热点数据 (注意是热点) 同一时间失效,导致大量访问涌入时都访问的数据库而导致崩溃。

3. 缓存击穿:由于一个热点数据访问量过大,而此数据失效的瞬间导致击穿崩溃。

4.Redis 是单线程,至于为什么这么快。首先由于 Redis 的操作都基于内存,所以读写耗时问题可以忽略,更多的是 CPU 及网络带宽影响其上下限,单线程避免了 CPU 不必要的上下文切换和竞争条件,也避免了锁的耗时问题。再者,Redis 采用 Key-Value 存储,基本读是 O(1) 的时间复杂度。

5. 有关主从复制:从节点仅提供读操作,主节点提供写操作。从节点中的定时任务发现主节点信息,连接建立后,主节点将所有数据发送给从节点(数据同步)。主节点把当前的数据同步给从节点后,便完成了复制的建立过程。接下来,主节点就会持续的把写命令发送给从节点,保证主从数据一致性。

6.Redis 分片及 Hash 槽相关:首先 Redis 采用 Hash 槽来确定数据分配到集群的哪个主机,每个节点的槽位 (如 0-5000) 是需要人工配置的,最大槽位为 2 的 14 次方即 16384。第一个槽位和最后一个槽位相连,形成一个圆环,需要放入新数据时,利用 crc16 求出 hash 值,对 16384 求余而确定放入那个节点。之所以不用一致性 hash 是为了避免数据倾斜问题。参考此篇文章。所以每次扩展或宕机时,只需要把该节点的所有槽位转移到新节点即可。

7. 有关哨兵:哨兵是一个独立的进程,顾名思义,哨兵主要用于监控 -Master 和 Slave 是否运作正常、提醒 - 通过 API 向管理员或者其他应用程序发送通知、自动故障迁移 - 将失效 Master 的其中一个 Slave 升级为新的 Master(就像电视里的巡逻、吹哨、发现危险拿起武器操作一番)。多个哨兵使用投票协议 (agreement protocols) 来决定是否执行自动故障迁移, 以及选择哪个 Slave 作为新的 Master。

哨兵个数最少是三个,并且建议是奇数个。主要是为了投票主节点是否下线,少数服从多数。几个哨兵投票为多数的配置,在 sentinel.conf 里配置 sentinel monitor 开头的一行,最后一个数字即是投票数。

哨兵默认端口号:26379  redis 默认端口号 6379

redis 是没有回滚的。其事务主要是为了能够全部执行正确的操作。如果在执行时出错,如转账功能,是不会回滚的 (效率第一的理念)。但是运行前的入队操作,有语法错误是不会提交的。

8.Redis 持久化:就两种,一种是 RDB(Redis DataBase),一种是 AOF(Append Only File)。

RDB:指定时间间隔内,将内存的数据集快照,保存到磁盘。Redis 会创建一个子进程,将快照写入临时文件中,等到持久化结束就覆盖上一次的备份。此过程主进程不进行 IO 操作。如上所述,很有可能丢失最后一次备份。所以适合完整性和一致性要求不高的情况,Fork 时候是克隆当前主进程,导致两倍的内存占比,需要考虑内存配置。在 Redis.conf 可以配置文件名及自动备份时间。

AOF:利用文件保存所有写操作,只追加不能修改,Redis 重启就会读取此文件进行恢复。如果遇到断电等 aof 文件错乱的情况,可以用 redis-check-aof --fix 文件名 来修复。所以也会丢失近一段时间的数据,不过一般比 RDB 丢失的少。在 redis.conf 里可修改当占用多大存储 (auto-aof-rewrite-min-size 64mb 默认 64 兆) 时进行压缩及比上次膨胀百分比(auto-aof-rewrite-percentage 100 默认 100%),

9. 事务:MULTI 开始事务,添加指令 (任何符合规范的命令 get set 等),EXEC 执行事务。一个命令在录入时失败则全失败 (即 EXEC 之前失败)!如果是运行时失败则其他的是成功的!!

Watch 一个或多个 key 表示监视一个或多个 key,执行 exec 命令后,锁都被释放。如果期间有其他人改动过这些 key 的 value 值,则事务被打断。

10. 关于 ACID:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)是相对于事务而言。Redis 保证了数据的一致性 (内存模式下,重启后为空,不会一部分保存一部分未保存)、隔离性 (单线程不涉及其他事务),实现了部分原子性 (如第九条,EXEC 可以在运行失败时完成其他成功语句),但是没有持久性,因为 Redis 事务执行过程中如果崩溃,不一定能够恢复。