2024-09-04

Redis中集合(Set)的底层实现可以是intset或者hashtable。

  1. intset:当集合中的所有元素都是整数并且元素数量不多时,Redis会使用整数集合(intset)作为集合的底层实现。
  2. hashtable:当集合的元素不满足intset的条件时,Redis会使用哈希表(hashtable)作为集合的底层实现。

例如,以下是使用Redis命令操作集合的示例:




# 创建一个名为myset的集合,并添加几个元素
> SADD myset 1 "two" 3.0

# 查看myset的内容
> SMEMBERS myset
1) "1"
2) "two"
3) "3.0"

# 查看myset的底层实现
> OBJECT ENCODING myset
"intset" # 假设元素都是整数或能转换为整数

# 继续添加一个非整数元素
> SADD myset "four"

# 查看myset的底层实现变化
> OBJECT ENCODING myset
"hashtable" # 当集合包含不可以转换为整数的元素时,底层实现变为哈希表

以上命令展示了如何在Redis中创建一个集合,如何查看集合的内容,以及如何查看集合的底层实现。当我们向集合中添加非整数元素"four"时,集合的底层实现由原来的intset变为hashtable。

2024-09-04

复现Redis未授权访问远程代码执行漏洞(CVE-2015-3208,也称为CNVD-2015-07557)的步骤如下:

  1. 使用Docker运行Vulfocus的Redis未授权访问环境。
  2. 利用Redis未授权访问漏洞执行任意命令。

以下是一个简单的复现示例:

首先,确保你有Docker环境。

然后,运行以下命令来启动一个包含漏洞的Docker容器:




docker run -d --name cve-2015-3208 vulhub/redis:unauthorized-rce

容器启动后,漏洞利用通常需要发送一个特制的请求到Redis服务。你可以使用curl或者nc来进行测试。

例如,使用curl




curl -X POST -d '*2\r\n$6\r\nconfig\r\n$3\r\nget\r\n$8\r\ndir\r\n*1\r\n$2\r\n*\r\n*1\r\n$1\r\n1\r\n' http://your-ip:6379

替换http://your-ip:6379为实际的Redis服务地址。

如果Redis未授权访问漏洞存在,执行上述命令后,你将能够获取服务器上的目录信息。

请注意,在实际的渗透测试中,你应该遵守相关法律法规,并在获得授权的情况下进行测试。不要对未经授权的系统执行渗透测试或任何可能违反其网络安全政策的活动。

2024-09-04

Redis 支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合),zset(有序集合)。

以下是各种数据类型的基本操作命令:

  1. string(字符串)



# 设置键值
SET key value
 
# 获取键值
GET key
 
# 删除键值
DEL key
  1. hash(哈希)



# 设置哈希字段
HSET hash_key field value
 
# 获取哈希字段
HGET hash_key field
 
# 删除哈希字段
HDEL hash_key field
  1. list(列表)



# 在列表左侧插入元素
LPUSH list_key value
 
# 在列表右侧插入元素
RPUSH list_key value
 
# 获取列表元素
LRANGE list_key start stop
 
# 删除列表元素
LREM list_key count value
  1. set(集合)



# 添加元素到集合
SADD set_key member
 
# 获取集合所有成员
SMEMBERS set_key
 
# 删除集合中的元素
SREM set_key member
  1. zset(有序集合)



# 添加成员到集合,并设置分数
ZADD zset_key score member
 
# 获取集合所有成员及分数
ZRANGE zset_key start stop [WITHSCORES]
 
# 删除集合中的成员
ZREM zset_key member

以上命令均为基本命令,Redis 还支持更复杂的操作,如事务、锁等,需要根据具体场景使用。

2024-09-04

Redis是一个开源的使用C语言编写的、支持网络交互的、可基于内存也可持久化的日志型、Key-Value数据库,并提供多种语言的API。

以下是Redis中一些常用的命令和数据结构:

  1. 常用命令:

    • SET:为一个键设置值。
    • GET:获取一个键的值。
    • DEL:删除一个键。
    • EXPIRE:为一个键设置过期时间。
    • EXISTS:检查一个键是否存在。
    • KEYS:查找符合给定模式的键。
    • PING:测试与服务器的连接是否仍然有效。
  2. 数据结构:

    • 字符串(String):可以存储任何类型的字符串,包括二进制、JSON、序列化对象等。
    • 列表(List):按照插入顺序保存数据,可以在头部或尾部添加或删除元素。
    • 集合(Set):无序的字符串集合,不允许重复。
    • 有序集合(Sorted Set):字符串成员与浮点数分数相关联,成员是唯一的,分数可以重复。
    • 哈希(Hash):包含键值对的无序散列表。
    • 位图(Bitmap):用于处理二进制数据,可以对位进行设置、清除和切换操作。
    • 超级字符串(HyperLogLog):用于计算集合的基数,适合用于数据统计。
  3. 使用示例:

    
    
    
    # 设置键值对
    SET key "value"
     
    # 获取键的值
    GET key
     
    # 删除键
    DEL key
     
    # 设置键的过期时间
    EXPIRE key 60
     
    # 检查键是否存在
    EXISTS key
     
    # 查找所有符合模式的键
    KEYS *
     
    # 测试与服务器的连接
    PING

以上是Redis的基本概念和常用命令,实际应用中可以根据需求选择合适的数据结构和命令。

2024-09-04



import redis
import time
import uuid
 
class RedisLock:
    def __init__(self, client: redis.Redis, lock_name: str, lock_timeout: int = 10):
        self.client = client
        self.lock_name = lock_name
        self.lock_timeout = lock_timeout
 
    def acquire_lock(self):
        identifier = str(uuid.uuid4())
        end = time.time() + self.lock_timeout
        while time.time() < end:
            if self.client.set(self.lock_name, identifier, ex=self.lock_timeout, nx=True):
                return identifier
            time.sleep(0.001)
        return False
 
    def release_lock(self, identifier):
        pipe = self.client.pipeline(True)
        while True:
            try:
                pipe.watch(self.lock_name)
                if pipe.get(self.lock_name) == identifier:
                    pipe.multi()
                    pipe.delete(self.lock_name)
                    pipe.execute()
                    return True
                pipe.unwatch()
                break
            except redis.exceptions.WatchError:
                pass
        return False
 
# 使用示例
client = redis.Redis(host='localhost', port=6379, db=0)
lock = RedisLock(client, "my_lock")
identifier = lock.acquire_lock()
if identifier:
    try:
        # 在这里执行需要互斥访问的代码
        print("Lock acquired and executed code")
    finally:
        lock.release_lock(identifier)
else:
    print("Could not acquire lock")

这段代码实现了一个基于Redis的分布式锁,使用Python语言和redis-py库。它提供了一种方法来避免多个服务实例同时写入数据或执行特定操作。锁通过一个唯一标识符来释放,确保只有获得锁的服务实例能够执行操作。这是构建微服务时常用的一种技术,以确保数据的一致性和系统的可靠性。

2024-09-04



local resty_lock = require "resty.lock"
local cache_ng = require "resty.openresty-cache-ng"
local cache_zone = ngx.shared.cache_zone
local cache_zone_2 = ngx.shared.cache_zone_2
 
-- 创建锁
local lock = resty_lock:new("lock_zone")
 
-- 尝试获取锁
local elapsed, err = lock:lock("some_key")
if not elapsed then
    ngx.log(ngx.ERR, "failed to lock: ", err)
    return
end
 
-- 尝试从第一级缓存获取数据
local data, err = cache_ng.get(cache_zone, "some_key", {
    ttl = 5, -- 缓存时间
    neg_ttl = 3, -- 负缓存时间
    l1_serializer = "json", -- 缓存数据的序列化方式
    l1_neg_load = function(key) -- 负载函数,当缓存失效时调用
        -- 从数据源获取数据
        local data_source_data = fetch_data_from_source(key)
        if data_source_data then
            -- 将数据存入第二级缓存
            cache_ng.set(cache_zone_2, key, data_source_data, { ttl = 300 })
            -- 设置缓存数据
            return cache_ng.set(cache_zone, key, data_source_data, { ttl = 5 })
        end
        return nil, "data not found"
    end
})
 
-- 如果数据未找到,则释放锁并返回错误信息
if not data then
    lock:unlock()
    ngx.say("data not found")
    return
end
 
-- 输出数据
ngx.say(data)
 
-- 释放锁
lock:unlock()

这段代码展示了如何在OpenResty环境中使用Redis作为分布式缓存,并且实现了多级缓存的策略。它使用了resty.lock库来处理分布式锁,以及resty.openresty-cache-ng库来管理缓存。代码中包含了锁的创建、获取以及释放,同时展示了如何使用负载函数来从数据源获取数据并设置缓存。

2024-09-04

在Linux系统中安装和启动Redis的步骤如下:

  1. 更新包管理器索引并安装Redis:



sudo apt-get update
sudo apt-get install redis-server
  1. 启动Redis服务:



sudo systemctl start redis-server
  1. 确认Redis正在运行:



sudo systemctl status redis-server
  1. 如需开机自启动Redis:



sudo systemctl enable redis-server
  1. 测试Redis是否安装成功:



redis-cli ping

如果返回PONG,则表示Redis已成功安装并可以使用。

以上步骤适用于基于Debian或Ubuntu的Linux发行版。其他Linux发行版可能需要修改安装命令。

2024-09-04

要在Python中获取Redis的所有数据,你可以使用redis包。以下是一个简单的例子,展示了如何连接到Redis服务器并获取所有键及其值。

首先,确保你已经安装了redis包,如果没有安装,可以使用pip安装:




pip install redis

然后,你可以使用以下代码来获取所有Redis键及其值:




import redis
 
# 连接到本地Redis实例
r = redis.Redis(host='localhost', port=6379, db=0)
 
# 获取所有的keys
keys = r.keys('*')
 
# 获取每个key的值
data = {key.decode('utf-8'): r.get(key).decode('utf-8') for key in keys}
 
print(data)

请注意,使用keys('*')可能会对生产环境中的大型数据库性能产生负面影响,因为它会检索所有的键。在生产环境中,考虑使用SCAN迭代键以避免性能问题。

2024-09-04

在上一篇文章中,我们已经讲解了Redis主从复制的基本概念和配置方法。在这篇文章中,我们将深入到Redis主从复制的具体实现细节。

Redis主从复制的实现主要依赖于sync命令和psync命令。

  1. sync命令:当从服务器连接到主服务器时,会发送PSYNC ? -1命令,请求全量复制。主服务器接收到命令后,会开始在后台保存快照(RDB持久化),并在保存过程中继续处理命令。当快照完成后,主服务器会将快照文件发送给从服务器,从服务器接收并加载快照。
  2. psync命令:当从服务器连接已经建立,主服务器会把自己执行的写命令发送给从服务器。当从服务器与主服务器网络连接断开后,会尝试重新连接主服务器,此时会发送PSYNC <runid> <offset>命令,其中<runid>是主服务器的运行ID,<offset>是断开时的复制偏移量。如果<runid>和主服务器的运行ID相同,且主服务器仍然保留了此次断开前的回放缓冲区,则可以使用部分复制功能,只将断开后的命令发送给从服务器。

以下是一个Redis主从复制的配置示例:




# 在主服务器的redis.conf中
bind 0.0.0.0
 
# 在从服务器的redis.conf中
slaveof 主服务器IP 主服务器端口

启动Redis服务并配置主从复制后,可以通过Redis命令info replication查看复制的状态和信息。

注意:在生产环境中,为了数据的安全性和一致性,建议使用Sentinel或者Cluster来管理Redis的高可用性和扩展性。

2024-09-04

在Redis中设置密码,你需要修改Redis配置文件(通常名为redis.conf),找到# requirepass foobared这行配置,去掉前面的#并将foobared替换成你想要设置的密码。

例如,你想要设置密码为myStrongPassword123,你应该这样修改配置文件:




requirepass myStrongPassword123

修改完成后,重启Redis服务以使配置生效。

在Linux中,你可以使用以下命令来重启Redis服务:




sudo service redis-server restart

或者如果你使用的是systemd(大多数现代Linux发行版):




sudo systemctl restart redis.service

设置密码后,客户端连接到Redis服务时需要提供密码。使用redis-cli时,可以使用-a参数:




redis-cli -a myStrongPassword123

在编程时,连接Redis时需要提供密码:




import redis
 
# 创建连接对象
r = redis.StrictRedis(host='localhost', port=6379, password='myStrongPassword123')
 
# 测试连接
r.ping()

请确保在设置密码后,你的应用程序和其他管理工具(如Redis Desktop Manager或其他CLI工具)都使用正确的密码进行连接,否则将无法正常访问Redis服务。