自学内容网 自学内容网

Java-04

目录

Redis如何实现延时队列

延时队列的组成

生产消息

消费消息

实现细节

Redis集群

Integer.compare(a[1], b[1]))与a[1] - b[1])

设计模式​编辑

算法


Redis如何实现延时队列

使用 sortedset ,拿时间戳作为 score ,消息内容作为 key 调用 zadd 来生产消息,消费者用

zrangebyscore 指令获取 N 秒之前的数据轮询进行处理。

延时队列的组成

  • Sorted Set:在Redis中,Sorted Set是一个集合,其中的每个元素都关联一个分数(score),这使得集合中的元素能够根据分数进行排序。

生产消息

  1. 选择Sorted Set
    • 选择一个或多个Sorted Set来作为延时队列的数据结构。
  1. 定义分数
    • 分数(score)通常设置为消息需要被处理的时间戳。例如,如果想要消息在5秒后被处理,那么分数就是当前时间戳加上5秒。

添加消息

    • 使用ZADD命令将消息添加到Sorted Set中。消息内容作为Sorted Set的成员(member),而消息需要被处理的时间戳作为分数。
  1. shell复制
ZADD queue_name timestamp message
    • queue_name是Sorted Set的键名。
    • timestamp是消息应该被处理的时间戳。
    • message是消息的内容。

消费消息

  1. 轮询检查
    • 消费者需要定期检查Sorted Set,以确定是否有消息已经到了处理时间。

获取可处理的消息

    • 使用ZRANGEBYSCORE命令获取所有分数小于或等于当前时间戳的成员。
  1. shell复制
ZRANGEBYSCORE queue_name -inf $(current_timestamp)
    • -inf表示分数的下界,这里表示从最小分数开始。
    • $(current_timestamp)是当前时间戳,表示分数的上界。
  1. 处理消息
    • ZRANGEBYSCORE返回的列表中,取出每个消息进行处理。

移除已处理的消息

    • 处理完消息后,使用ZREM命令从Sorted Set中移除该消息。
  1. shell复制
ZREM queue_name message
    • message是已经处理完毕的消息内容。

实现细节

  • 定时轮询:消费者可以使用定时任务(如cron job)或循环逻辑来定期执行ZRANGEBYSCORE命令。
  • 多消费者:如果有多个消费者,可以使用分布式锁或其他同步机制来避免消息被重复处理。
  • 性能考虑ZRANGEBYSCOREZREM命令在处理大量数据时可能会影响性能,因此需要合理设计消息的大小和处理频率。
  • 消息持久化:Redis的Sorted Set支持持久化,可以确保即使Redis重启,消息也不会丢失。

Redis集群

Redis集群是一个提供在多个Redis节点之间进行数据分片(sharding)和复制的分布式系统。


Redis集群是一种分布式Redis实现,它可以将数据分布在多个Redis实例上,以提高Redis的性能和可扩展性。Redis集群通过分片(sharding)技术将数据分散存储在不同的Redis实例上,每个实例负责存储数据的一部分。Redis集群由多个主节点和从节点组成,主节点负责处理客户端的写入和读取请求,从节点则负责同步主节点的数据。

  1. 分片(Sharding):Redis集群将数据分片存储在不同的Redis实例上,每个实例存储数据的一部分。这样可以将数据分散到多个节点上,提高Redis的性能和可扩展性。
  2. 主从复制(Master-Slave Replication):Redis集群中的每个主节点都有一个或多个从节点。主节点负责处理客户端的写入和读取请求,并将数据同步到从节点。从节点则负责接收主节点的数据,并可以在主节点故障时提升为主节点。
  3. 故障转移(Failover):当主节点发生故障时,从节点可以提升为主节点,并继续处理客户端的请求。其他从节点会继续同步提升后的主节点。
  4. 自动分片和扩展:Redis集群可以自动进行分片和扩展,无需停机。当添加新节点时,Redis集群会自动将数据分片到新节点上,以提高性能和可扩展性。
  5. 高可用性(High Availability):Redis集群具有高可用性,即使某些节点发生故障,集群仍然可以继续处理客户端的请求。
  6. 一致性(Consistency):Redis集群提供了强一致性保证,所有写入操作都保证在主节点和从节点之间同步。
  7. 多线程和网络优化:Redis集群使用多线程和网络优化技术,以提高性能和响应速度。

在Redis集群中,Redis实例可以分为主节点(Master)和从节点(Slave)。

redis集群模式:

Redis集群模式主要包括以下几种:

  1. 主从复制(Master-Slave Replication)
    • 在主从复制模式中,一个主节点(Master)负责处理写入和读取请求,并生成内存快照和命令日志。
    • 多个从节点(Slaves)从主节点同步数据,并保持与主节点的数据一致性。
    • 主从复制模式提高了Redis的可用性和故障转移能力,同时也支持读写分离,提高了读取性能。
  1. 哨兵(Sentinel)
    • 哨兵是一个分布式系统,用于监控主从复制模式的Redis集群。
    • 哨兵可以监控主节点的运行状态,并在主节点故障时选举出一个从节点作为新的主节点。
    • 哨兵模式确保了Redis集群的高可用性,即使主节点发生故障,集群仍然可以继续处理客户端的请求。
  1. Redis Cluster
    • Redis Cluster是Redis官方提供的分布式Redis实现,支持自动分片和故障转移。
    • 在Redis Cluster模式中,数据被分片存储在多个Redis实例上,每个实例负责存储数据的一部分。
    • Redis Cluster支持自动扩展和负载均衡,可以动态地添加或移除节点,以满足不断增长的业务需求。
    • Redis Cluster提供了强一致性保证,所有写入操作都保证在主节点和从节点之间同步。
  1. Redis-Cluster-Sentinel
    • Redis-Cluster-Sentinel结合了Redis Cluster和哨兵的功能。
    • 在Redis-Cluster-Sentinel模式中,哨兵用于监控Redis Cluster的运行状态,并在主节点故障时选举出一个从节点作为新的主节点。
    • Redis-Cluster-Sentinel模式确保了Redis Cluster的高可用性和数据一致性。

读写分离:

主从复制模式(Master-Slave Replication)通过将Redis实例分为主节点(Master)和从节点(Slave)来实现读写分离,从而提高系统的可用性和性能。

主从复制模式支持读写分离的原理:

  1. 主节点(Master)
    • 负责处理写入请求,即客户端的写入操作(SET、DEL等)。
    • 生成内存快照(RDB)和记录写入命令(AOF),用于从节点的同步。
    • 主节点会定期将快照和增量命令发送给从节点。
  1. 从节点(Slave)
    • 负责处理读取请求,即客户端的读取操作(GET、KEYS等)。
    • 从节点不会处理写入请求,它们只会执行从主节点接收到的命令。
    • 从节点会定期从主节点接收快照和增量命令,以保持与主节点的数据一致性。

通过这种模式,客户端可以将读取请求发送给从节点,将写入请求发送给主节点。由于从节点只负责处理读取请求,它们通常会部署在性能较低的节点上,而主节点则处理写入请求,并负责数据的完整性和一致性。

主从复制和哨兵模式可以一起使用,以实现更高级的可用性和故障转移能力。例如,一个Redis集群可以包含多个主节点和从节点,每个主节点都配备有哨兵,以确保在任何主节点故障时,集群都可以继续工作。

Redis使用哈希槽:

在Redis集群模式中,数据被分片存储在不同的Redis实例上,每个实例负责存储数据的一部分。为了实现这种分片存储,Redis集群使用了哈希槽(Hash Slot)的概念。

哈希槽是Redis集群中的一个抽象概念,用于将数据分布到不同的节点上。每个哈希槽负责存储一个哈希值范围内的所有数据。Redis集群总共有16384个哈希槽,这意味着每个哈希槽负责处理大约65536个不同的键(因为一个键的哈希值范围是0到65535)。

当一个键被添加到Redis集群时,首先需要计算这个键的CRC16哈希值。CRC16是一种循环冗余校验(CRC)算法,用于生成一个16位的校验和,这个校验和可以用来确定数据传输过程中是否有错误发生。

在Redis集群中,计算给定密钥的哈希槽的步骤如下:

  1. 对密钥计算CRC16哈希值。
  2. 将得到的16位哈希值对16384取模。
  3. 得到的模数就是该键所属的哈希槽的编号。
  4. 将键存储在编号为该模数的哈希槽对应的主节点上。

通过这种方式,Redis集群可以自动将数据分散存储到不同的节点上,每个节点负责管理一部分哈希槽,从而实现数据的分片存储和负载均衡。

Integer.compare(a[1], b[1]))与a[1] - b[1])

在Java中,Arrays.sort 方法可以接受一个比较器(Comparator),用于定义数组元素的排序规则。两种写法都是用来对数组进行排序的,但是它们在某些情况下的行为可能会有所不同。

  1. Arrays.sort(points, (a, b) -> Integer.compare(a[1], b[1]))
    • 这里使用的是 Integer.compare 方法,它是一个静态方法,用于比较两个 int 值。如果 a[1] 小于 b[1],它返回一个负数;如果 a[1] 等于 b[1],它返回 0;如果 a[1] 大于 b[1],它返回一个正数。这种写法是类型安全的,因为它明确地处理了 int 值的比较,并且可以正确处理 Integer.MIN_VALUE 的情况。
  1. Arrays.sort(points, (a, b) -> a[1] - b[1])
    • 这里直接返回两个 int 值相减的结果。这种写法在大多数情况下工作正常,但是如果 a[1]b[1] 的值接近 Integer.MIN_VALUE,相减的结果可能会超出 int 的范围,导致 Integer.MIN_VALUE 被错误地转换为一个正数,从而破坏排序。这是因为 int 类型的减法可能会产生溢出,而 Integer.compare 会避免这种情况。

总结来说,Integer.compare 是一个更安全的选择,因为它可以正确处理所有 int 值的比较,包括边界情况,而直接相减可能会导致整数溢出的问题。在实际编程中,推荐使用 Integer.compare 来避免潜在的溢出问题。

设计模式

算法

2.小红书推荐系统

小红书有一个推荐系统,可以根据用户搜索的关键词推荐用户希望获取的内容。
现在给定小红的搜索记录(记录为分词后的结果),我们认为当一个单词出现的次数不少于3次时,该单词为“用户期望搜索的单词”,即称为关键词。请你根据小红的记录,输出小红的用户画像对应的所有关键词。
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 256M,其他语言512M
输入描述:
一行字符串,仅由小写字母和空格组成。代表小红的搜索记录。
字符串长度不超过100000。
输出描述:
小红所有的关键词。每行输入一个。你需要按照搜索频次从高到低输出。频次相同的,你需要按字典序升序输出。
示例1
输入例子:
kou red game red ok who game red karaoke yukari kou red red nani kou can koukou ongakugame game
输出例子:
red
game
kou
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        // 读取输入字符串
        String input = sc.nextLine();
        
        // 使用 HashMap 统计单词频率
        Map<String, Integer> frequency = new HashMap<>();
        String[] words = input.split(" ");
        
        // 统计每个单词的频率
        for (String word : words) {
            frequency.put(word, frequency.getOrDefault(word, 0) + 1);
        }
        
        // 筛选出频率大于等于3的关键词
        List<String> keywords = new ArrayList<>();
        for (Map.Entry<String, Integer> entry : frequency.entrySet()) {
            if (entry.getValue() >= 3) {
                keywords.add(entry.getKey());
            }
        }
        
        // 按照频率降序和字典序升序排序
        keywords.sort((a, b) -> {
            int freqCompare = frequency.get(b).compareTo(frequency.get(a));
            if (freqCompare != 0) {
                return freqCompare; // 按频率降序
            }
            return a.compareTo(b); // 按字典序升序
        });
        
        // 输出结果
        for (String keyword : keywords) {
            System.out.println(keyword);
        }
        
        sc.close();
    }
}

近日总结:

身体不舒服,好烦

 


原文地址:https://blog.csdn.net/Hubery_sky/article/details/143836643

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!