### Redis与Memcached的主要区别 #### 数据结构支持 - **Redis**:支持多种数据结构,如字符串(Strings)、散列(Hashes)、列表(Lists)、集合(Sets)、有序集合(Sorted Sets)等,这使得Redis适用于更广泛的场景。 - **Memcached**:主要支持键值对(KV)存储,适用于简单的缓存需求。 #### 持久化与容灾 - **Redis**:提供多种持久化机制,包括RDB快照和AOF(Append Only File)两种方式,确保数据在断电或其他故障情况下的安全性。 - **Memcached**:不支持数据的持久化,主要用于临时缓存,一旦服务器重启或宕机,所有数据都将丢失。 #### 虚拟内存与扩展性 - **Redis**:支持虚拟内存特性,能够在内存不足时将部分冷数据转移到磁盘,提高系统整体的存储容量。 - **Memcached**:通常运行在纯内存环境中,不支持虚拟内存功能。 #### 消息队列支持 - **Redis**:可以利用其发布/订阅(Pub/Sub)功能作为消息中间件,构建消息队列系统。 - **Memcached**:不具备消息队列功能。 #### 并发性能 - 在高并发场景下,尽管**Memcached**采用了多线程模型,但引入了缓存一致性和锁机制,这些机制在提高并发安全性的同时也带来了额外的性能开销。 - 相比之下,**Redis**采用单线程模型处理所有客户端请求,避免了多线程间的数据竞争问题,从而在某些情况下能够展现出更高的性能。 ### Redis 主从复制机制 - **快照传输**:主节点将当前内存中的数据做一份完整的快照,并将其发送给从节点。从节点接收到快照后,将其加载到自己的内存中,完成数据的初始化同步。 - **增量同步**:主从同步完成后,主节点会将后续的所有写操作记录为类似于MySQL的二进制日志(Binary Log),并将这些日志发送给从节点。从节点根据接收到的日志进行重放,保持与主节点数据的一致性。 ### Redis 集群模式 - **客户端分片(Client-side Sharding)**:应用程序负责将数据分片到不同的Redis实例上。 - **基于代理的分片(Proxy-based Sharding)**:通过中间层代理软件如Twemproxy或Codis等来实现数据的分片。 - **Redis-Cluster**:内置了自动分片功能,每个集群包含多个节点,数据被均匀分布到这些节点上,用户无需关心具体的数据分片位置。 #### 分片原理 - **虚拟槽(Virtual Slots)**:每个Redis-Cluster包含16384个虚拟槽,这些槽被分配给各个主节点。每个键(Key)通过哈希运算映射到特定的槽上,进而确定该键所在的节点。 - **节点间通信**:节点之间通过gossip协议相互交换状态信息,包括节点的健康状态、槽的归属等信息,以保证集群的一致性。 ### 分布式锁的实现 #### Redis 实现 - **SetNX 命令**:尝试为锁对象设置一个值,如果成功则表示获取到了锁。 - **GetSet 命令**:用于释放锁,通过比较旧值和当前值是否一致来判断是否持有锁。 - **超时机制**:为锁设置一个超时时间,防止死锁。 #### ZooKeeper 实现 - **顺序节点**:客户端在ZooKeeper上创建一个具有唯一ID的临时顺序节点。 - **最小节点**:如果客户端创建的节点ID是最小的,则该客户端获得锁;否则监听比自身节点ID小的最大节点。 - **锁释放**:客户端处理完业务逻辑后删除自己的节点,释放锁。 #### 区别 - **性能**:ZooKeeper相比Redis实现的分布式锁性能较差,开销更大。 - **实现复杂度**:ZooKeeper实现起来相对简单,但需要依赖额外的服务。 ### Redis 持久化机制 #### RDB (Redis Database) - **快照保存**:定期生成数据集的时间点快照。 - **优点**:数据恢复速度快。 - **缺点**:可能会导致数据丢失。 #### AOF (Append Only File) - **日志记录**:将每次执行的命令追加到文件中。 - **优点**:数据丢失的可能性极低。 - **缺点**:文件体积大,恢复速度较慢。 ### Redis 过期策略 #### 定时过期 - 对于每一个设置了过期时间的键,Redis会在键的过期时间到达时立即删除该键。 #### 惰性过期 - 只有当尝试访问一个已过期的键时,Redis才会检查并删除它。 #### 定期过期 - 结合了定时过期和惰性过期的优点,通过定期检查一部分随机选择的键来检测并删除过期键。 ### LRU 算法 Java 实现示例 以下是一个使用Java实现的LRU缓存示例,基于`LinkedHashMap`: ```java import java.util.LinkedHashMap; import java.util.Map; public class LRUCache<K, V> extends LinkedHashMap<K, V> { private final int capacity; public LRUCache(int capacity) { // 初始化LinkedHashMap,指定访问顺序排序 super(capacity, 0.75f, true); this.capacity = capacity; } @Override protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { // 当LinkedHashMap的大小超过预设的容量时,移除最老的元素 return size() > capacity; } } // 使用示例 public class Main { public static void main(String[] args) { LRUCache<String, String> cache = new LRUCache<>(3); cache.put("one", "1"); cache.put("two", "2"); cache.put("three", "3"); System.out.println(cache.get("one")); // 输出: 1 cache.put("four", "4"); // 此时容量已满,最久未访问的键"one"被移除 System.out.println(cache.get("one")); // 输出: null } } ``` 以上示例中,`LRUCache`类继承自`LinkedHashMap`,通过重写`removeEldestEntry`方法实现LRU缓存策略。当缓存达到预设的容量时,最久未访问的键会被自动移除。
- 粉丝: 98
- 资源: 162
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助