java-基础知识(6)

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 基础知识

1.Mysql中多大的表是大表?
我们通常说表太大,另外一层意思就是数据太多了,导致索引的效果都不明显了,只能分表了。所以我们在讨论什么是大表时,需要站在Mysql索引角度来分析,到底多大数据量时是大表。

上图是Innodb中的一个主键索引,也就是一颗B+树,树中的每个节点是一个Innodb Page,大小默认为16kb,叶子节点中的每个节点主要存储的就是一条条数据,非叶子节点中存储的是主键和页地址。

所以,我们可以来计算一下,如果B+树的高度为2,能存多少条数据。

● 假如一条记录为1kb
● 主键类型为int类型,也就一个主键占4b
● innodb中一个页地址需要占6b

所以1页中,也就是一个节点中,可以存:

  1. 16kb/1kb = 16条行数据
  2. 16kb/(4b+6b) = 1638条索引记录(主键+索引地址)

所以如果B+树的高度为2,那么叶子节点就有1638个,所以能存的行数据条数为:1638*16 = 26208条记录。

如果B+树的高度为3,那么第一层一个节点,第二层1638个节点,第三层16381638个节点,最终数据条数为:16381638*16=42,928704

也就是差不多4000多万条数据。

如果主键的类型为bigint,一个主键占8个字节,所以高度为3时,能存:

  1. 16kb/(8b+6b) = 1170
  2. 1170117016= 21902400

也就是2000多万行数据。

所以,我们可以通过这种方式来判断一个表的数据量是不是过多(B+树的高度一般不建议超过三层,因为B+树的数据都是存在磁盘中的,树太高了,进行IO的次数就表多了,整体效率也就降低了),大家后续可以通过我介绍的方法来计算某一个表,B+树高度为2时能存多少条记录,高度为3时能存多少记录,如果表中实际的数据总条数超过了3层能存放的数据量,那么这个表就是大表了,此时索引的效率就不高了,就需要进行分表了。

2.Redis的过期键的删除策略

Redis是key-value数据库,我们可以设置Redis中缓存的key的过期时间。Redis的过期策略就是指当Redis中缓存的key过期了,Redis如何处理。

● 惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
● 定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。

(expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。)

Redis中同时使用了惰性过期和定期过期两种过期策略。

3.简述Redis事务实现

1、事务开始

MULTI命令的执行,标识着一个事务的开始。MULTI命令会将客户端状态的flags属性中打开REDIS_MULTI标识来完成的。

2、命令入队

当一个客户端切换到事务状态之后,服务器会根据这个客户端发送来的命令来执行不同的操作。如果客户端发送的命令为MULTI、EXEC、WATCH、DISCARD中的一个,立即执行这个命令,否则将命令放入一个事务队列里面,然后向客户端返回QUEUED回复

● 如果客户端发送的命令为 EXEC、DISCARD、WATCH、MULTI 四个命令的其中一个,那么服务器立即执行这个命令。
● 如果客户端发送的是四个命令以外的其他命令,那么服务器并不立即执行这个命令。
首先检查此命令的格式是否正确,如果不正确,服务器会在客户端状态(redisClient)的 flags 属性关闭 REDIS_MULTI 标识,并且返回错误信息给客户端。
如果正确,将这个命令放入一个事务队列里面,然后向客户端返回 QUEUED 回复

事务队列是按照FIFO的方式保存入队的命令

3、事务执行

客户端发送 EXEC 命令,服务器执行 EXEC 命令逻辑。

● 如果客户端状态的 flags 属性不包含 REDIS_MULTI 标识,或者包含 REDIS_DIRTY_CAS 或者 REDIS_DIRTY_EXEC 标识,那么就直接取消事务的执行。
● 否则客户端处于事务状态(flags 有 REDIS_MULTI 标识),服务器会遍历客户端的事务队列,然后执行事务队列中的所有命令,最后将返回结果全部返回给客户端;

redis 不支持事务回滚机制,但是它会检查每一个事务中的命令是否错误。

Redis 事务不支持检查那些程序员自己逻辑错误。例如对 String 类型的数据库键执行对 HashMap 类型的操作!

● WATCH 命令是一个乐观锁,可以为 Redis 事务提供 check-and-set (CAS)行为。可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令。
● MULTI命令用于开启一个事务,它总是返回OK。MULTI执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中的命令才会被执行。
● EXEC:执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令执行的先后顺序排列。当操作被打断时,返回空值 nil 。
● 通过调用DISCARD,客户端可以清空事务队列,并放弃执行事务, 并且客户端会从事务状态中退出。
● UNWATCH命令可以取消watch对所有key的监控。

4.Redis 主从复制的核心原理

通过执行slaveof命令或设置slaveof选项,让一个服务器去复制另一个服务器的数据。主数据库可以进行读写操作,当写操作导致数据变化时会自动将数据同步给从数据库。而从数据库一般是只读的,并接受主数据库同步过来的数据。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库。

全量复制:

  1. 主节点通过bgsave命令fork子进程进行RDB持久化,该过程是非常消耗CPU、内存(页表复制)、硬盘IO的
  2. 主节点通过网络将RDB文件发送给从节点,对主从节点的带宽都会带来很大的消耗
  3. 从节点清空老数据、载入新RDB文件的过程是阻塞的,无法响应客户端的命令;如果从节点执行bgrewriteaof,也会带来额外的消耗

部分复制:

  1. 复制偏移量:执行复制的双方,主从节点,分别会维护一个复制偏移量offset
  2. 复制积压缓冲区:主节点内部维护了一个固定长度的、先进先出(FIFO)队列 作为复制积压缓冲区,当主从节点offset的差距过大超过缓冲区长度时,将无法执行部分复制,只能执行全量复制。
  3. 服务器运行ID(runid):每个Redis节点,都有其运行ID,运行ID由节点在启动时自动生成,主节点会将自己的运行ID发送给从节点,从节点会将主节点的运行ID存起来。 从节点Redis断开重连的时候,就是根据运行ID来判断同步的进度:
    ○ 如果从节点保存的runid与主节点现在的runid相同,说明主从节点之前同步过,主节点会继续尝试使用部分复制(到底能不能部分复制还要看offset和复制积压缓冲区的情况);
    ○ 如果从节点保存的runid与主节点现在的runid不同,说明从节点在断线前同步的Redis节点并不是当前的主节点,只能进行全量复制。

5.Redis有哪些数据结构?分别有哪些典型的应用场景?
Redis的数据结构有:

  1. 字符串:可以用来做最简单的数据,可以缓存某个简单的字符串,也可以缓存某个json格式的字符串,Redis分布式锁的实现就利用了这种数据结构,还包括可以实现计数器、Session共享、分布式ID
  2. 哈希表:可以用来存储一些key-value对,更适合用来存储对象
  3. 列表:Redis的列表通过命令的组合,既可以当做栈,也可以当做队列来使用,可以用来缓存类似微信公众号、微博等消息流数据
  4. 集合:和列表类似,也可以存储多个元素,但是不能重复,集合可以进行交集、并集、差集操作,从而可以实现类似,我和某人共同关注的人、朋友圈点赞等功能
  5. 有序集合:集合是无序的,有序集合可以设置顺序,可以用来实现排行榜功能

6.Redis分布式锁底层是如何实现的?

  1. 首先利用setnx来保证:如果key不存在才能获取到锁,如果key存在,则获取不到锁
  2. 然后还要利用lua脚本来保证多个redis操作的原子性
  3. 同时还要考虑到锁过期,所以需要额外的一个看门狗定时任务来监听锁是否需要续约
  4. 同时还要考虑到redis节点挂掉后的情况,所以需要采用红锁的方式来同时向N/2+1个节点申请锁,都申请到了才证明获取锁成功,这样就算其中某个redis节点挂掉了,锁也不能被其他客户端获取到

7.Redis主从复制的核心原理
Redis的主从复制是提高Redis的可靠性的有效措施,主从复制的流程如下:

  1. 集群启动时,主从库间会先建立连接,为全量复制做准备
  2. 主库将所有数据同步给从库。从库收到数据后,在本地完成数据加载,这个过程依赖于内存快照RDB
  3. 在主库将数据同步给从库的过程中,主库不会阻塞,仍然可以正常接收请求。否则,redis的服务就被中断了。但是,这些请求中的写操作并没有记录到刚刚生成的RDB文件中。为了保证主从库的数据一致性,主库会在内存中用专门的replication buffer,记录RDB文件生成收到的所有写操作。
  4. 最后,也就是第三个阶段,主库会把第二阶段执行过程中新收到的写命令,再发送给从库。具体的操作是,当主库完成RDB文件发送后,就会把此时replocation buffer中修改操作发送给从库,从库再执行这些操作。这样一来,主从库就实现同步了
  5. 后续主库和从库都可以处理客户端读操作,写操作只能交给主库处理,主库接收到写操作后,还会将写操作发送给从库,实现增量同步

8.Redis集群策略
Redis提供了三种集群策略:

  1. 主从模式:这种模式比较简单,主库可以读写,并且会和从库进行数据同步,这种模式下,客户端直接连主库或某个从库,但是但主库或从库宕机后,客户端需要手动修改IP,另外,这种模式也比较难进行扩容,整个集群所能存储的数据受到某台机器的内存容量,所以不可能支持特大数据量
  2. 哨兵模式:这种模式在主从的基础上新增了哨兵节点,但主库节点宕机后,哨兵会发现主库节点宕机,然后在从库中选择一个库作为进的主库,另外哨兵也可以做集群,从而可以保证但某一个哨兵节点宕机后,还有其他哨兵节点可以继续工作,这种模式可以比较好的保证Redis集群的高可用,但是仍然不能很好的解决Redis的容量上限问题。
  3. Cluster模式:Cluster模式是用得比较多的模式,它支持多主多从,这种模式会按照key进行槽位的分配,可以使得不同的key分散到不同的主节点上,利用这种模式可以使得整个集群支持更大的数据容量,同时每个主节点可以拥有自己的多个从节点,如果该主节点宕机,会从它的从节点中选举一个新的主节点。

对于这三种模式,如果Redis要存的数据量不大,可以选择哨兵模式,如果Redis要存的数据量大,并且需要持续的扩容,那么选择Cluster模式

9.Redis和Mysql如何保证数据一致

  1. 先更新Mysql,再更新Redis,如果更新Redis失败,可能仍然不一致
  2. 先删除Redis缓存数据,再更新Mysql,再次查询的时候在将数据添加到缓存中,这种方案能解决1方案的问题,但是在高并发下性能较低,而且仍然会出现数据不一致的问题,比如线程1删除了Redis缓存数据,正在更新Mysql,此时另外一个查询再查询,那么就会把Mysql中老数据又查到Redis中
  3. 延时双删,步骤是:先删除Redis缓存数据,再更新Mysql,延迟几百毫秒再删除Redis缓存数据,这样就算在更新Mysql时,有其他线程读了Mysql,把老数据读到了Redis中,那么也会被删除掉,从而把数据保持一致

10.Redis的持久化机制
RDB:Redis DataBase 将某一个时刻的内存快照(Snapshot),以二进制的方式写入磁盘。
手动触发:
● save命令,使 Redis 处于阻塞状态,直到 RDB 持久化完成,才会响应其他客户端发来的命令,所以在生产环境一定要慎用
● bgsave命令,fork出一个子进程执行持久化,主进程只在fork过程中有短暂的阻塞,子进程创建 之后,主进程就可以响应客户端请求了
● 自动触发:
● save m n :在 m 秒内,如果有 n 个键发生改变,则自动触发持久化,通过bgsave执行,如果设置多个、只要满足其一就会触发,配置文件有默认配置(可以注释掉)
● flushall:用于清空redis所有的数据库,flushdb清空当前redis所在库数据(默认是0号数据库),会 清空RDB文件,同时也会生成dump.rdb、内容为空
● 主从同步:全量同步时会自动触发bgsave命令,生成rdb发送给从节点

优点:

  1. 整个Redis数据库将只包含一个文件 dump.rdb,方便持久化。
  2. 容灾性好,方便备份。
  3. 性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能
  4. 相对于数据集大时,比 AOF的启动效率更高。

缺点:

  1. 数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候)
  2. 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。会占用cpu

AOF:Append Only File 以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录,调操作系统命令进程刷盘

  1. 所有的写命令会追加到 AOF 缓冲中。
  2. AOF 缓冲区根据对应的策略向硬盘进行同步操作。
  3. 随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
  4. 当 Redis 重启时,可以加载 AOF 文件进行数据恢复。同步策略:

每秒同步:异步完成,效率非常高,一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢 失
每修改同步:同步持久化,每次发生的数据变化都会被立即记录到磁盘中,最多丢一条 不同步:由操作系统控制,可能丢失较多数据

优点:

  1. 数据安全
  2. 通过 append 模式写文件,即使中途服务器宕机也不会破坏已经存在的内容,可以通过 redis- check-aof 工具解决数据一致性问题。
  3. AOF 机制的 rewrite 模式。定期对AOF文件进行重写,以达到压缩的目的

缺点:

  1. AOF 文件比 RDB 文件大,且恢复速度慢。
  2. 数据集大的时候,比 rdb 启动效率低。
  3. 运行效率没有RDB高

对比:
● AOF文件比RDB更新频率高,优先使用AOF还原数据。AOF比RDB更安全也更大
● RDB性能比AOF好
● 如果两个都配了优先加载AOF

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
3月前
|
Java C++ 索引
【Java】JavaSE基础知识
【Java】JavaSE基础知识
110 0
|
4月前
|
Java 编译器
Java基础知识:什么是封装、继承和多态?
Java基础知识:什么是封装、继承和多态?
72 0
|
18天前
|
Java 程序员 调度
Java中的多线程编程:基础知识与实践
【4月更文挑战第5天】 在现代软件开发中,多线程编程是一个不可或缺的技术要素。它允许程序员编写能够并行处理多个任务的程序,从而充分利用多核处理器的计算能力,提高应用程序的性能。Java作为一种广泛使用的编程语言,提供了丰富的多线程编程支持。本文将介绍Java多线程编程的基础知识,并通过实例演示如何创建和管理线程,以及如何解决多线程环境中的常见问题。
|
4月前
|
Java API
Java基础知识:什么是Java平台,包括Java SE,Java EE和Java ME?
Java基础知识:什么是Java平台,包括Java SE,Java EE和Java ME?
52 2
|
4月前
|
存储 Java
Java基础知识:Java中的基本数据类型有哪些?
Java基础知识:Java中的基本数据类型有哪些?
39 0
|
24天前
|
关系型数据库 Java 开发工具
Java入门高频考查基础知识9(15问万字参考答案)
本文探讨了Spring Cloud的工作原理,包括注册中心的心跳机制、服务发现机制,以及Eureka默认的负载均衡策略。同时,概述了Spring Boot中常用的注解及其实现方式,并深入讨论了Spring事务的注解、回滚条件、传播性和隔离级别。文章还介绍了MySQL的存储引擎及其区别,特别关注了InnoDB如何实现MySQL的事务处理。此外,本文还详细探讨了MySQL索引,包括B+树的原理和设计索引的方法。最后,比较了Git和SVN的区别,并介绍了Git命令的底层原理及流程。
31 0
Java入门高频考查基础知识9(15问万字参考答案)
|
24天前
|
存储 缓存 算法
Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)
最重要的是保持自信和冷静。提前准备,并对自己的知识和经验有自信,这样您就能在面试中展现出最佳的表现。祝您面试顺利!Java 是一种广泛使用的面向对象编程语言,在软件开发领域有着重要的地位。Java 提供了丰富的库和强大的特性,适用于多种应用场景,包括企业应用、移动应用、嵌入式系统等。下是几个面试技巧:复习核心概念、熟悉常见问题、编码实践、项目经验准备、注意优缺点、积极参与互动、准备好问题问对方和知其所以然等,多准备最好轻松能举一反三。
48 0
Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)
|
24天前
|
存储 算法 JavaScript
Java入门高频考查算法逻辑基础知识3-编程篇(超详细18题1.8万字参考编程实现)
解决这类问题时,建议采取下面的步骤: 理解数学原理:确保你懂得基本的数学公式和法则,这对于制定解决方案至关重要。 优化算法:了解时间复杂度和空间复杂度,并寻找优化的机会。特别注意避免不必要的重复计算。 代码实践:多编写实践代码,并确保你的代码是高效、清晰且稳健的。 错误检查和测试:要为你的代码编写测试案例,测试标准的、边缘情况以及异常输入。 进行复杂问题简化:面对复杂的问题时,先尝试简化问题,然后逐步分析和解决。 沟通和解释:在编写代码的时候清晰地沟通你的思路,不仅要写出正确的代码,还要能向面试官解释你的
33 0
|
24天前
|
存储 Java 编译器
Java入门高频考查基础知识2(超详细28题2.5万字答案)
多态是面向对象编程中的一个重要概念,它允许不同类的对象对同一消息作出不同的响应。在具体实现上,多态允许一个父类的引用指向其子类的对象,并根据实际指向的对象的类型来调用相应的方法。在 Java 中,多态可以通过以下几种方式实现:在同一个类中,方法名相同,但形参列表不同,实现了多态。子类可以重写(覆盖)其父类的方法,实现多态。在父类引用中调用该方法时,根据实际指向的子类对象的类型来调用相应的方法实现。
39 0
|
30天前
|
Java 数据库连接 API
Java 学习路线:基础知识、数据类型、条件语句、函数、循环、异常处理、数据结构、面向对象编程、包、文件和 API
Java 是一种广泛使用的、面向对象的编程语言,始于1995年,以其跨平台性、安全性和可靠性著称,应用于从移动设备到数据中心的各种场景。基础概念包括变量(如局部、实例和静态变量)、数据类型(原始和非原始)、条件语句(if、else、switch等)、函数、循环、异常处理、数据结构(如数组、链表)和面向对象编程(类、接口、继承等)。深入学习还包括包、内存管理、集合框架、序列化、网络套接字、泛型、流、JVM、垃圾回收和线程。构建工具如Gradle、Maven和Ant简化了开发流程,Web框架如Spring和Spring Boot支持Web应用开发。ORM工具如JPA、Hibernate处理对象与数
92 3

热门文章

最新文章