一.Redis(内存式nosql数据库)
- NoSQL与RDBMS
1.1:RDBMS(关系型数据库mysql)的特点:体现数据之间的关系,支持事务,保障业务的完整性和稳定性,小数据量的性能也比较好。但是高并发会导致数据库奔溃。
1.2NoSQL(非关系型数据库Redis,HBASE,MongoDB)的特点:一般用于高并发高性能场景下的数据缓存或者数据库存储,读写速度快,并发量高,不如RDBMS稳定,对事务性的支持不太友好。
读注重并发,写注重安全。 - Redis的功能和应用场景:
2.1定义:基于内存的分布式的nosql数据库,所有数据存储在内存中,并且持久化机制,每次redis重启会从文件中重新加载数据到内存,所有的读写都只是基于内存
2.2功能:高性能高并发的数据存储读写
2.3特点:与硬件交互性能好,基于内存实现数据读写,读写性能快,分布式的(扩展和稳定),kv结构数据库,拥有各种丰富的数据类型(String,hash,list,set,zset)
2.4应用场景:缓存(高并发的大数据量缓存,临时性缓存),数据库(高性能的小数据量读写,大数据存储实时处理的结果),消息中间件(消息队列,大数据一般不用用kafka) - redis的单机部署:
3.1上传解压,安装C语言的编译器:
yum -y install gcc-c++ tcl
3.2编译安装
进入源码目录:/export/server/redis-3.2.8/编译make;安装: make PREFIX=/export/server/redis-3.2.8-bin install
3.3修改配置(拷贝配置文件):
cp /export/server/redis-3.2.8/redis.conf /export/server/redis-3.2.8-bin/
创建日志文件
mkdir -p /export/server/redis-3.2.8-bin/logs
创建数据文件
mkdir -p /export/server/redis-3.2.8-bin/datas
修改配置:
vim redis.conf
改绑定的机器地址:
后台运行
日志存储位置
内存中持久化数据存储位置
创建软连接指向redis-3.2.8-bin: ln -s redis-3.2.8-bin redis
修改配置文件
启动:编辑启动脚本在redis的bin目录下:
#!/bin/bash
REDIS_HOME=/export/server/redis
${REDIS_HOME}/bin/redis-server ${REDIS_HOME}/redis.conf
添加权限:chmod u+x /export/server/redis/bin/redis-start.sh
端口为:6379.
客户端连接:redis-cli -h node1 -p 6379
shutdown关闭服务端。或:kill -9 `cat /var/run/redis_6379.pid ``
-
redis的数据结构和数据类型
数据结构:kv结构存在k作为唯一标识符,固定为string类型;v:真正存储的数据,可以事string,hash,list,set,zset,bitmap。hypeloglog。
4.1 string用于存储单个字符串,存储结果
pv:页面访问量,用户每访问一个页面,pv就加一
uv:用户访问量,每个用户算作一个uv
4.2 hash:map集合,用于存储多个属性的值
4.3 list:list,有序可重复,可以存储多个值
4.4 set:set去除重复的值,唯一
4.5 zset:TreeMap,结合了list和set的特点,有序,且不重复(排序规则实现topn) -
redis的通用命令:
5.1 keys:列举当前数据库的所有key
5.2 del key:删除key
5.3 exists key:判断key是否存在
5.4 type key:查看类型
5.5 expire key 20s:20s后key过期
5.6 ttl key:key还有多长时间过期
5.7select n:切换数据库默认存0开始有16个数据库,个数可以通过配置文件修改db0
5.8 move key n:将某个key移到某个数据库
5.9 flushdb:清空数据库
5.10 flushall:清空所有数据库的key -
对字符串string的操作:
6.1 set : set s1 hadoop
6.2 get key:获取指定key的值
get s1
6.3将给定的key的值设置成value,并返回key的旧值
getset key value
6.4设置多个string类型的kv:mset k1 v1 k2 v2
6.5获取多个value:mget k1 k2
6.6构建抢占锁,搭配expire来使用,只能用于新增数据,当k不存在时新增setnx k v
6.7 incr:用于对数值类型的字符串进行递增1,一般用于计数器 incr k
6.8 指定对数值类型的字符串增长固定的步长:incrby k n
6.9 对数值类型的数据进行递减1:decr k
6.10 decrby:按照指定步长进行递减 decrby k n
6.11 strlen:统计字符串的长度 strlen k
6.12 getrange:用于截取字符串
-
hash 类型
7.1 hset:用于为某个key添加一个属性 hset k k v
7.2hmset:批量的为某个k赋值:
hmset K k1 v1 k2 v2 ……
7.2 hget:用于获取某个k的某个属性值 hget k k
7.3hmget :批量的获取某个k的多个属性的值
hmget k k1 k2 k3 k4
7.4hgetall:获取所有属性的值 hgetall k
7.5hdel:删除某个属性
hdel k k1 k2 k3
7.6 hlen:统计k对应的value总的属性的个数
hlen k
7.7 hexists:判断这个k是否包含这个属性
hexists k k
7.8 hvals:获取所有属性的value
7.9 hkeys:获取所有的属性
-
list类型的常用命令
8.1lpush:将每个元素放到集合的左边,左序放入
lpush k e1 e2
8.2 rpush:将每个元素放到集合的右边,右序放入
rpush k e1 e2
8.3lrange:通过下标的范围来获取元素的数据
lrange k start end从0 或-1
8.4llen:统计集合的长度
llen k
8.5 lpop:删除左边的一个元素
lpop k
8.6 rpop:删除右边的一个元素
rpop k -
set 类型的常用命令
9.1 sadd:用于添加元素到 set集合中
9.2 smembers:用于查看set集合的所有成员
9.3 sismember:判断是否包含这个元素
9.4 srem:删除其中某个元素
9.5 scard:统计集合长度
9.6 sunion :取两集合的并集
sunion k1 k2
9.7 sinter:取两集合的交集
sinter k1 k2 -
Zset类型的常用命令
10.1 zadd:添加元素到zset集合
10.2 zrevrange:倒序查询
10.3 zrem:移除一个元素
10.4 zcard:统计集合的长度
10.5 zscore:获取评分
node1:6379> zadd zset1 10000 hadoop 2000 hive 5999 spark 3000 flink
(integer) 4
node1:6379> zrange zset1 0 -1
1) "hive"
2) "flink"
3) "spark"
4) "hadoop"
node1:6379> zrange zset1 0 -1 withscores
1) "hive"
2) "2000"
3) "flink"
4) "3000"
5) "spark"
6) "5999"
7) "hadoop"
8) "10000"
node1:6379> zrange zset1 0 2 withscores
1) "hive"
2) "2000"
3) "flink"
4) "3000"
5) "spark"
6) "5999"
node1:6379> zrevrange zset1 0 -1
1) "hadoop"
2) "spark"
3) "flink"
4) "hive"
node1:6379> zrevrange zset1 0 2
1) "hadoop"
2) "spark"
3) "flink"
node1:6379> zrevrange zset1 0 2 withscores
1) "hadoop"
2) "10000"
3) "spark"
4) "5999"
5) "flink"
6) "3000"
node1:6379> zadd zset1 4000.9 oozie
(integer) 1
node1:6379> zrange zset1 0 -1
1) "hive"
2) "flink"
3) "oozie"
4) "spark"
5) "hadoop"
node1:6379> zrange zset1 0 -1 withscores
1) "hive"
2) "2000"
3) "flink"
4) "3000"
5) "oozie"
6) "4000.9000000000001"
7) "spark"
8) "5999"
9) "hadoop"
10) "10000"
node1:6379> zrem zset1 oozie
(integer) 1
node1:6379> zrange zset1 0 -1 withscores
1) "hive"
2) "2000"
3) "flink"
4) "3000"
5) "spark"
6) "5999"
7) "hadoop"
8) "10000"
node1:6379> zcard zset1
(integer) 4
node1:6379> zscore zset1 flink
"3000"
node1:6379>
- bitmap类型的常用命令
11.1 通过一个string 对象的存储空间,来构建位图,每一位用0和1来表示状态。
11.2 setbit:修改某一位的值
setbit bit1 0 1
11.3 bitcount :统计一的个数
bitcount bit1 0 10:第0-80有几个一
11.4 bitop :与或非运算
bitop and/or/xor/not - hyperloglog:类似于set使用与数据量大,存在一定的误差率
12.1 pfadd:添加元素
12.2 pfcount:统计个数
12.3 pfmerge:合并
- 代码构建
13.1添加依赖
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<!-- <verbal>true</verbal>-->
</configuration>
</plugin>
</plugins>
</build>
13.2 构建连接
package bigdata.redis;
import org.junit.After;
import org.junit.Before;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisClientTest {
Jedis jedis=null;//普通的jedis对象
@Before
public void getConnectipn() {
//方式1直接实例化,指定服务端地址:机器 端口
//jedis=new Jedis("node1",6379);
//方式2构建线程池
//线程池的配置对象
JedisPoolConfig config=new JedisPoolConfig();
config.setMaxTotal(10);//线程池的最大连接数
config.setMaxIdle(5);
config.setMinIdle(2);
JedisPool jedisPool=new JedisPool(config,"node1",6379);
//从线程池中获取连接
jedis=jedisPool.getResource();
}
@After
//关闭连接
public void closeconnect(){
jedis.close();
}
}
13.3常用5种类型的操作:
13.3.1 string操作:
public void StringTest(){
jedis.set("name", "lihua");
System.out.println(jedis.get("name"));
jedis.set("s2", "10");
System.out.println(jedis.incr("s2"));
Boolean s2 = jedis.exists("s2");
System.out.println(s2);
jedis.expire("s2", 10);
while (true){
System.out.println(jedis.ttl("s2"));
if(jedis.ttl("s2")==-2)break;
}
13.3.2 hash的操作:
public void hashTest(){
jedis.hset("hash1", "k1", "hash是 最好的");
System.out.println(jedis.hget("hash1","k1"));
//hmset
Map map=new HashMap();
map.put("name", "lihua");
map.put("age", "26");
map.put("sex", "nan");
jedis.hmset("m11",map);
System.out.println(jedis.hmget("m11", "age","sex"));
Map<String, String> hgetAll = jedis.hgetAll("m11");
System.out.println(hgetAll);
}
13.3.3 list类型:
public void listTest(){
jedis.lpush("list1", "3","2","1","0");
System.out.println(jedis.lrange("list1",0,4));
}
13.3.4 set类型:
public void setTest(){
jedis.sadd("set1", "1","2","3","1","9","10","5","3");
System.out.println(jedis.smembers("set1"));
System.out.println(jedis.scard("set1"));
}
13.3.5 zset类型
public void zsetTest(){
jedis.zadd("zset11", 0,"hadoop");
jedis.zadd("zset11", 30,"hive");
jedis.zadd("zset11", 40,"flash");
jedis.zadd("zset11", 20,"happy");
jedis.zadd("zset11", 100,"hp");
System.out.println(jedis.zrange("zset11",0, -1));//排序输出
System.out.println(jedis.zrangeWithScores("zset11", 0,-1));
System.out.println(jedis.zrevrange("zset11", 0, -1));
}
- 数据存储设计:
14.1 数据存储如何保障数据安全性?
磁盘存储:空间大,安全性相对较高,但读写性能相对较差;数据安全:副本机制(硬件副本:RAIDI,软件副本HDFS的block)
内存存储:数据存储在内存,读写相对较高,空间小不稳定;数据安全:内存的操作日志,将内存的变化追加到写入磁盘文件或者将整个内存的数据存储到磁盘一份
14.2 HDFS的数据怎么保障安全性?
linux磁盘通过副本机制。
14.3 HDFS的元数据怎么保障安全性?
元数据存储在:namenode的内存中,或namenode节点的磁盘上的fsimage文件
故障重启:将内存元数据的变化记录在edits文件中
每次启动namenode,将edits文件与fsimage文件合并恢复内存元数据 - Redis的持久化
15.1 每次redis写入内存,将数据同步到磁盘,如果重启就将磁盘的数据重新加载到内存,提供读写。
15.2 RDB方案:redis默认的持久化方案:按照一定的时间内,如果redis内存中的数据产生一定次数的更新,就将整个redis的所有数据拍摄一个全量快照文件存储在硬盘上,新的快照覆盖老的快照,快照是全量快照,基本与内存一致。
手动触发:在redis目录下的datas/dump.rdb
命令:save(阻塞) 或bgsave
自动触发:按照一定的时间内发生的更新次数,拍摄快照。
配置文件中有对应的配置:
默认3组,如果只有一组,面向不同的场景会导致数据的丢失,针对不同的读写速度,满足各种情况下数据的保存策略。存在一定的数据丢失情况。
15.3 AOF设计
将内存数据的操作日志追加写入一个文件中,当redis发生故障重启,从文件中进行读取所有的操作日志,恢复内存中的数据。
15.3.1 always:每新加一条数据就同步更新操作追加到文件
15.3.2 appendfsync everysec:每秒将内存中数据的操作异步追加写入文件,有数据丢失的风险,最多丢失1s
15.3.3 appendfsync no:交给操作系统,不由redis控制