前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java面试:2021.05.30

Java面试:2021.05.30

原创
作者头像
夕梦
修改2021-06-07 17:55:55
3280
修改2021-06-07 17:55:55
举报
文章被收录于专栏:每日面试每日面试

1、什么是悲观锁?什么是乐观锁? 1)悲观锁 它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在 整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供 的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改 数据)。

在悲观锁的情况下,为了保证事务的隔离性,就需要一致性锁定读。读取数据时给加锁,其它事务无法修改这些数 据。修改删除数据时也要加锁,其它事务无法读取这些数据。

:悲观锁,就是我们上面看到的共享锁和排他锁。

2)乐观锁 相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证 操作大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承 受。

而乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本( Version )记录机制实现。何谓数据 版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据 的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予 以更新,否则认为是过期数据。

:乐观锁,实际就是通过版本号,从而实现 CAS 原子性更新。

2、MySQL 主从复制的流程是怎么样的?

MySQL 的主从复制是基于如下 3 个线程的交互(多线程复制里面应该是 4 类线程): 

1、Master 上面的 binlog dump 线程,该线程负责将 master 的 binlog event 传到 slave 。 

2、Slave 上面的 IO 线程,该线程负责接收 Master 传过来的 binlog,并写入 relay log 。 

3、Slave 上面的 SQL 线程,该线程负责读取 relay log 并执行。 

4、如果是多线程复制,无论是 5.6 库级别的假多线程还是 MariaDB 或者 5.7 的真正的多线程复制, SQL 线 程只做 coordinator ,只负责把 relay log 中的 binlog 读出来然后交给 worker 线程, woker 线程负责具体 binlog event 的执行。 3、MySQL 如何保证复制过程中数据一致性?

1、在 MySQL5.5 以及之前, slave 的 SQL 线程执行的 relay log 的位置只能保存在文件( relay-log.info)里 面,并且该文件默认每执行 10000 次事务做一次同步到磁盘, 这意味着 slave 意外 crash 重启时, SQL 线程 执行到的位置和数据库的数据是不一致的,将导致复制报错,如果不重搭复制,则有可能会导致数据不一 致。 

MySQL 5.6 引入参数 relay_log_info_repository,将该参数设置为 TABLE 时, MySQL 将 SQL 线程执行 到的位置存到 mysql.slave_relay_log_info 表,这样更新该表的位置和 SQL 线程执行的用户事务绑定成 一个事务,这样 slave 意外宕机后,slave 通过 innodb 的崩溃恢复可以把 SQL 线程执行到的位置和用 户事务恢复到一致性的状态。

2、MySQL 5.6 引入 GTID 复制,每个 GTID 对应的事务在每个实例上面多执行一次, 这极大地提高了复制 的数据一致性。 

3、MySQL 5.5 引入半同步复制, 用户安装半同步复制插件并且开启参数后,设置超时时间,可保证在超时 时间内如果 binlog 不传到 slave 上面,那么用户提交事务时不会返回,直到超时后切成异步复制,但是如果 切成异步之前用户线程提交时在 master 上面等待的时候,事务已经提交,该事务对 master 上面的其他 session 是可见的,如果这时 master 宕机,那么到 slave 上面该事务又不可见了,该问题直到 5.7 才解决。 

4、MySQL 5.7 引入无损半同步复制,引入参 rpl_semi_sync_master_wait_point,该参数默认为 after_sync,指的是在切成半同步之前,事务不提交,而是接收到 slave 的 ACK 确认之后才提交该事务,从 此,复制真正可以做到无损的了。 

5、可以再说一下 5.7 的无损复制情况下, master 意外宕机,重启后发现有 binlog 没传到 slave 上面,这部 分 binlog 怎么办???分 2 种情况讨论, 1 宕机时已经切成异步了, 2 是宕机时还没切成异步??? 这个怎 么判断宕机时有没有切成异步呢??? 分别怎么处理???

4、Redis 和 Memcached 的区别有哪些?

1. Redis 支持复杂的数据结构 Memcached 仅提供简单的字符串。 

Redis 提供复杂的数据结构,丰富的数据操作。 也因为 Redis 支持复杂的数据结构,Redis 即使往于 Memcached 推出,却获得更多开发者的青睐。

Redis 相比 Memcached 来说,拥有更多的数据结构,能支持更丰富的数据操作。如果需要缓存能够支持更复杂的 结构和操作,Redis 会是不错的选择。

2. Redis 原生支持集群模式 

在 Redis3.x 版本中,官方便能支持 Cluster 模式。 

Memcached 没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据。

3. 性能对比 

Redis 只使用单核,而 Memcached 可以使用多核,所以平均每一个核上 Redis在存储小数据时比 Memcached 性能更高。 

在 100k 以上的数据中,Memcached 性能要高于 Redis 。虽然 Redis 近也在存储大数据的性能上进行优 化,但是比起 Memcached,还是稍有逊色。

4. 内存使用效率对比 

简单的 Key-Value 存储的话,Memcached 的内存利用率更高,可以使用类似内存池。 

如果 Redis 采用 hash 结构来做 key-value 存储,由于其组合式的压缩, 其内存利用率会高于 Memcached 。

另外,Redis 和 Memcached 的内存管理方法不同。

Redis 采用的是包装的 malloc/free , 相较于 Memcached 的内存管理方法 tcmalloc / jmalloc 来说,要简单 很多 。 

5. 网络 IO 模型 Memcached 是多线程,非阻塞 IO 复用的网络模型,原型上接近 Nignx 。 

Redis 使用单线程的 IO 复用模型,自己封装了一个简单的 AeEvent 事件处理框架,主要实现了 epoll, kqueue 和 select ,更接近 Apache 早期的模式。 

6. 持久化存储

Memcached 不支持持久化存储,重启时,数据被清空。 

Redis 支持持久化存储,重启时,可以恢复已持久化的数据。

5、请说说 Redis 的线程模型?

redis 内部使用文件事件处理器 file event handler ,这个文件事件处理器是单线程的,所以 redis 才叫做单线 程的模型。它采用 IO 多路复用机制同时监听多个 socket,根据 socket 上的事件来选择对应的事件处理器进行处 理。

文件事件处理器的结构包含 4 个部分: 多个 socket;

IO 多路复用程序;

文件事件分派器;

事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)。

多个 socket 可能会并发产生不同的操作,每个操作对应不同的文件事件,但是 IO 多路复用程序会监听多个 socket,会将 socket 产生的事件放入队列中排队,事件分派器每次从队列中取出一个事件,把该事件交给对应的 事件处理器进行处理。

来看客户端与 redis 的一次通信过程:

客户端 socket01 向 redis 的 server socket 请求建立连接,此时 server socket 会产生一个 AE_READABLE 事件,IO 多路复用程序监听到 server socket 产生的事件后,将该事件压入队列中。文件事件分派器从队列 中获取该事件,交给 连接应答处理器 。连接应答处理器会创建一个能与客户端通信的 socket01,并将该 socket01 的 AE_READABLE 事件与命令请求处理器关联。 

假设此时客户端发送了一个 set key value 请求,此时 redis 中的 socket01 会产生 AE_READABLE 事 件,IO 多路复用程序将事件压入队列,此时事件分派器从队列中获取到该事件,由于前面 socket01 的 AE_READABLE 事件已经与命令请求处理器关联,因此事件分派器将事件交给命令请求处理器来处理。命令 请求处理器读取 socket01 的 key value 并在自己内存中完成 key value 的设置。操作完成后,它会将 socket01 的 AE_WRITABLE 事件与令回复处理器关联。

如果此时客户端准备好接收返回结果了,那么 redis 中的 socket01 会产生一个 AE_WRITABLE 事件,同样压 入队列中,事件分派器找到相关联的命令回复处理器,由命令回复处理器对 socket01 输入本次操作的一个结 果,比如 ok ,之后解除 socket01 的 AE_WRITABLE 事件与命令回复处理器的关联。

6、为什么 Redis 单线程模型也能效率这么高?

1、纯内存操作。 Redis 为了达到快的读写速度,将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以 Redis 具有快速和数据持久化的特征。 

如果不将数据放在内存中,磁盘 I/O 速度为严重影响 Redis 的性能。 

2、核心是基于非阻塞的 IO 多路复用机制。 

3、单线程反而避免了多线程的频繁上下文切换问题。

Redis 利用队列技术,将并发访问变为串行访问,消除了传统数据库串行控制的开销

4、Redis 全程使用 hash 结构,读取速度快,还有一些特殊的数据结构,对数据存储进行了优化,如压缩 表,对短数据进行压缩存储,再如,跳表,使用有序的数据结构加快读取的速度。

7、Redis 有几种持久化方式?

Redis 提供了两种方式,实现数据的持久化到硬盘。     1、【全量】RDB 持久化,是指在指定的时间间隔内将内存中的数据集快照写入磁盘。实际操作过程是,fork 一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。 - 默认开启rdb持久化;

    2、【增量】AOF持久化,以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。 - 默认关闭 每次写,删除操作就同步或者每秒同步。 (1)RDB 优缺点 优点:     灵活设置备份频率和周期。你可能打算每个小时归档一次最近 24 小时的数据,同时还要每天归档一次最近 30 天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。     非常适合冷备份,对于灾难恢复而言,RDB 是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。推荐,可以将这种完整的数据文件发送到一些远程的安全存储上去,比如说 Amazon 的 S3 云服务上去,在国内可以是阿里云的 OSS 分布式存储上。     性能最大化。对于 Redis 的服务进程而言,在开始持久化时,它唯一需要做的只是 fork 出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行 IO 操作了。也就是说,RDB 对 Redis 对外提供的读写服务,影响非常小,可以让 Redis 保持高性能。     恢复更快。相比于 AOF 机制,RDB 的恢复速度更更快,更适合恢复数据,特别是在数据集非常大的情况。 缺点:     如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么 RDB 将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。         所以,RDB 实际场景下,需要和 AOF 一起使用。       由于 RDB 是通过 fork 子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是 1 秒钟。         所以,RDB 建议在业务低估,例如在半夜执行。 (2)AOF 优缺点 优点:     该机制可以带来更高的数据安全性,即数据持久性。Redis 中提供了 3 种同步策略,即每秒同步、每修改(执行一个命令)同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。     由于该机制对日志文件的写入操作采用的是 append 模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。因为以 append-only 模式写入,所以没有任何磁盘寻址的开销,写入性能非常高。另外,如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在 Redis 下一次启动之前,我们可以通过 redis-check-aof 工具来帮助我们解决数据一致性的问题。     如果日志过大,Redis可以自动启用 rewrite 机制。即使出现后台重写操作,也不会影响客户端的读写。因为在 rewrite log 的时候,会对其中的指令进行压缩,创建出一份需要恢复数据的最小日志出来。再创建新日志文件的时候,老的日志文件还是照常写入。当新的 merge 后的日志文件 ready 的时候,再交换新老日志文件即可。     AOF 包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。 缺点:     对于相同数量的数据集而言,AOF 文件通常要大于 RDB 文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。     根据同步策略的不同,AOF 在运行效率上往往会慢于 RDB 。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和 RDB 一样高效。     以前 AOF 发生过 bug ,就是通过 AOF 记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。所以说,类似 AOF 这种较为复杂的基于命令日志/merge/回放的方式,比基于 RDB 每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有 bug 。不过 AOF 就是为了避免 rewrite 过程导致的 bug ,因此每次 rewrite 并不是基于旧的指令日志进行 merge 的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多。 (3)如何选择     不要仅仅使用 RDB,因为那样会导致你丢失很多数据     也不要仅仅使用 AOF,因为那样有两个问题,第一,你通过 AOF 做冷备,没有 RDB 做冷备,来的恢复速度更快; 第二,RDB 每次简单粗暴生成数据快照,更加健壮,可以避免 AOF 这种复杂的备份和恢复机制的 bug 。     Redis 支持同时开启开启两种持久化方式,我们可以综合使用 AOF 和 RDB 两种持久化机制,用 AOF 来保证数据不丢失,作为数据恢复的第一选择; 用 RDB 来做不同程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可以使用 RDB 来进行快速的数据恢复。     如果同时使用 RDB 和 AOF 两种持久化机制,那么在 Redis 重启的时候,会使用 AOF 来重新构建数据,因为 AOF 中的数据更加完整。     一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失,那么你可以只使用 RDB 持久化。     有很多用户都只使用 AOF 持久化,但并不推荐这种方式:因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比AOF恢复的速度要快,除此之外,使用 RDB 还可以避免之前提到的 AOF 程序的 bug。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档