夜间模式暗黑模式
字体
阴影
滤镜
圆角
主题色
数据库 – Redis

下载与安装

  1. 使用 wget 命令下载资源
  2. 解压 redis
    • tar -xzvf redis-5.0.0.tar.gz
  3. 使用 make 编译器
    • 进入 redis 根目录
    • 使用 make 命令
    • make MALLOC=libc
    • 注意:使用之前需要用到 gcc
      • yum -y install gcc automake libtool make #安装 gcc 命令
  4. 启动 Redis 服务
    • redis-server
  5. 启动客户端
    • 创建一个新的会话连接
    • 进入到redis/src目录中
    • redis-cli

 

数据库访问架构的发展阶段

  • 单实例
    • app (web、se、安卓等前端应用程序) –> DAL (数据访问层:jdbc、mybatis、hibernate、自行封装的持久层等) –> MySQLInstance
    • 访问量不能太大
    • 瓶颈:
      • 一台机器中放不了太多的数据
      • 官方给定,MySQL 5.7 一张表可以放500万条记录,然而实际应用中,超过300万条记录之后,会出现访问过慢的情况
      • 因此需要对数据表进行 “瘦身”(分库分表)
      • 数据索引需要额外的占用存储空间
      • 访问量大,并且读写混合现象,一个实例不能承受
  • 缓存 + 垂直拆分
    • 通过缓存减少访问数据库的次数
  • 主从复制 + 读写分离
    • 主从复制提升读和写的性能
    • 对于读操作为主的应用,使用读写分离是最好的方式。
    • 读写分离可以确保写的服务器压力更小
    • 而读又可以接受一些时间上的延迟
  • 分表分库 + 水平拆分 + 集群
    • 集群是一组相互独立的、通过高速网络互联的计算机,构成的一个组,并以单一系统的模式加以管理

什么是 NoSql

  • NoSQl = Not Only Sql
  • NoSql 数据库种类繁多,但数据之间都没有关系
  • NoSql 无需事先为要存储的数据建立字段
  • 随时都可以存储自定义的数据格式
  • 存储形式:Key – Value 存储、列存储、文档存储等
  • 优势:扩展能力强

NoSql 相关产品

  • Memcache
    • 专注用作高速缓存
  • MongoDB
    • 最像关系型数据库的NoSql
  • Redis
    • 数据类型丰富、多功能

Redis 介绍

  • Redis (Remote Dictionary Server),它是一个 Key – Value 的存储系统
  • 它使用 ANSI c 语言编写
  • 有时也被称为“数据结构服务器”
  • Redis 的特点
    • 完全免费开源
    • 是一个高性能的 Key – Value 数据库
    • 可实现持久化
    • Redis 支持的数据类型
      • String
      • list
      • set
      • hash(map)
      • Sorted set

配置

  • 在Redis目录中,找到redis.conf 文件 (此文件为Redis 配置文件,相当于mysql 的my.ini文件)
  • 进入redis.conf文件
    • 修改 port 8000(默认6379)
    • 修改 daemonize yes(默认 no)
  • 注意:不建议在原有的redis.conf文件中修改
    • 在redis目录下创建一个目录etc,将redis.conf复制其中
    • 修改etc下的redis.conf
  • 启动
    • 服务端
      • src/redis-server etc/redis.conf
    • 客户端
      • src/redis-cli -p 8000

常用命令

  • Redis 是单进程的,默认Redis 提供了16个数据库,可以在redis.conf文件中配置默认数据库的数量
  • select:切换数据库
  • dbsize:当前数据库键的数量
  • flushdb:清空当前数据库的数据
  • flushall:清空全部数据库
  • keys操作:
    • keys *:查看所有键的名称
    • exists key:查找给定的键是否存在,存在返回 1,否则返回 0
    • move key db:将指定的数据移动到指定的数据库中
    • ttl key:查看指定的键过期时间,永不过期为 -1
    • expire key:设置指定键的过期时间,单位:秒
    • persist key:为指定键清除过期时间
    • type key:查看类型
    • del key:删除指定键
    • randomkey:随机获得库中的一个键

数据结构

  • string
    • get key:返回指定的key 的 value值
    • set key name [EX|PX|NX|XX]:设置key-value
      • EX|PX:设置有效时间,秒|毫秒
      • NX:在键不存在时,才对键进行设置
      • XX:只有在键已存在时,才对键进行设置
    • append key value:将新数据追加到尾部
    • strlen key:返回指定数据长度
    • incr key:将键中存储的数字加 1
    • decr key:将键中存储的数字减 1
    • incrby key count:将键中存储的数字增加给定的数
    • decrby key count:将键中存储的数字减少给定的数
    • setrange key offset value:设置或修改字符串某个位置的值
    • getrange key start end:获取字符串某个位置的值
    • msetns key1 value1 key2 value2…:同时修改多个key-value,如果存在key,则操作失败
    • mset key1 value1 key2 value2…:同时修改多个key-value,可覆盖
    • mget key1 key2…:同时取多个值
    • setex key timeout value:创建数据并设置过期时间
    • getset key value:先get后set
  • list 集合
    • 常用命令:
      • lpush/rpush key value:在首部/尾部添加数据
      • lrange start end:返回指定区间内的书
      • llen key:返回列表长度
      • lpop/rpop key:弹出首尾元素
      • lindex key index:按照索引位置获取元素
      • lrem key count value:一处列表中与参数value相等的元素
        • count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT
        • count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为 COUNT 的绝对值
        • count = 0 : 移除表中所有与 VALUE 相等的值
      • lrim key start end:保留截取某个范围内的list,其余的删除
      • rpoplpush srckey dstkey:移除列表中的最后一个元素,并将该元素添加到另一个列表并返回
      • lset key index value:通过索引来设置元素的值
      • linsert key BEFORE|AFTER pivot value:在列表的元素前或后插入元素
  • set 集合
    • set 是String 类型的无序集合
    • 集合的成员是唯一的
    • 通过哈希表实现的,所以,添加、删除、查找的复杂度是:O(1)
    • 常用命令
      • sadd key value1 value2…:添加成员
      • smembers key:列出所有成员
      • sismember key value:成员是否存在
      • scard key:获取元素个数
      • srem key value1 value2…:删除集合中的元素
      • srandmember key count:随机返回几个元素
      • spop key count:随机出栈
      • 数学类集合
        • sdiff key1 key2…:返回差
        • sinter key1 key2…:返回交集
        • sunion key1 key2…:返回并集
  • Sorted set(zset)
    • 有序集合
    • 每个元素都会关联一个分数(score)
    • Redis 通过分数为集合进行排序(从小到大)
    • 常用命令
      • zadd key score1 value1 score2 value2…:添加成员
      • zrange key start stop [WITSSCORES]: 指定区间内,有序集成员的列表。
      • zrangebyscore key min max [WITSSCORES] [LIMIT offset count]:返回指定分数取键的成员列表
      • zrem key member1 member2…:删除元素
      • zcard key:返回元素个数
      • zcount key min max:指定分数区间的元素个数
      • zrank key member:返回指定成员的排名
      • zscore key member:获得分数
      • zrevrank key member:以从大到小的顺序返回指定成员的排名
      • zrevrang key start stop [WITSSCORES]:指定区间内,从大到小地显示有序集成员的列表。
      • zrevrangbyscore key max min [WITSSCORES] [LIMIT offset count]:从大到小返回指定分数取键的成员列表
  • Hash
    • Hash 是一个String类型的field和value 的映射表
    • Hash特别适合存储对象
    • 常用命令
    • hset key name value:添加属性值到hash中
    • hget key name:或取指定集合中指定属性值
    • hmset key1 name1 value1 key2 name2 value2…:添加多个属性值到hash 中
    • hgetall name:返回指定集合中所有属性值
    • hlen name:返回元素个数
    • hexists key name:某个键是否存在
    • hkeys key:返回集合中所有的属性名称
    • hvals key:返回集合中所有的属性值
    • hincrby key name number:为哈希表中的字段值加上指定增量值。增量也可以为负数,相当于对指定字段进行减法操作。
      • 如果哈希表的 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。
      • 如果指定的字段不存在,那么在执行命令前,字段的值被初始化为
    • hincrbyfloat key name float: 命令用于为哈希表中的字段值加上指定浮点数增量值。
    • hsetnx key value: 用于为哈希表中不存在的的字段赋值
      • 如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作
      • 如果字段已经存在于哈希表中,操作无效
      • 如果 key 不存在,一个新哈希表被创建并执行 HSETNX 命令

应用

Redis 中的事务

  • Redis 事务可以一次执行多个命令,并且可以保证以下两点
    • 事务时一个单独的隔离操作
      • 所有事务命令序列化并按顺序执行
      • 事务在执行时,不会被其他客户端发送的请求所打断
    • 事务时一个原子操作
      • 全部执行
      • 全部不执行
  • Redis 事务三个阶段
    • 开始事务
    • 命令入队
    • 执行事务
  • 注意:2.2 之后,redis 使用CAS(check and set)
  • 小结:
    • redis是nosql的数据库
    • 主要的用途是做缓存
    • 一般很少用于业务逻辑
    • redis 对事务的支持有限,属于部分支持

Redis 操作事务的三个步骤

  • 开启事务
  • 命令入队(事务未执行)
  • 提交事务
  • 注意:Redis 采用的乐观锁 (CAS)

Redis 事务命令

  • 命令
    • DISCARD:取消事务,放弃执行事务块内的所有命令
    • EXEC:执行所有事务块内的命令
    • MULTI:标记一个事务块的开始
    • UNWATCH:取消WATCH命令对所有key 的监视
    • WATCH key1 key2…:监视一个或多个key,如果在事务执行之前这些key被其他命令所改动,那么事务将被打断
  • Redis 事务的五个操作
    • 提交:multi –> 正确的命令1,2,3 –> exec
    • 回退:multi –> 正确的命令1,2,3 –> discard
    • 连坐:multi –> 命令1,2,3,中间存在错误命令 –> exec
    • 部分提交:multi –> 命令1,2, 失败命令3 –> exec
    • 监控:
      • 悲观锁与乐观锁
        • 悲观锁:并发操作数据时,通过锁机制保证数据访问的同步性
        • 乐观锁:并发操作数据时,不适用锁机制,CAS算法机制来保证操作目标数据的同步性
      • watch 操作
        • 使用 watch 关键字监控目标数据
        • 启动一个事务
        • 添加命令
        • 提交事务
      • 注意:
        • 如果在执行exec之前,操作的目标数据发生改变,则执行失败,需要重新执行操作
        • 由于乐观锁的因素,执行失败后,会反复执行操作,直到操作执行成功

发布订阅

  • Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
  • Redis 客户端可以订阅任意数量的频道。
  • 客户端订阅:订阅一个或多个指定的频道
    • subscribe channel1, channel2…
  • 服务端发布:向指定的频道发布消息
    • publish channel message

持久化

  • 将Redis 内存中的数据永久的保存到本地文件中
  • 持久化两种方式
    • RDB
      • Redis DataBase(全量,对所有数据)
    • AOF
      • Append Only File(增量,对新增数据)

RDB

  • 在指定的时间间隔内将内存中的数据集,快照写入磁盘
  • Redis 通过 Snapshot 快照,将库写入磁盘
  • 将快照文件直接读取到内存中
  • 工作方式:
    • 当Redis需要保存dump.rdb文件时,服务器执行以下操作
      • Redis调用forks,同时拥有父进程和子进程
      • 子进程将数据集写入到一个临时的rdb文件中
      • 当子进程完成对新rdb文件写入时,Redis用新的rdb文件替换原来的rdb文件
  • 配置项
    • stop-writes-on-bgsave-error yes:默认yes,如果为no表示不在乎数据不一致或者有其他手段发现或控制
    • rdbcompression yes:是否压缩数据
    • rdbchecksum yes:在存储快照后,还可以让redis使用CRC64算法验证
  • RDB模式持久化操作步骤
    • 复制redis目录下redis.conf到etc目录中命名为redis_6380.conf
    • 修改etc下的redis_6380.conf
      • 端口号:port 6380
      • 是否开启受保护机制:protected-mode yes
      • 是否后台开启:daemonize yes
      • 进程名称:pidfile /var/run/redis_6380.pid
      • 日志文件:logfile “6380.log”
      • 持久化规则:
        • save 60 10 #每60秒内,至少更改了10次
      • 生成持久化rdb文件:dbfilename dump6380.rdb
    • 启动redis服务
      • src/redis-server tec/redis_6380.conf
      • src/redis-cli -p 6380
    • 当客户端连接服务端时自动生成持久化文件:dump6380.rdb
    • 使用save命令持久化数据
      • 使用save命令立即写入快照数据
    • 使用配置文件的快照规则实现写入
      • 在1分钟之内set命令10次,即根据规则自动写入
    • 备份与还原持久化数据库文件
      • 备份:cp dump6380.rdb dump6380_bak.rdb
      • 还原:cp dump6380_bak.rdb dump6380.rdb,选择覆盖即可
  • 总结:
    • Redis 内存 (rdb load)<– –>(rdb save)磁盘中的rdb文件
    • rdb是一个非常紧凑的文件
    • Rdb在保存文件时父进程唯一需要做的事forks(创建)出一个子进程
    • 所有rdb都将由子进程来做,父进程不需要再做其他的IO
    • 所以,Redis持久化方式可以最大化Redis性能
    • 缺陷:
      • 数据丢失风险大
      • 当父进程forks子进程时,如果数据集比较大,那么会非常耗时,可能会导致redis不能毫秒级响应客户端

AOF

  • 由于RDB模式在故障时将丢失没有被save的数据
  • Redis1.1 版本开始,增加了一种持久化方式 AOF
  • AFO操作方式
    • 需要配置文件中打开AOF模式:appendonly yes
    • AOF生效后,每当Redis执行一个改变数据集的命令(set)时候,这个命令就会被追加到AOF文件(appendonly.aof)的末尾
    • 在Redis重启时,程序可以通过重新执行AOF命令来达到重建数据集的目的
    • 修改配置文件信息:
      • 复制redis.conf文件到etc目录下
      • 添加日志
      • 启动AOF:appendonly yes
      • 生成持久化AOF文件:appendfilename “appendonly.aof”
      • 同步频率(默认即可):

        #appendfsync always 每次变化同步

        appendfsync everysec 每秒同步

        #appendfsync no 不同步,操作系统刷新输出缓存时同步

      • 重写规则(默认即可):

        no-appendfsync-on-rewrite no 重写日志是否同步

        auto-aof-rewrite-percentage 100 当容量达到上次重写时的100%时,重写日志

        auto-aof-rewrite-min-size 64mb 当容量达到64mb时候,重写日志

      • 启动redis服务
      • 启动redis客户端
        • 客户端连接成功后,会生成持久化文件:appendonly.aof
      • 对数据库进行变更
        • 变更后的命令将会加到aof文件的尾部
      • AOF备份与恢复
        • 备份:cp 备份文件
        • 恢复两种形式:
          • 文件
            • 可以修改appendfilename “appendonly.aof”文件中的内容
            • 重启后,执行次文件中的命令,恢复数据
          • 命令
            • redis-check-aof –fix
      • 总结:
        • 客户端 –> 请求命令 –> 服务端 –> 网络协议 –> AOF文件
        • AOF文件是一个只进行追加的日志文件
        • Reids可以在AOF文件体积过大时,自动在后台对AOF进行重写
        • 对于相同的数据集来说,AOF文件会大于RDB文件
      • AOF与RDB比较
        • 优势:同步性好,实时
        • 劣势:速度慢于RDB及占用空间大
      • Rdis持久化总结
        • RDB用于对数据的完整性要求不是太高
        • AOF完整性好,但性能不如RDB
        • 如果只做缓存,可不用任何存储
        • 两种模式可以混合使用

主从复制/读写分离

作用

  • 读写分离
  • 容灾备份

如何配置

  • 配从不配主
  • 从机配置
    • slaveof 主机ip 主机端口

修改配置文件中的信息

  • 拷贝多个redis.conf文件
  • 开启daemonize yes
  • 更改pid文件名称
  • 更改log文件名字
  • 更改dump.rdb的名字
  • 命令
    • info replication 查看连接信息
      • role
        • master:主机
        • connected slaves:连接从机的数量

Redis 主从复制/读写分离的方式

  • 一主二从
    • 启动主机(master)
    • 查看连接信息:info replication
    • 启动从机
    • 查看连接信息
    • 使用slaveof配置从机
      • 格式:slaveof 127.0.0.1 6390
    • 小结:当主机出现故障时,从机仍然可以连接主机,只不过获取不到数据,直到主机恢复正常后,才能获取数据(可能存在延迟)
  • 薪火相传
    • 大部分与一主二从相同
    • 6392 连接 6391 连接6390 连接 6392
  • 反客为主
    • 大部分与一主二从相同
    • 当主机宕机时,可以将任意一个从机转换为主机
    • 从机转主机命令:slaveof no one
    • 主机恢复后,可变为从机连接新主机,获取新数据(数据同步)

通过配置文件进行主从配置

  • 不需要使用命令进行手动设置
  • 在redis.conf 中配置 replicaof <masterip> <masterport>

总结

  • slaveof 启动成功连接到master后会发送一个sync命令
  • master接收到命令启动后台的存盘进程,同时收集所有接收到的用于修改的数据集命令,在后台进程执行完毕后,master将传递整个数据文件到slave,以完成同步
  • 同步时有两种形式
    • 全量复制
      • slave在接收到数据库文件数据后,将其存盘并加载到内存中
    • 增量复制
      • master继续将新的所有收集到的修改命令一次传递给slave,完成同步

哨兵模式

  • Redis-Sentinel
  • 此模式就是反客为主的自动版
  • Redis-Sentinel 高可用解决方案
  • 当redis在做 master-slave高可用方案时,如果master宕机,redis本身都没有实现自动进行主从切换的功能,而redis-Sentinel本身也是独立运行的进程,可以部署在其他与redis可通讯的机器中监控redis集群
  • 操作步骤
    • 在etc目录下创建sentinel.conf文件
    • 在此文件中添加
    • sentinel monitor 被监控数据库的名称
      • 例如:sentinel monitor master6390 127.0.0.1 6390 1
        • 1 代表多少个从机认为主机下线,可以开始投票
    • 启动哨兵
      • redis-sentinel etc/sentinel.conf
    • 启动主机及从机
      • 启动redis后,主机宕机后,从机上位

Jedis 操作 Redis

  • Redis 可视化操作软件:RedisDesktopManager

    • 安装

    • 配置Redis 实现连接

      • 将本地IP注掉:#bind 127.0.0.1

      • 开启安全模式

        • protected-mode yes
        • 设置远程登录密码:requirepass passwd
      • redis启动后,需要输入密码方可访问

        • auth 密码
  • Jedis是一套用来操作Redis数据库的API

  • 使用步骤

    • 创建maven项目

    • 导入依赖

    • 使用API

      • 创建Jedis:Jedis jj = new Jedis(ip, port);

      • 输入远程登录:jj.auth(passwd);

      • 测试连接:jj.ping(); 如果返回 PONG 表明连接成功

         

Java 数据存储 Redis

  • 将Java对象中的数据存储到redis中,需要使用流操作

  • 操作步骤

    • 创建VO类

    • 制作输入输出流工具

      • 注意:不能将一个Java对象直接存储到redis中
    • 对象转换字节

    • 存入redis中

	public static byte[] toBytes(Object obj) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ObjectOutputStream oos;
		try {
			oos = new ObjectOutputStream(baos);
			oos.writeObject(obj);
			return baos.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	public static Object toObject(byte[] b) {
		ByteArrayInputStream bais = new ByteArrayInputStream(b);
		try {
			ObjectInputStream ojs = new ObjectInputStream(bais);
			try {
				return ojs.readObject();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;		
	}
  • 也可用JSON的方式存储数据
	Jedis edis = new Jedis("192.168.229.128",8000);
	edis.auth("passwd");
	System.out.println(edis.ping());
	Person person = new Person("张三",20,"男");
	ObjectMapper mapper = new ObjectMapper();
	String str;
	try {
		str = mapper.writeValueAsString(person);
        edis.set("data",str);
	} catch (JsonProcessingException e) {
		e.printStackTrace();
	} finally {
        edis.close();
    }

 

Java 操作Redis事务

  • 在Java中使用 redis中的相应命令操作事务

  • 常用方法:

    • multi:开启事务
    • exec:提交事务
    • discard:回退
    • watch:监控事务
    • unwatch:关闭监控
    • Transaction:事务
	public static void fun(){
        Jedis edis = new Jedis("192.168.229.128",8000);
		edis.auth("passwd");
        // 事务操作
		edis.watch("balance");
		Transaction t = edis.multi();
		t.decrBy("balance", 25);
		t.incrBy("debt", 25);
		
		t.exec();	//提交事务
		// t.discard(); //回退事务
		edis.close();
		System.out.println("执行成功");
    }
	// 测试watch
	public static void fun2() throws InterruptedException {
		Jedis edis = new Jedis("192.168.229.128",8000);
		edis.auth("passwd");
		List<Object> result = null;
		do {
			edis.watch("balance");
			String value = edis.get("balance");
			System.out.println(value);
			
			Thread.sleep(10000);//这期间修改Redis的值
			
			Transaction t = edis.multi();
			t.decrBy("balance", 25);
			t.incrBy("debt", 25);
			result = t.exec();
			System.out.println("提交结果:"+result);
			if(result != null) 
				edis.unwatch();
		} while(result == null);
	}

 

Redis 连接池

  • JedisPool:Redis连接池
  • JedisConfig:Redis连接池的配置类
public static Demo(){
	public static JedisPool PoolDemo() {
		/* 
		 * JedisPool 构造函数参数
		 * param1: 池的配置信息
		 * param2: 数据库的ip
		 * param3: 数据库的端口号
		 * param4: timeout
		 * param5: 远程连接密码
		 */
		JedisPool pool = new JedisPool(config,"192.168.229.128",8000,5000,"moliao102411");
		// Double Lock
		if(pool == null) {
			synchronized(Demo.class) {
				if(pool == null) {
					JedisPoolConfig config = new JedisPoolConfig();
					config.setMaxTotal(100); // 最大连接数
					config.setMaxIdle(20); // 最大空闲数
					config.setMaxWaitMillis(5000); // 最大等待时间
					pool = new JedisPool(config,"192.168.229.128",8000,5000,"moliao102411");			
				}
			}
		}
		return pool;
	}
   }

 

 

暂无评论

发送评论 编辑评论


				
上一篇