每日面试题Day02

57 阅读7分钟

跟孙哥学java

孙哥主页

Redis有什么数据结构,根据什么来选择数据结构

Redis支持多种数据结构,每种结构都适用于不同类型的问题和用例。以下是一些常见的Redis数据结构以及它们的主要特点:

  1. 字符串 (String):
  • 特点:简单的键值对存储。
  • 适用场景:存储简单的数值、文本或二进制数据。
  1. 哈希表 (Hash):
  • 特点:类似于内部嵌套的键值对结构,适用于存储对象。
  • 适用场景:存储、检索、更新对象属性。
  1. 列表 (List):
  • 特点:有序集合,支持从两端插入和删除元素。
  • 适用场景:队列、栈、实时消息发布与订阅。
  1. 集合 (Set):
  • 特点:无序集合,不允许重复元素。
  • 适用场景:存储唯一值,集合运算(并集、交集等)。
  1. 有序集合 (Sorted Set):
  • 特点:有序集合,每个成员都关联一个分数(score)。
  • 适用场景:排行榜、按分数范围获取成员。
  1. 位图 (Bitmap):
  • 特点:存储位信息,支持位操作。
  • 适用场景:标记某个元素是否存在,例如用户在线状态。
  1. HyperLogLog:
  • 特点:用于估计集合的基数(不重复元素的数量)。
  • 适用场景:大规模数据的基数统计。

选择合适的数据结构通常取决于你的具体用例和要解决的问题。以下是一些选择数据结构的考虑因素:

  • 访问模式: 考虑你的数据如何被访问和使用。不同的数据结构适用于不同的访问模式,例如随机访问、顺序访问、范围查询等。
  • 功能需求: 考虑你的应用需要什么功能,例如是否需要支持排序、去重、事务等功能。
  • 性能要求: 不同的数据结构在执行不同操作时有不同的时间复杂度。选择适当的数据结构可以提高性能。
  • 内存占用: 不同的数据结构在存储相同数据量时占用的内存可能有差异,考虑你的内存约束。
  • 复杂性: 有时候,为了简化问题的处理,选择简单的数据结构可能更合适。

Redis中有什么锁在 Redis 中,实现分布式锁通常有两种主要方式:基于 SETNX 和基于 Redlock 算法。

  1. 基于 SETNX 的简单分布式锁:
  • 使用 SETNX(SET if Not eXists)指令,该指令在键不存在时设置键的值。
  • 利用该指令,可以通过设置一个键作为锁,来实现简单的分布式锁。
  • 缺点:可能存在死锁和竞态条件,需要谨慎处理。
import redis.clients.jedis.Jedis;

public class SimpleDistributedLock {

    public boolean acquireLock(Jedis jedis, String lockKey, String lockValue, int expireTime) {
        String result = jedis.set(lockKey, lockValue, "NX", "EX", expireTime);
        return "OK".equals(result);
    }

    public void releaseLock(Jedis jedis, String lockKey) {
        jedis.del(lockKey);
    }
}

  1. 基于 Redlock 算法的分布式锁:
  • Redlock 是由 Redis 官方提出的一种分布式锁算法,通过在多个 Redis 实例上协作来实现更强大的锁。
  • Redlock 算法要求在多个 Redis 实例上获取锁,并在释放锁时验证锁的持有权。
  • 缺点:相对较复杂,需要仔细考虑网络分区等问题。

以下是 Redlock 算法的简化示例(实际应用需要更复杂的实现):

import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;

import java.util.List;

public class Redlock {

    private List<Jedis> jedisNodes;

    public Redlock(List<Jedis> jedisNodes) {
        this.jedisNodes = jedisNodes;
    }

    public boolean acquireRedlock(String lockKey, String lockValue, int expireTime, int retryTimes) {
        boolean lockAcquired = false;
        int retryCount = 0;

        while (!lockAcquired && retryCount < retryTimes) {
            lockAcquired = true;
            int lockInstances = 0;

            try {
                for (Jedis jedis : jedisNodes) {
                    SetParams setParams = new SetParams().nx().ex(expireTime);
                    String result = jedis.set(lockKey, lockValue, setParams);
                    if ("OK".equals(result)) {
                        lockInstances++;
                    }
                }
            } catch (Exception e) {
                lockAcquired = false;
            }

            if (lockAcquired && lockInstances < jedisNodes.size() / 2) {
                // 如果锁在大多数实例上都获得了,否则认为锁未获得
                lockAcquired = false;
            }

            if (!lockAcquired) {
                // 未获得锁,等待一段时间后进行重试
                try {
                    Thread.sleep((long) (Math.random() * 100 + 100));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                retryCount++;
            }
        }

        return lockAcquired;
    }

    public void releaseRedlock(String lockKey) {
        for (Jedis jedis : jedisNodes) {
            jedis.del(lockKey);
        }
    }
}

选择哪种分布式锁取决于你的应用需求和复杂性要求。对于简单的应用,基于 SETNX 的方式可能已经足够;对于需要更强大锁特性和对抗网络分区等问题的场景,考虑使用 Redlock 算法。需要注意的是,Redlock 算法的使用需要慎重,因为网络分区等异常情况可能导致锁失效。

Mysql的存储引擎有什么,其索引的数据结构是什么?

MySQL支持多种存储引擎,每种引擎都有其自己的特点和适用场景。以下是一些常见的 MySQL 存储引擎:

  1. InnoDB:
  • 事务安全存储引擎,支持事务、外键、行级锁等。
  • 默认的存储引擎,适用于大多数应用场景。
  • B+树索引结构。
  1. MyISAM:
  • 不支持事务和行级锁,但提供了高性能的读操作。
  • 适用于读密集、写少的应用。
  • B树索引结构。
  1. Memory (Heap):
  • 将表存储在内存中,适用于对性能要求较高的临时表。
  • 不支持持久化。
  • 哈希索引结构。

每种存储引擎的索引数据结构不同,主要有 B树、B+树、哈希、Fractal Tree 等。以下是常见存储引擎的索引数据结构:

  • B树(Binary Tree):
    • MyISAM 使用 B树索引。
    • B树是一种平衡的树结构,对于范围查询效果较好。
  • B+树(Binary Plus Tree):
    • InnoDB 使用 B+树索引。
    • B+树是在B树的基础上演变而来,具有更好的范围查询性能。
  • 哈希索引:
    • Memory 和 NDB Cluster 存储引擎使用哈希索引。
    • 哈希索引适用于等值查询,但不支持范围查询。

不同的索引结构适用于不同的查询模式和性能需求。在选择存储引擎和创建索引时,需要考虑应用的读写模式、事务要求以及数据量等因素。

Redis存储数据有没有限制?Redis 存储数据的大小是有限制的,主要受到以下几个方面的限制:

  1. 内存限制: Redis 将所有数据存储在内存中,因此实际可用内存是主要的限制因素。如果 Redis 的数据量超过了可用内存大小,可能导致系统性能下降或者数据无法继续存储。
  2. 单个键值对大小限制: 单个键值对的大小不能超过 Redis 的配置参数 maxmemory,这个参数默认是 0,表示不限制。如果设置了 maxmemory,当达到该限制时,Redis 会根据一定的淘汰策略删除部分数据以腾出空间。
  3. 字符串类型大小限制: 单个字符串类型的值最大可以达到 512MB。如果需要存储更大的数据,可以考虑使用 Redis 的其他数据结构,如分块字符串(chunked string)或者分布式文件存储等方式。
  4. 列表、集合、有序集合等数据结构的元素数量限制: 每个 Redis 数据结构的元素数量是有限制的,具体限制取决于数据结构的类型。例如,列表的最大长度是 2^32 - 1,集合和有序集合的最大元素数量也是 2^32 - 1。

Linux查看有多少个线程在运行的命令?在Linux中,你可以使用以下命令来查看有多少个线程在运行:

ps -eLf | wc -l

这个命令的含义是列出所有进程的详细信息,并使用管道将结果传递给 wc -l 命令,以计算行数。每个进程都对应一个线程,因此这个命令的输出行数即为正在运行的线程数。

另一种方法是使用下面的命令:

top

top 命令的界面中,你可以看到系统的实时性能数据,包括线程数。在任务栏上,你会看到类似 "Tasks" 的信息,其中包含了线程数的统计信息。按下 q 键退出 top 命令。

Linux有多少个端口,一个ip最多连接多少个端口?