青花小记

这个人很懒,只想写写代码做做饭

0%

项目的创建

访问start.spring.io,选择相应的模块,生成代码,导入到IDE中即可

也可以直接使用IDE进行创建,以idea为例:

点击新建项目,选择Spring Initializr,选择JDK和URL

输入图片说明

填写项目相关信息,点击next

输入图片说明

选择需要用到的模块,本例中先选择Web,后续如果有用到其他模块,可以再进行添加

输入图片说明

点击Finish,完成SpringBoot项目的创建

创建完成后,会自动创建相应的文件夹,并生成一个【项目名+Application】的Java类,如我的项目名是rabbit,则创建的Java类为 RabbitApplication

如图为自动创建的资源文件和Java类

输入图片说明

RabbitApplication是整个项目的入口类

1
2
3
4
5
6
7
@SpringBootApplication
public class RabbitApplication {

public static void main(String[] args) {
SpringApplication.run(RabbitApplication.class, args);
}
}

Redis的虚拟内存和操作系统的虚拟内存不是一码事,但是思路和目的都是相同的:

就是暂时把不常访问的数据从内存交换到磁盘中,从而腾出宝贵的内存空间

Redis在用户态实现了自己的虚拟内存机制

主要的理由有以下两点:

  1. 操作系统的虚拟内存是以4k/页为最小单位进行交换的。而Redis 的大多数对象都远小于4k,所以一个操作系统页上可能有多个Redis对象。另外Redis的集合对象类型如list,set可能存在于多个操作系统页上,最终可能造成只有10%的key 被经常访问,但是所有操作系统页都会被操作系统认为是活跃的,这样只有内存真正耗尽时操作系统才会进行页的交换。

  2. 相比操作系统的交换方式,Redis 可以将被交换到磁盘的对象进行压缩,保存到磁盘的对象可以去除指针和对象元数据信息。一般压缩后的对象会比内存中的对象小10 倍。这样Redis 的虚拟内存会比操作系统的虚拟内存少做很多IO 操作。

虚拟内存配置

#开启虚拟内存的功能
vm-enabled yes

#交换出来value保存的文件路径/tmp/redis.swap
vm-swap-file /tmp/redis.swap

#redis使用的最大内存上限,超出上限后redis开始狡猾value到磁盘swap文件中,建议设置为系统空闲内存的60%~80%
vm-max-memory 268435456

#每个Redis页的大小 字节
vm-page-size 32

#最多在文件中使用多少个页,交换文件的大小 = (vm-page-size * vm-pages)
vm-pages 1334217728

#用于执行value对象换入换出的工作线程数量,0表示不使用工作线程
vm-max-threads 8

Redis的虚拟内存在设计上为了保证key 的查询速度,只会将value 交换到swap 文件中。如果是由于太多key很小的value造成的内存问题,那么redis 的虚拟内存并不能解决问题。和操作系统一样redis 也是按页来交换对象的。redis 规定同一个页只能保存一个对象。但是一个对象可以保存在多个页中。在redis 使用的内存没超过vm-max-memory 之前是不会交换任何value 的。当超过最大内存限制后,redis 会选择把较老的对象交换到swap文件中去。如果两个对象一样老会优先交换比较大的对象, 精确的交换计算公式swappability = age*log(size_in_memory)。对于vm-page-size 的设置应该根据自己应用将页的大小设置为可以容纳大多数对象的尺寸。太大了会浪费磁盘空间,太小了会造成交换文件出现过多碎片。对于交换文件中的每个页,redis 会在内存中用一个1bit 值来对应记录页的空闲状态。所以像上面配置中页数量(vm-pages 134217728 )会占用16MB 内存用来记录页的空闲状态。vm-max-threads 表示用做交换任务的工作线程数量。如果大于0 推荐设为服务器的cpu 的核心数。如果是0 则交换过程在主线程进行。

Redis虚拟内存工作方式简介

当vm-max-threads设置为0时(阻塞方式)
换出

主线程定期检查发现内存超出最大上限后,会直接以阻塞的方式,将选中的对象保存到swap文件中,并释放对象占用的内存空间,此过程会一直重复直到下面条件满足:

1.内存使用降到最大限制以下

2.swap文件满了

3.几乎全部的对象都被交换到磁盘

换入

当有客户端请求已经被换出的value时,主线程会以阻塞的方式从swap文件中加载对应的value对象,加载时会阻塞所有客户端,然后处理该客户端的请求

当vm-max-threads设置为大于0时(工作线程方式)
换出

当主线程检测到使用内存超过最大上限,会将选中要交换的对象信息放到一个队列中交给工作线程后台处理,主线程会继续处理客户端请求

换入

如果有客户端请求的key已经被换出了,主线程会先阻塞发出命令的客户端,然后将加载对象的信息放到一个队列中,让工作线程去加载。加载完毕后工作线程通知主线程,主线程再执行客户端的命令,这种方式值阻塞请求的value是已经被换出key的客户端

总的来说,阻塞方式的性能更好一点,因为不需要线程同步、创建线程和恢复被阻塞的客户端等开销,但是也相应的牺牲了响应性

工作线程方式主线程不会阻塞在磁盘IO上,所以响应性更好

如果应用不太经常发生换入换出,而且也不太在意有点延迟的话,推荐使用阻塞方式

Redis支持将数据同步到多个从服务器上

1.Master可以有多个slave

2.多个slave可以练到同一个Master上,也可以连接到其他slave上

3.主从复制不会阻塞Master,Master可以继续处理客户端发来的请求,反而slave在初次同步数据时则会阻塞不能处理客户端的请求

4.主从复制可以提高系统的伸缩性,可以用多个slave专门用于客户端的读请求,也可以做简单的数据冗余

5.可以在Master禁用数据持久化,只在slave上配置数据持久化

主从复制过程

1.slave与master建立连接,发送sync同步命令

2.master启动一个后台进程,将数据库快照保存在文件中,同时master主进程会开始收集新的写命令并缓存起来

3.后台进程完成写文件后,master就发送文件给slave,slave将文件保存在磁盘上,然后加载到内存恢复数据库快照到slave上

4.接着master就会把缓存命令转发给slave,而且后续master收到的写命令都会通过开始建立的连接发送给slave

注意:

master到slave的同步数据的命令和从客户端发送的命令使用相同的协议格式

当master和slave的连接断开时slave可以自动重新建立连接

如果master同时收到多个slave发来的同步连接命令,只会启动一个进程来写数据库镜像,然后发送给所有slave

配置

在配置文件中写入配置即可

slaveof 1.1.1.1 6379      #指定master的IP和端口

1.设置Redis密码

修改redid.conf文件

#requirepass foobared
requirepass yourpassword

重启Redis服务

2.设置防火墙,关闭Redis的6379端口的对外访问

一般不建议设置密码,只需要关闭端口的对外访问即可

关于key的操作

Redis的key是字符串类型的,不可以包含空格和换行字符

获取所有的键
keys *
查看数据库的key的数量
dbsize
检测某个key是否存在,返回1表示存在,0表示不存在
exits key 
删除给定的key,返回删除key的数目,如果返回0,则表示给定的key不存在
del key1, key2, ... 
返回给定key值的类型,返回none表示key不存在
type key 
重命名一个key,如果newkey存在,将会被覆盖;返回1表示成功,返回0表示失败,可能是oldkey不存在或者和newkey相同
rename oldkey newkey 
重命名一个key,和rename类似,但是如果newkey存在会返回失败
renamenx oldkey newkey
为key指定过期时间,单位是秒;返回1成功,0表示key已经设置过过期时间或者key不存在
expire key seconds 
返回设置了过期时间的key的剩余过期秒数,-1表示key不存在或者未设置过期时间
ttl key 
取消过期时间
persist
随机返回数据库里的一个key
randomkey
将key从当前数据库移动到指定数据库,返回1表示成功,0表示key不存在或者已经在指定的数据库中
move key db-index

数据库操作

通过索引选择数据库,默认连接的数据库是0,默认数据库是16个; 返回1表示切换成功,0表示失败
select db-index 
清空当前数据库,慎用
flushdb
清空所有数据库,慎用
flushall

监控

获取当前redis服务器状态和一些统计信息
info
返回相关的配置信息
config get paramter
返回所有配置
config get *
实时监听并返回redis服务器接收到的所有请求信息
monitor
获取一个key的调试信息
debug object key

其他

制造一次服务器当机
debug segfault
打印命令
echo

String 字符串类型

二进制安全,可以包含任何数据,比如jpg图片或者序列化的对象;从内部实现看,string其实可以看做byte数组,最大上限是1G字节

语法
set name qinghuazangshui --赋值 set key value

get name --获取内容 get key

setnx (not exist)

setnx name qinghua  --存在则修改,不存在则赋值  setnx key value

setex (expired)

setex name 10 qinghua2 --设置过期时间

setrange name 2 qaq --从第二位开始替换,替换成qaq

mset key1 value1 key2 value2 --设置多个键值

mget key1 key2 key3 --一次性取多个值

getset name qinghua3 --返回旧值,返回新值 getset key value

incr age  --递增操作,数字类型 incr key,相当于++操作,如果value不是int类型的会返回错误,incr一个不存在的key,则设置key的值为1

decr age --递减操作,数字类型 decr key, 相当于--操作,decr一个不存在的key,则设置key的值为-1

incrby/decrby age 3 --增加/减少指定的值 incrby/decrby key integer 

append name 123 --追加

Hash类型

Hash类型是String类型key和value的映射表,或者说是一个String集合

添加、删除操作都是O(1)(平均)

适合存储对象

相对而言,将一个对象类型存储在Hash类型里要比存储在String类型里占用更少的内存空间,并方便存取整个对象;省内存的原因是新建一个hash对象时开始使用zipmap来存储的。

如果field或者value的大小超出一定限制后,redis会在内部自动将zipmap替换成正常的hash实现,可以在配置文件中设置最大值

hash-max-zipmap-entries 64 #配置字段最多64个

hash-max-zipmap-value 512 #配置value最大为512字节
语法
hset user id 1 --设置属性和值 hset key field value

hset user name qinghua

hset user age 18

hget user id --取值 hget key field

hget user name 

hmset user id  2 name qinghua2 age 20 --批量设置键值 hmset key field1 value1 field2 value2...

hmget user id name age --批量取值 hmget key field1 field2...

hexists user age --是否存在键值 hexists key field 

hlen user --user的长度 hlen key 返回指定hash的field的数量 

hkeys user --获取user的所有键  返回hash的所有field

hvals user --获取user下的所有值 hvals key

hgetall user --返回hash的所有的键值 hgetall key 

hdel key field --删除指定的hash field

hincrby key field integer --将制定hash field加上指定值

List类型

链表结构(双向链表)的集合,即可以理解为一个每个子元素都是string类型的双向链表

主要功能有push、pop、获取元素等,可以在头部或尾部增删元素,操作中key理解为链表的名字

既可以作为栈,也可以作为队列

lpush list qinghua  --从头部添加元素,返回1表示成功,0表示key存在且不是list类型 lpush key string

rpush list zangshui --在尾部添加元素 rpush key string

linsert list before zangshui qaq --插入

lrange list 0 -1 --遍历List,-1代表最后的索引位置  lrange key start end 返回指定区间内的元素,下标从0开始,复制表示从后面计算,-1表示倒数第一个元素,key不存在返回空列表

lset key index value--将制定下表的元素替换掉,成功返回1

lrem list 1 qinghua --删除元素,返回删除的元素个数 lrem key count value 从list的头部(正数)或尾部(负数)删除一定数量匹配value的元素,返回删除的元素数量,count为0时删除全部

ltrim key start end--保留指定key的值范围内的数据,截取 list指定区间内元素,成功返回 1,key不存在返回错误

lpop key--从头部删除元素,并返回删除元素

rpop key--从尾部删除元素,并返回删除元素

rpoplpush --从尾部删除元素,然后从头部插入元素

lindex --返回名称为key的list中index位置的元素

llen key--返回元素的个数,即返回key对应的list的长度,如果key不存在返回0,如果key对应类型不是list返回错误    

set集合

string类型的无序集合,通过hashtable实现,实现集合的交集、并集、差集操作,查找的复杂度为O(1),hashtable会随着添加或者删除自动的调整大小,需要注意的是调整hash table大小的时候需要同步(获取写锁),会阻塞其他读写操作。

最大可以包含2^32-1个元素

set中不允许重复

sadd set1 aaa --添加元素 sadd key member 成功返回1,如果元素以及在集合中则返回0,key对应的set不存在则返回错误

srem key member --从key对应set中移除指定元素,成功返回1,如果member在集合中不存在或者key不存在返回0,如果key对应的不是set类型的值返回错误

spop key --删除并返回key对应set中随机的一个元素,如果set是空或者key不存在返回nil

srandmember key -- 同spop,随机取set中的一个元素,但是不删除元素

smove srckey destkey member --从srckey对应set中移除member并添加到destkey对应set中,整个操作是原子的。成功返回1,如果member在srckey中不存在返回0,如果key不是set类型返回错误

scard key --返回set中元素的个数,如果set是空或者key不存在返回0

smembers key --返回key对应set的所有元素,结果是无序的

sinter key1 key2 --返回所有给定key的交集

sinterstore destkey key1 key2 --取交集结果,并存储到指定集合destkey中

sunion key1 key2 --取并集

sunionstore destkey key1 key2 --取并集结果,并存储到指定集合destkey中

sdiff key1 key2 --返回所有给定key的差集

sdiffstore destkey key1 key2 --取差集结果,并存储到指定集合destkey中

sismember key member --判断member是否在set中,存在返回1,0表示不存在或者key不存在

zset 有序集合

可以做搜索排行

zadd key score member--向有序集合中添加一个元素,元素在集合中存在则更新对应score

zrem key member --删除指定元素,1表示成功,如果元素不存在返回0

zincrby key incr member --增加对应member的score值,然后移动元素并保持skip list保持有序。返回更新后的score值

zrank key member --返回指定元素在级合格中的排名(下标),集合中元素是按score从小到大排序的

zrevrank key member --同上,但是结合中元素是按score从大到小排序

zrange key start end --类似lrange操作从集合中去指定区间的元素,返回的是有序结果

zrevrange key start end --同上,返回结果是按score逆序的

zrangebyscore key min max --返回集合中score在给定区间的数量

zcount key min max --返回集合中score在给定区间的数量

zcard key --返回集合中元素个数

zscore key element --返回给定元素对应的score      

zremrangebyrank  key min max --删除集合中排名在给定区间的元素

zremrangebyscore key min max --删除集合中score在给定区间的元素

该篇主要是针对Redis的配置文件中各项配置的一个简单说明,为后期Redis的应用提供一个参考

阅读全文 »

  1. 首先需要安装gcc,把下载好的redis-3.0.0-rc2.tar.gz放到linux的/usr/local文件夹

  2. 进行解压

     # tar -zxvf redis-3.0.0-rc2.tar.gz
    
  3. 进入到redis-3.0.0目录下,进行编译

     # cd redis-3.0.0-rc2
    
     # make
    

    验证(ll查看src下的目录,有redis-server 、redis-cil即可)

  4. 建立俩个文件夹存放redis命令和配置文件

        # mkdir -p /usr/local/redis/etc
    
        # mkdir -p /usr/local/redis/bin
    
  5. 把redis-3.0.0下的redis.conf 移动到/usr/local/redis/etc下,

        # cp redis.conf /usr/local/redis/etc/
    
  6. 把redis-3.0.0/src里的mkreleasehdr.sh、redis-benchmark、redis-check-aof、redis-check-dump、redis-cli、redis-server文件移动到bin下

        # mv mkreleasehdr.sh redis-benchmark redis-check-aof redis-check-dump redis-cli redis-server /usr/local/redis/bin
    

    redis-server: Redis服务器的daemon启动程序

    redis-cli: Redis命令行操作工具

    redis-benchmark: Redis的性能测试工具,测试Redis在你的系统及你的配置下的读写性能

     # redis-benchmark -n 100000 -c 50 --模拟同时由50个客户端发送100000个SETs/GETs查询
    

    redi-check-aof:更新日志检查

    redis-check-dump:本地数据库检查

  7. 启动时并指定配置文件:

        # cd /usr/local/redis/bin
    
        # ./redis-server /usr/local/redis/etc/redis.conf
    

    注意要使用后台启动,所以修改redis.conf里的 daemonize 改为yes

  8. 验证启动是否成功:

        # ps -ef | grep redis 
    

    查看是否有redis服务

    或者

    查看端口:

     # netstat -tunpl | grep 6379
    
  9. 进入redis客户端

     # ./redis-cli 
    

    退出客户端

     # quit
    
  10. 退出redis服务

    (1)pkill redis-server

    (2)kill 进程号

    (3)/usr/local/redis/bin/redis-cli shutdown

    (4) 关闭指定端口的redis服务

    # redis-cli -p 6379 shutdown
    

泛指非关系型数据库

四大分类

1.键值存储数据库(KV)

Redis、Memecached

2.列存储数据库

通常用来应对分布式存储的海量数据

键仍然存在,但是指向了多个列

HBase、Riak

3.文档型数据库

MongoDB

4.图形数据库

特点:

数据模型比较简单

需要灵活性更强的IT系统

对数据库性能要求较高

不需要高度的数据一致性

对于给定Key,比较容易映射复杂值的环境

K-V形式存储

优点:

对数据高并发读写

对海量数据的高效率存储和访问

对数据的可扩展性和高可用性

缺点:

ACID处理非常简单

无法做到太复杂的关系数据模型

数据类型
  • string 字符串

  • 哈希

  • list 链表

  • set 集合

  • zset 有序集合

持久化

RDB

AOF

集群策略
  1. 主从形式

  2. 哨兵形式

  3. 3.0之后的集群模式

主从形式

主节点写,从节点读

哨兵形式

哨兵节点去监控主从节点的状态,主节点挂掉之后,哨兵会在从节点之间选取一个节点,提升为主节点;如果主节点重新加入,则变成从节点