2024-09-04



import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import redis.clients.jedis.Jedis;
 
public class RedisCaffeineCache {
    private final Jedis jedis;
    private final Cache<String, String> caffeineCache;
 
    public RedisCaffeineCache(Jedis jedis) {
        this.jedis = jedis;
        this.caffeineCache = Caffeine.newBuilder()
                .maximumSize(10_000)
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .build();
    }
 
    public String get(String key) {
        // 先从Caffeine缓存获取
        String value = caffeineCache.getIfPresent(key);
        if (value == null) {
            // Caffeine缓存未命中,从Redis获取
            value = jedis.get(key);
            if (value != null) {
                // 将获取的数据存入Caffeine缓存
                caffeineCache.put(key, value);
            }
        }
        return value;
    }
 
    public void put(String key, String value) {
        // 直接写入Redis
        jedis.set(key, value);
        // 同时写入Caffeine缓存
        caffeineCache.put(key, value);
    }
 
    public void evict(String key) {
        // 从Redis删除
        jedis.del(key);
        // 从Caffeine缓存删除
        caffeineCache.invalidate(key);
    }
}

这个示例代码展示了如何使用Redis和Caffeine实现两级缓存。get方法首先检查Caffeine缓存,如果未命中,再去Redis查询。put方法直接将数据存入Redis,并同时更新Caffeine缓存。evict方法会从Redis和Caffeine缓存中删除一个键值对。

2024-09-04

Lettuce 是一个高级 Redis 客户端,用于线程安全的、可编程的、异步和同步的 Redis 连接。它提供了一个清晰的API,并且可以用于构建非块的、高性能的应用程序。

Lettuce 的主要特性包括:

  1. 同步和异步的连接以及编程模型。
  2. 高级的 Redis 集群支持,包括自动发现和完整的集群通信。
  3. 高度可定制的超时和重试机制。
  4. 可以使用 Netty 线程池或者 Reactor 线程模型。
  5. 完整的 Redis 命令支持和实现。
  6. 可以使用 Redis 的新特性,比如 ACLLOGSTORE。

以下是一个使用 Lettuce 连接 Redis 并执行基本命令的示例代码:




import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
 
public class LettuceExample {
    public static void main(String[] args) {
        // 连接到 Redis 服务器
        RedisClient redisClient = RedisClient.create("redis://localhost");
        StatefulRedisConnection<String, String> connection = redisClient.connect();
        RedisCommands<String, String> syncCommands = connection.sync();
 
        // 设置键值对
        syncCommands.set("key", "value");
 
        // 获取键对应的值
        String value = syncCommands.get("key");
        System.out.println("key 对应的值是: " + value);
 
        // 关闭连接
        connection.close();
        redisClient.shutdown();
    }
}

在这个例子中,我们创建了一个 RedisClient 实例,然后使用它连接到本地的 Redis 服务器。接着,我们通过连接获取了同步命令接口 RedisCommands,并使用它来执行 set 和 get 命令。最后,我们关闭了连接和客户端,释放资源。

2024-09-04

在Redis中实现分布式锁通常使用SETNX命令(或在Redis 2.6.12以上版本中使用SET key value EX max-lock-time NX命令,这样可以一次性设置并加锁,避免了两条命令之间客户端被阻塞的问题)。以下是一个使用SET命令实现分布式锁的Python示例:




import redis
import time
import uuid
 
def acquire_lock(conn, lock_name, acquire_timeout=10, lock_timeout=10):
    identifier = str(uuid.uuid4())  # 生成一个唯一的ID
    end = time.time() + acquire_timeout
 
    while time.time() < end:
        if conn.set(lock_name, identifier, ex=lock_timeout, nx=True):
            return identifier  # 加锁成功,返回唯一标识
        time.sleep(0.001)
 
    return False  # 在规定时间内未能获得锁
 
def release_lock(conn, lock_name, identifier):
    pipe = conn.pipeline(True)
    while True:
        try:
            pipe.watch(lock_name)
            if pipe.get(lock_name) == identifier:
                pipe.multi()
                pipe.delete(lock_name)
                pipe.execute()
                return True
            pipe.unwatch()
            break
        except redis.exceptions.WatchError:
            pass
    return False  # 释放锁失败,可能由于标识符不匹配
 
# 使用示例
client = redis.StrictRedis(host='localhost', port=6379, db=0)
lock_name = "my_lock"
lock_identifier = acquire_lock(client, lock_name)
if lock_identifier:
    try:
        # 在这个区块内执行需要互斥的操作
        print("Lock acquired")
    finally:
        if not release_lock(client, lock_name, lock_identifier):
            print("Failed to release lock")
else:
    print("Failed to acquire lock")

这段代码中,acquire_lock函数尝试获取一个分布式锁,如果在指定时间内成功,它会返回一个唯一标识符;release_lock函数尝试释放由该唯一标识符持有的锁。如果标识符匹配并成功释放锁,函数返回True;如果标识符不匹配或者释放锁时发生错误,函数返回False。在实际应用中,你需要确保在获取锁之后及异常发生时释放锁,以避免死锁情况的发生。

2024-09-04



#!/bin/bash
# 快速编译安装 PHP 8.3.3 并配置常用扩展:redis、zip、igbinary、memcached
 
# 定义 PHP 版本和源代码目录变量
PHP_VERSION="php-8.3.3"
SRC_DIR="/usr/local/src"
 
# 安装依赖库
yum install -y epel-release \
    && yum install -y \
    gcc \
    gcc-c++ \
    make \
    zlib-devel \
    openssl-devel \
    libxml2-devel \
    bzip2-devel \
    curl-devel \
    freetype-devel \
    gmp-devel \
    libmcrypt-devel \
    libpng-devel \
    libjpeg-turbo-devel \
    libzip-devel \
    recode-devel \
    libicu-devel \
    libxslt-devel \
    systemd-devel \
    pcre-devel \
    sqlite-devel \
    oniguruma-devel \
    libwebp-devel \
    libc-client-devel \
    openldap-devel
 
# 下载 PHP 源代码
cd $SRC_DIR \
    && wget "https://www.php.net/distributions/$PHP_VERSION.tar.gz" \
    && tar -zxvf "$PHP_VERSION.tar.gz" \
    && cd "$PHP_VERSION"
 
# 配置编译选项
./configure \
    --prefix=/usr/local/php8 \
    --with-curl \
    --with-freetype \
    --with-gd \
    --with-gettext \
    --with-iconv-dir \
    --with-kerberos \
    --with-libdir=lib64 \
    --with-libxml-dir \
    --with-mysqli \
    --with-openssl \
    --with-pcre-regex \
    --with-pear \
    --with-pdo-mysql \
    --with-pdo-sqlite \
    --with-pear \
    --with-png-dir \
    --with-xmlrpc \
    --with-xsl \
    --with-zlib \
    --enable-bcmath \
    --enable-fpm \
    --enable-gd-jis-conv \
    --enable-inline-optimization \
    --enable-mbregex \
    --enable-mbstring \
    --enable-opcache \
    --enable-pcntl \
    --enable-shmop \
    --enable-soap \
    --enable-sockets \
    --enable-sysvsem \
    --enable-xml \
    --enable-zip \
    --disable-debug \
    --disable-rpath \
    --disable-fileinfo
 
# 编译并安装 PHP
make -j$(nproc) && make install
 
# 配置 PHP
cp php.ini-development /usr/local/php8/lib/php.ini
cp /usr/local/php8/etc/php-fpm.conf.default /usr/local/php8/etc/php-fpm.conf
cp /usr/local/php8/etc/php-fpm.d/www.conf.default /usr/local/php8/etc/php-fpm.d/www.conf
 
# 下载并编译安装 PHP 扩展
for extension in redis zip igbinary memcached; do
    cd $SRC_DIR \
    && git clone "https://github.com/php/$extension-ds.git" \
    && cd "$extension-ds" \
    && phpize \
    && ./configure --with-php-config=/usr/local/php8/bin/php-config \
    && make && make install
done
 
# 配置 PHP 加载扩展
extension_dir="/usr/local/php8/lib/php/extensions/no-debug-non-zts-20210902"
for extension in redis zip igbinary memcached; do
    echo "extension=$
2024-09-04

Redis的持久化主要有两种方式:RDB(Redis DataBase)和AOF(Append Only File)。

  1. RDB:定时将内存中的数据快照保存到磁盘的一个压缩二进制文件中。可以配置定时任务来控制快照的频率。



# 配置保存点(在redis.conf中设置)
save 900 1      # 900秒内至少1个键被修改则保存
save 300 10     # 300秒内至少10个键被修改则保存
save 60 10000   # 60秒内至少10000个键被修改则保存
  1. AOF:每个写命令都通过append操作保存到文件中。在服务重启时,通过重放这些命令来恢复数据。



# 配置AOF持久化(在redis.conf中设置)
appendonly yes       # 开启AOF持久化
appendfilename "appendonly.aof"  # AOF文件名
# appendfsync always   # 每个命令都同步,最慢但最安全
# appendfsync everysec # 每秒同步一次,折衷方案
# appendfsync no       # 由操作系统决定何时同步

在实际应用中,可以两者结合使用,或者只使用其中一种。根据需求和性能考量,选择合适的持久化策略。

2024-09-04

这个错误信息表明你尝试与远程主机通信时,远程主机上的Redis服务强制关闭了一个现有的连接。这种情况通常发生在Redis服务器遇到问题,如配置错误、内存不足、达到连接数限制或其他内部错误时。

解决方法:

  1. 检查远程Redis服务器的日志文件,以查找为何关闭连接的具体原因。
  2. 确认Redis配置文件(通常是redis.conf)中的设置是否正确,如最大连接数、内存限制等。
  3. 如果是因为连接数限制,可以在Redis配置文件中增加maxclients的值。
  4. 确保远程Redis服务器有足够的内存和处理能力来处理请求。
  5. 如果问题依然存在,可以尝试重启Redis服务。
  6. 如果你是远程服务器的管理员,可以使用工具如htoptop来监控Redis进程的资源使用情况。
  7. 如果你无法解决问题,可以联系远程服务器的管理员或技术支持。

请注意,解决方案取决于具体的错误原因,可能需要对Redis配置进行调整或进行更深入的故障排除。

2024-09-04

在Redis中,可以使用TTL命令来查看一个key的过期时间。在Spring框架中,如果你使用的是RedisTemplateStringRedisTemplate,你可以通过以下方式来获取key的过期时间:




import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
 
import java.util.concurrent.TimeUnit;
 
@Component
public class RedisService {
 
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
 
    public Long getExpire(String key) {
        return stringRedisTemplate.getExpire(key, TimeUnit.SECONDS);
    }
}

在上面的代码中,getExpire方法接收一个key作为参数,并返回该key的剩余过期时间(单位为秒)。如果key不存在或没有设置过期时间,则返回值为null。如果你想获取其他时间单位的剩余时间,可以在getExpire方法中指定不同的TimeUnit

2024-09-04

Redis 支持三种集群模式:主从模式、哨兵模式和分片集群模式。

  1. 主从模式(Master-Slave Mode)

    主从模式是最简单的Redis集群模式。在这种模式下,有一个主节点和一个或多个从节点,主节点用于处理写操作,从节点用于处理读操作。数据是以快照的方式从主节点同步到从节点。




# 配置主节点
redis-server --port 6379

# 配置从节点
redis-server --port 6380 --slaveof 127.0.0.1 6379
  1. 哨兵模式(Sentinel Mode)

    哨兵模式是主从模式的升级版。它通过哨兵进程监控主节点的健康状态,并在主节点宕机时自动进行故障转移。




# 启动哨兵进程
redis-sentinel /path/to/your/sentinel.conf
  1. 分片集群模式(Sharded Cluster Mode)

    分片集群模式是最复杂的Redis集群模式,它通过分片机制将数据分布在多个节点上。




# 配置分片集群
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 --cluster-replicas 1

以上是三种Redis集群模式的简要说明和配置示例。在实际应用中,你需要根据具体需求选择合适的集群模式,并进行相应的配置和管理。

2024-09-04

创建一个Docker部署的Spring Cloud微服务、MySQL 8、TDengine 3.0、Redis 6和Nginx 1的环境,你可以使用Docker Compose来简化这个过程。以下是一个基本的docker-compose.yml文件示例,它定义了所需的服务:




version: '3.8'
services:
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: mydb
    ports:
      - "3306:3306"
 
  redis:
    image: redis:6.0
    ports:
      - "6379:6379"
 
  taos:
    image: tdengine/tdengine:3.0.0.0
    ports:
      - "6030-6040:6030-6040"
      - "1883-1884:1883-1884"
      - "6030-6040:6030-6040/udp"
      - "1883-1884:1883-1884/udp"
 
  eureka:
    image: openjdk:8-jdk
    command: ["java", "-jar", "eureka.jar"]
    volumes:
      - ./eureka.jar:/eureka.jar
    depends_on:
      - taos
      - mysql
      - redis
    ports:
      - "8761:8761"
 
  nginx:
    image: nginx:1
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    ports:
      - "80:80"
    depends_on:
      - eureka

在这个例子中,每个服务都被定义为一个Docker容器,并且指定了相应的镜像、环境变量、卷挂载和端口映射。depends_on字段确保了容器按正确的顺序启动,并且它们之间可以相互通信。

请注意,这只是一个基础示例,你需要根据自己的需求调整配置,例如,指定正确的jar文件路径、配置文件路径和端口映射。

要运行此环境,请确保你有一个docker-compose.yml文件,并在包含此文件的目录中运行以下命令:




docker-compose up -d

这将在后台启动所有服务。如果你还没有安装Docker Compose,你可以通过运行sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose来安装它,并通过运行sudo chmod +x /usr/local/bin/docker-compose来使其可执行。

2024-09-04



import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
 
import java.util.Set;
 
@Service
public class RankingService {
 
    @Autowired
    private StringRedisTemplate redisTemplate;
 
    // 获取排行榜前N名的用户
    public Set<ZSetOperations.TypedTuple<String>> getTopNUsers(String rankKey, int N) {
        return redisTemplate.opsForZSet().reverseRangeByScoreWithScores(rankKey, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 0, N - 1);
    }
 
    // 更新用户分数
    public void updateUserScore(String rankKey, String userId, double newScore) {
        redisTemplate.opsForZSet().add(rankKey, userId, newScore);
    }
 
    // 删除用户分数
    public void removeUser(String rankKey, String userId) {
        redisTemplate.opsForZSet().remove(rankKey, userId);
    }
}

这段代码提供了一个简单的服务类,用于与Redis Zset有序集合交互,实现排行榜功能。它展示了如何获取前N名用户,如何更新用户的分数,以及如何删除用户。这个例子是基于Spring Data Redis的StringRedisTemplate,它提供了操作Redis的方法。