151. RabbitMQ 对集群节点停止顺序有要求吗?
RabbitMQ 对集群的停止的顺序是有要求的,应该先关闭内存节点,最后再关闭磁盘节点。
如果顺序恰好相反的话,可能会造成消息的丢失。
Kafka
152.kafka 可以脱离 zookeeper 单独使用吗?为什么?
kafka 不能脱离 zookeeper 单独使用,因为 kafka 使用 zookeeper 管理和协调 kafka 的节点服务器。
153.kafka 有几种数据保留的策略?
kafka 有两种数据保存策略:按照过期时间保留和按照存储的消息大小保留。
154.kafka 同时设置了 7 天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?
这个时候 kafka 会执行数据清除工作,时间和大小不论那个满足条件,都会清空数据。
155.什么情况会导致 kafka 运行变慢?
cpu 性能瓶颈
磁盘读写瓶颈
网络瓶颈
156.使用 kafka 集群需要注意什么?
集群的数量不是越多越好,最好不要超过 7 个,因为节点越多,消息复制需要的时间就越长,整个群组的吞吐量就越低。
集群数量最好是单数,因为超过一半故障集群就不能用了,设置为单数容错率更高。
Zookeeper
157. zookeeper 是什么?
一.zookeeper 是什么
ZooKeeper由雅虎研究院开发,是Google Chubby的开源实现,后来托管到Apache,于2010年11月正式成为Apache的顶级项目。
ZooKeeper是一个经典的分布式数据一致性解决方案,致力于为分布式应用提供一个高性能、高可用,
且具有严格顺序访问控制能力的分布式协调服务。
分布式应用程序可以基于ZooKeeper实现数据发布与订阅、负载均衡、命名服务、分布式协调与通知、集群管理、
Leader选举、分布式锁、分布式队列等功能。
二.ZooKeeper目标
ZooKeeper致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调服务
2.1 高性能
ZooKeeper将全量数据存储在内存中,并直接服务于客户端的所有非事务请求,尤其适用于以读为主的应用场景
2.2 高可用
ZooKeeper一般以集群的方式对外提供服务,一般3 ~ 5台机器就可以组成一个可用的Zookeeper集群了,
每台机器都会在内存中维护当前的服务器状态,并且每台机器之间都相互保持着通信。
只要集群中超过一般的机器都能够正常工作,那么整个集群就能够正常对外服务
2.3 严格顺序访问
对于来自客户端的每个更新请求,ZooKeeper都会分配一个全局唯一的递增编号,这个编号反映了所有事务操作的先后顺序
三.ZooKeeper五大特性
ZooKeeper一般以集群的方式对外提供服务,一个集群包含多个节点,每个节点对应一台ZooKeeper服务器,
所有的节点共同对外提供服务,整个集群环境对分布式数据一致性提供了全面的支持,具体包括以下五大特性:
3.1 顺序一致性
从同一个客户端发起的请求,最终将会严格按照其发送顺序进入ZooKeeper中
3.2 原子性
所有请求的响应结果在整个分布式集群环境中具备原子性,即要么整个集群中所有机器都成功的处理了某个请求,
要么就都没有处理,绝对不会出现集群中一部分机器处理了某一个请求,而另一部分机器却没有处理的情况
3.3 单一性
无论客户端连接到ZooKeeper集群中哪个服务器,每个客户端所看到的服务端模型都是一致的,
不可能出现两种不同的数据状态,因为ZooKeeper集群中每台服务器之间会进行数据同步
3.4 可靠性
一旦服务端数据的状态发送了变化,就会立即存储起来,除非此时有另一个请求对其进行了变更,否则数据一定是可靠的
3.5 实时性
当某个请求被成功处理后,ZooKeeper仅仅保证在一定的时间段内,客户端最终一定能从服务端上读取到最新的数据状态,
即ZooKeeper保证数据的最终一致性
四.ZooKeeper集群角色
在分布式系统中,集群中每台机器都有自己的角色,ZooKeeper没有沿用传统的Master/Slave模式(主备模式),
而是引入了Leader、Follower和Observer三种角色
4.1 Leader
集群通过一个Leader选举过程从所有的机器中选举一台机器作为”Leader”,Leader能为客户端提供读和写服务
Leader服务器是整个集群工作机制的核心,主要工作:
1.事务请求的唯一调度者和处理者,保证集群事务处理的顺序性
2.集群内部各服务器的调度者
4.2 Follower
顾名思义,Follower是追随者,主要工作:
1.参与Leader选举投票
2.处理客户端非事务请求 - 即读服务
3.转发事务请求给Leader服务器
4.参与事务请求Proposal的投票
4.3 Observer
Observer是ZooKeeper自3.3.0版本开始引入的一个全新的服务器角色,充当一个观察者角色,
工作原理和Follower基本是一致的,和Follower唯一的区别是Observer不参与任何形式的投票
1.处理客户端非事务请求 - 即读服务
2.转发事务请求给Leader服务器
3.不参与Leader选举投票
4.参与事务请求Proposal的投票
所以Observer可以在不影响写性能的情况下提升集群的读性能
五. 原子广播协议 - Zab
ZooKeeper并非采用经典的分布式一致性协议 - Paxos,
而是参考了Paxos设计了一种更加轻量级的支持崩溃可恢复的原子广播协议-Zab(ZooKeeper Atomic Broadcast)。
ZAB协议分为两个阶段 - Leader Election(领导选举)和Atomic Broadcast(原子广播)
5.1 领导选举 - Leader Election
当集群启动时,会选举一台节点为Leader,而其他节点为Follower,当Leader节点出现网络中断、崩溃退出与重启等异常情况,
ZAB会进入恢复模式并选举产生新的Leader服务器,当集群中已有过半机器与该Leader服务器完成数据状态同步,退出恢复模式
5.2 原子广播 - Atomic Broadcast
当领导选举完成后,就进入原子广播阶段。此时集群中已存在一个Leader服务器在进行消息广播,
当一台同样遵循ZAB协议的服务器启动后加入到集群中,新加的服务器会自动进入数据恢复阶段
六. 事务请求
在ZooKeeper中,事务是指能够改变ZooKeeper服务器状态的请求,一般指创建节点、更新数据、删除节点以及创建会话操作
6.1 事务转发
为了保证事务请求被顺序执行,从而确保ZooKeeper集群的数据一致性,所有的事务请求必须由Leader服务器处理,
ZooKeeper实现了非常特别的事务请求转发机制:
所有非Leader服务器如果接收到来自客户端的事务请求,必须将其转发给Leader服务器来处理
6.2 事务ID - ZXID
在分布式系统中,事务请求可能存在依赖关系,如变更C需要依赖变更A和变更B,
这样就要求ZAB协议能够保证如果一个状态变更成功被处理了,那么其所有依赖的状态变更都应该已经提前被处理掉了。
在ZooKeeper中对每一个事务请求,都会为其分配一个全局唯一的事务ID,使用ZXID表示,通常是一个64位的数字。
每一个ZXID对应一次事务,从这些ZXID可以间接识别出ZooKeeper处理这些事务请求的全局顺序
七. 数据节点 - ZNode
ZooKeeper内部拥有一个树状的内存模型,类似文件系统,只是在ZooKeeper中将这些目录与文件系统统称为ZNode,
ZNode是ZooKeeper中数据的最小单元,每个ZNode上可以保存数据,还可以挂载子节点,因此构成了一个层次化的命名空间
7.1 节点路径
ZooKeeper中使用斜杠(/)分割的路径表示ZNode路径,斜杠(/)表示根节点
7.2 节点特性
在ZooKeeper中,每个数据节点ZNode都是有生命周期的,其生命周期的长短取决于ZNode的节点类型
7.3 权限控制 - ACL
为了有效保障ZooKeeper中数据的安全,避免因误操作而带来数据随意变更导致分布式系统异常,
ZooKeeper提供了一套完善的ACL(Access Contro List)权限控制机制来保障数据的安全。
可以从三个方面理解ACL机制,分别是:权限模式(Scheme)、授权对象(ID)和权限(Permission),
通常使用”scheme:id:permission”来标识一个有效的ACL信息
7.4 节点状态信息
每个数据节点ZNode除了存储数据内容外,还存储了数据节点本身的一些状态信息
7.5 节点版本
ZooKeeper为数据节点引入版本的概念,对个数据节点都具有三种类型的版本信息,对数据节点的任何更新操作都会引起版本号的变化
在分布式系统中,在运行过程中往往需要保证数据访问的排他性。Java并发中是实现了对CAS的指令支持,即对于值V,
每次更新前都会比对其值是否是预期值A,只有符合预期,才会将V原子化的更新到新值B
而ZooKeeper每个节点都有数据版本的概念,在调用更新操作的时候,先从请求中获取当前请求的版本version,
同时获取服务器上该数据最新版本currentVersion,如果无法匹配,就无法更新成功,这样可以有效避免一些分布式更新的并发问题
八. Watcher - 数据变更的通知
在ZooKeeper中,引入Watcher机制来实现分布式数据的发布/订阅功能。ZooKeeper允许客户端向服务器注册一个Watcher监听,
当服务器的一些指定事件触发了这个Watcher,那么就会向指定客户端发送一个事件通知来实现分布式的通知功能
Watcher机制为以下三个过程:
8.1 客户端注册Watcher
在创建一个ZooKeeper客户端对象实例时,可以向构造方法中传入一个Watcher,这个Watcher将作为整个ZooKeeper会话期间的默认Watcher,
一致保存在客户端,并向ZooKeeper服务器注册Watcher
客户端并不会把真实的Watcher对象传递到服务器,仅仅只是在客户端请求中使用boolean类型属性进行标记,降低网络开销和服务器内存开销
8.2 服务端处理Watcher
服务端执行数据变更,当Watcher监听的对应数据节点的数据内容发生变更,如果找到对应的Watcher,会将其提取出来,
同时从管理中将其删除(说明Watcher在服务端是一次性的,即触发一次就失效了),触发Watcher,向客户端发送通知
8.3 客户端回调Watcher
客户端获取通知,识别出事件类型,从相应的Watcher存储中去除对应的Watcher(说明客户端也是一次性的,即一旦触发就会失效)
8.4 总结
一致性:无论是客户端还是服务器,一旦一个Watcher被处罚,ZooKeeper都会将其从相应的存储中移除,
因此开发人员在Watcher使用上要反复注册,这样可以有效减轻服务器压力
客户端串行执行:客户端Watcher回调的过程是一个串行同步的过程,这保证了顺序
轻量:客户端并不会把真实的Watcher对象传递到服务器,仅仅只是在客户端请求中使用boolean类型属性进行标记,
降低网络开销和服务器内存开销
九. Session - 会话
Session是指客户端连接 - 客户端和服务器之间的一个TCP长连接
9.1 会话状态
会话在整个生命周期中,会在不同的会话转态之间进行切换
9.2 Session属性
Session是ZooKeeper中的会话实体,代表了一个客户端会话,其包含4个属性:
9.3 心跳检测
为了保证客户端会话的有效性,客户端会在会话超时时间范围内向服务器发送PING请求来保持会话的有效性,即心跳检测。
服务器接收到客户端的这个心跳检测,就会重新激活对应的客户端会话
9.4 会话清理
服务器的超级检查线程会在指定时间点进行检查,整理出一些已经过期的会话后,就要开始进行会话清理了:
关闭会话
清理相关的临时节点
9.5 重连
当客户端和服务器之间网络连接断开,客户端会自动进行反复的重连,直到最终成功连接上ZooKeeper集群中的一台机器
在会话超时时间内重新连接上,被视为重连成功
在会话超时时间外重新连接上,此时服务器已经进行了会话清理,但客户端不知道会话已经失效,
重新连接服务器会告诉客户端会话已失效,被视为非法会话
158. zookeeper 都有哪些功能?
集群管理:监控节点存活状态、运行请求等。
主节点选举:主节点挂掉之后可以从备用节点开始新一轮选举,主节点选举说的就是这个选举的过程,使用zookeeper可以是协助完成这个过程。
费不是锁:zookeeper提供两种锁:独占锁、共享锁。独占锁即一次只能有一个线程使用资源,共享锁是读锁共享,读写互斥,
既可以有多线程童师傅去一个资源,如果要使用写锁也只能有一个线程使用。zookeeper可以对分布式锁进行控制。
命名服务:在分布式系统中,通过使用命名服务,客户端应用能够根据指定名字来获取资源或服务的地址,提供者等信息。
159. zookeeper 有几种部署模式?
zookeeper有三种部署模式:
单机部署:一台集群上运行;
集群部署:多台集群运行;
伪集群部署:一台进群启动多个zookeeper实例运行;
160. zookeeper 怎么保证主从节点的状态同步?
Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。
Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。
恢复模式:当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,
且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。因此,选主得到的leader保证了同步状态的进行,
状态同步又保证了leader和Server具有相同的系统状态,当leader失去主权后可以在其他follower中选主新的leader。
161. 集群中为什么要有主节点?
在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,
其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能,所以就需要主节点
162. 集群中有 3 台服务器,其中一个节点宕机,这个时候 zookeeper 还可以使用吗?
可以继续使用,单数服务器只要没超过一半的服务器宕机就可以继续使用。
163. 说一下 zookeeper 的通知机制?
客户端端会对某个 znode 建立一个 watcher 事件,
当该 znode 发生变化时,这些客户端会收到 zookeeper 的通知,
然后客户端可以根据 znode 变化来做出业务上的改变。
MySQL
164. 数据库的三范式是什么?
1、第一范式,又称1NF,它指的是在一个应用中的数据都可以组织成由行和列的表格形式,且表格的任意一个行列交叉点即单元格,
都不可再划分为行和列的形式,实际上任意一张表格都满复足1NF;
2、第二范式,又称2NF,它指的是在满足1NF的基础上,
一张数据表中的任何非主键字段都全部依赖于主键字段,没有制任何非主键字段只依赖于主键字段的一部分。
即,可以由主键字段来唯一的确定一条记录。比如学号+课程号的联合主键,可以唯一的确定某个成绩是哪个学员的哪门课的成绩,
缺少学号或者缺少课程号,都不能确定成绩的意义。
3、第三范式,又称3NF,它是知指在满足2NF的基础上,
数据表的任何非主键字段之间都不产生函数依赖,即非主键字段之间没有依赖关系,全部只依赖于道主键字段。
例如将学员姓名和所属班级名称放在同一张表中是不科学的,因为学员依赖于班级,可将学员信息和班级信息单独存放,以满足3NF。
165. 一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 MySQL 数据库,又插入了一条数据,此时 id 是几?
一般情况下,我们创建的表的类型是InnoDB,如果新增一条记录(不重启mysql的情况下),这条记录的id是8;
但是如果重启(文中提到的)MySQL的话,这条记录的ID是6。因为InnoDB表只把自增主键的最大ID记录到内存中,
所以重启数据库或者对表OPTIMIZE操作,都会使最大ID丢失。
但是,如果我们使用表的类型是MylSAM,那么这条记录的ID就是8。因为MylSAM表会把自增主键的最大ID记录到数据文件里面,
重启MYSQL后,自增主键的最大ID也不会丢失。
注:如果在这7条记录里面删除的是中间的几个记录(比如删除的是3,4两条记录),重启MySQL数据库后,
insert一条记录后,ID都是8。因为内存或者数据库文件存储都是自增主键最大ID
166. 如何获取当前数据库版本?
mysql
select version();
oralce
select * from v$version;
167. 说一下 ACID 是什么?
ACID,是指在可靠数据库管理系统(DBMS)中,事务(transaction)所应该具有的四个特性:
原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability).
这是可靠数据库所应具备的几个特性.所以ACID就是这四大特性的缩写。
原子性(Atomicity)
原子性意味着数据库中的事务执行是作为原子。即不可再分,整个语句要么执行,要么不执行。
在SQL SERVER中,每一个单独的语句都可以看作是默认包含在一个事务之中,每一个语句本身具有原子性,
要么全部执行,这么全部不执行,不会有中间状态:
例如:
银行转账功能,从A账户减去100,在B账户增加100,如果这两个语句不能保证原子性的话,比如从A账户减去100后,
服务器断电,而在B账户中却没有增加100.虽然这种情况会让银行很开心,但作为开发人员的你可不希望这种结果.
而默认事务中,即使出错了也不会整个事务进行回滚。而是失败的语句抛出异常,而正确的语句成功执行。
这样会破坏原子性。所以SQL SERVER给予了一些选项来保证事务的原子性。
一致性(Consistency)
一致性即在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
一致性体现在两个层面:
1.数据库机制层面
数据库层面的一致性是,在一个事务执行之前和之后,
数据会符合你设置的约束(唯一约束,外键约束,Check约束等)和触发器设置.
这一点是由SQL SERVER进行保证的.
2.业务层面
对于业务层面来说,一致性是保持业务的一致性.这个业务一致性需要由开发人员进行保证.
很多业务方面的一致性可以通过转移到数据库机制层面进行保证.比如,产品只有两个型号,
则可以转移到使用CHECK约束使某一列必须只能存这两个型号.
隔离性(Isolation)
隔离性。事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。
在Windows中,如果多个进程对同一个文件进行修改是不允许的,Windows通过这种方式来保证不同进程的隔离性,
而SQL Server中,通过SQL SERVER对数据库文件进行管理,从而可以让多个进程可以同时访问数据库:
SQL Server利用加锁和阻塞来保证事务之间不同等级的隔离性.
一般情况下,完全的隔离性是不现实的,完全的隔离性要求数据库同一时间只执行一条事务,这样的性能可想而知.
想要理解SQL Server中对于隔离性的保障,首先要了解事务之间是如何干扰的.事务之间的互相影响的情况分为几种,
分别为:脏读(Dirty Read),不可重复读,幻读。
持久性(Durability)
持久性,意味着在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
即使出现了任何事故比如断电等,事务一旦提交,则持久化保存在数据库中.
168. char 和 varchar 的区别是什么?
1. char类型的长度是固定的,varchar的长度是可变的。
这就表示,存储字符串'abc',使用char(10),表示存储的字符将占10个字节(包括7个空字符)
使用varchar2(10),,则表示只占3个字节,10是最大值,当存储的字符小于10时,按照实际的长度存储。
2.char类型的效率比varchar的效率稍高
3.varchar 与 varchar2的区别
varchar2是oracle开发的一个数据类型。
工业标准的varchar可以存储空字符串,oracle的varchar2还可以存储NULL值,如果想要有向后兼容的能力建议使用varchar2
4.varchar2比char节省空间,但是在效率上比char稍差些。既要获得效率即必须牺牲一点空间,这就是设计上的"以空间换时间"
varchar2虽然比char节省空间,但是一个varchar2列经常被修改,而且每次修改的数据长度不同,这会引起“行迁移的现象”,
而这造成的多余的I/O,是数据库设计中尽量避免的,在这种情况下使用char代替varchar2会更好些。
总结:1. 如果一个字段经常被修改,而且每次修改的数据长度不同,
为了效率应当考虑用char定长代替varchar2变长。(列如一个用户的名字经常被修改)
2. 设计的时候尽量考虑 用空间换时间。
169. float 和 double 的区别是什么?
01.在内存中占有的字节数不同
单精度浮点数在机内存占4个字节
双精度浮点数在机内存占8个字节
02.有效数字位数不同
单精度浮点数有效数字8位
双精度浮点数有效数字16位
03.数值取值范围
单精度浮点数的表示范围:-3.40E+38~3.40E+38
双精度浮点数的表示范围:-1.79E+308~-1.79E+308
04.在程序中处理速度不同
一般来说,CPU处理单精度浮点数的速度比处理双精度浮点数快
如果不声明,默认小数为double类型,所以如果要用float的话,必须进行强转
例如:float a=1.3; 会编译报错,正确的写法 float a = (float)1.3;
或者float a = 1.3f;(f或F都可以不区分大小写)
注意:float是8位有效数字,第7位数字将会四舍五入
170. MySQL 的内连接、左连接、右连接有什么区别?
1.内连接,显示两个表中有联系的所有数据;
2.左链接,以左表为参照,显示所有数据,右表中没有则以null显示
3.右链接,以右表为参照显示数据,,左表中没有则以null显示
171. MySQL 索引是怎么实现的?
.B_Tree适用于:
1.全值匹配
全值匹配是指和索引中的所有列进行匹配。
2.匹配最左前缀
匹配左左前缀即只使用索引的第4102一列
3.匹配列前缀
匹配某一列开头部分(指的第一列)。
4.匹配范围值
5.精确匹配某一列并范围匹配另1653一列
6.只访问索引的查内询
只需访问索引,无需访问数据行。
.B_Tree限制
1.如果不是按照索引的最左列开始查找,则无法使用索引。
2.不能跳过索引中的列。
3.如果查询中有容某个列的范围查询,则其右边左右列无法使用索引优化查找。
172. 怎么验证 MySQL 的索引是否满足需求?
使用 explain 查看 SQL 是如何执行查询语句的,从而分析你的索引是否满足需求。
explain 语法:explain select * from table where type=1。
173. 说一下数据库的事务隔离?
Read uncommitted (读未提交):最低级别,以上问题均无法解决。
Read committed (读已提交):读已提交,可避免脏读情况发生。
Repeatable Read(可重复读):确保事务可以多次从一个字段中读取相同的值,
在此事务持续期间,禁止其他事务对此字段的更新,
可以避免脏读和不可重复读,仍会出现幻读问题。
Serializable (串行化):最严格的事务隔离级别,要求所有事务被串行执行,
不能并发执行,可避免脏读、不可重复读、幻读情况的发生。
174. 说一下 MySQL 常用的引擎?
(1):MyISAM存储引擎:不支持事务、也不支持外键,优势是访问速度快,对事务完整性没有
要求或者以select,insert为主的应用基本上可以用这个引擎来创建表
支持3种不同的存储格式,分别是:静态表;动态表;压缩表
静态表:表中的字段都是非变长字段,这样每个记录都是固定长度的,优点存储非常迅速,容易缓存,出现故障容易恢复;
缺点是占用的空间通常比动态表多(因为存储时会按照列的宽度定义补足空格)
ps:在取数据的时候,默认会把字段后面的空格去掉,
如果不注意会把数据本身带的空格也会忽略。
动态表:记录不是固定长度的,这样存储的优点是占用的空间相对较少;缺点:频繁的更新、删除数据容易产生碎片,
需要定期执行OPTIMIZE TABLE或者myisamchk-r命令来改善性能
压缩表:因为每个记录是被单独压缩的,所以只有非常小的访问开支
(2)InnoDB存储引擎*
该存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。但是对比MyISAM引擎,写的处理效率会差一些,
并且会占用更多的磁盘空间以保留数据和索引。?
InnoDB存储引擎的特点:支持自动增长列,支持外键约束
(3):MEMORY存储引擎
Memory存储引擎使用存在于内存中的内容来创建表。每个memory表只实际对应一个磁盘文件,格式是.frm。
memory类型的表访问非常的快,因为它的数据是放在内存中的,
并且默认使用HASH索引,但是一旦服务关闭,表中的数据就会丢失掉。?
MEMORY存储引擎的表可以选择使用BTREE索引或者HASH索引,两种不同类型的索引有其不同的使用范围
Hash索引优点:?
Hash 索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位,不像B-Tree 索引需要从根节点到枝节点,
最后才能访问到页节点这样多次的IO访问,所以 Hash 索引的查询效率要远高于 B-Tree 索引。?
Hash索引缺点: 那么不精确查找呢,也很明显,因为hash算法是基于等值计算的,
所以对于“like”等范围查找hash索引无效,不支持;
Memory类型的存储引擎主要用于哪些内容变化不频繁的代码表,或者作为统计操作的中间结果表,
便于高效地对中间结果进行分析并得到最终的统计结果,。
对存储引擎为memory的表进行更新操作要谨慎,因为数据并没有实际写入到磁盘中,
所以一定要对下次重新启动服务后如何获得这些修改后的数据有所考虑。
(4)MERGE存储引擎
Merge存储引擎是一组MyISAM表的组合,这些MyISAM表必须结构完全相同,merge表本身并没有数据,
对merge类型的表可以进行查询,更新,删除操作,这些操作实际上是对内部的MyISAM表进行的。
175. 说一下 MySQL 的行锁和表锁?
表锁:偏向MyISAM存储引擎,开销小,加锁快,无死锁,锁定粒度大,发送锁冲突的概率最高,并发度最低
结论:读锁会阻塞写,写锁会阻塞读和写
对MyISAM表的读操作,不会阻塞其它进程对同一表的读请求,但会阻塞对同一表的写请求。
只有当读锁释放后,才会执行其它进程的写操作。
对MyISAM表的写操作,会阻塞其它进程对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。
MyISAM不适合做写为主表的引擎,因为写锁后,其它线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞
行锁:偏向InnoDB存储引擎,开销大,加锁慢,会出现死锁,锁定粒度小,发送锁冲突的概率最低,并发度也最高
当选中某一行时,如果是通过主键或者索引选中的,这个时候是行级锁;如果是通过其它条件选中的,这个时候行级锁会升级成表锁,
其它事务无法对当前表进行更新或插入操作
适用范围:
A用户消费,service层先查询该用户的账户余额,若余额足够,则进行后续的扣款操作;
这种情况查询的时候应该对该记录进行加锁
否则,B用户在A用户查询后消费前先一步将A用户账号上的钱转走,而此时A用户已经进行了用户余额是否足够的判断,
则可能会出现余额已经不足但却扣款成功的情况
为了避免此情况,需要在A用户操作该记录的时候进行for update加锁
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;
对于键值在条件范围内并不存在的记录,叫做间隙
InnoDB也会对这个"间隙"加锁,这种锁机制就是所谓的间隙锁
优化建议:
尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁
合理设计索引,尽量缩小锁的范围
尽可能减少索引条件,避免间隙锁
尽量控制事务大小,减少锁定资源量和时间长度
尽可能低级别事务隔离
176. 说一下乐观锁和悲观锁?
何谓悲观锁与乐观锁
乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展。
这两种人各有优缺点,不能不以场景而定说一种人好于另外一种人。
悲观锁
总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,
这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。
传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
乐观锁
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,
但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。
乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。
在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。
两种锁的使用场景
从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景),
即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果是多写的情况,一般会经常产生冲突,
这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。
乐观锁常见的两种实现方式
乐观锁一般会使用版本号机制或CAS算法实现。
1. 版本号机制
一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。
当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,
若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。
2. CAS算法
即compare and swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,
也就是在没有线程被阻塞的情况下实现变量的同步,
所以也叫非阻塞同步(Non-blocking Synchronization)。CAS算法涉及到三个操作数
需要读写的内存值 V
进行比较的值 A
拟写入的新值 B
当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。
一般情况下是一个自旋操作,即不断的重试。
乐观锁的缺点:
ABA 问题是乐观锁一个常见的问题
1 ABA 问题
如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,
那我们就能说明它的值没有被其他线程修改过了吗?
很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回A,那CAS操作就会误认为它从来没有被修改过。
这个问题被称为CAS操作的 "ABA"问题。
JDK 1.5 以后的 AtomicStampedReference 类就提供了此种能力,
其中的 compareAndSet 方法就是首先检查当前引用是否等于预期引用,
并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
2 循环时间长开销大
自旋CAS(也就是不成功就一直循环执行直到成功)如果长时间不成功,会给CPU带来非常大的执行开销。
如果JVM能支持处理器提供的pause指令那么效率会有一定的提升,pause指令有两个作用,
第一它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,
在一些处理器上延迟时间是零。第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation)
而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率。
3 只能保证一个共享变量的原子操作
CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时 CAS 无效。但是从 JDK 1.5开始,
提供了AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行 CAS 操作.
所以我们可以使用锁或者利用AtomicReference类把多个共享变量合并成一个共享变量来操作。
CAS与synchronized的使用情景
简单的来说CAS适用于写比较少的情况下(多读场景,冲突一般较少),
synchronized适用于写比较多的情况下(多写场景,冲突一般较多)
对于资源竞争较少(线程冲突较轻)的情况,
使用synchronized同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源;
而CAS基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能。
对于资源竞争严重(线程冲突严重)的情况,CAS自旋的概率会比较大,从而浪费更多的CPU资源,效率低于synchronized。
补充: Java并发编程这个领域中synchronized关键字一直都是元老级的角色,很久之前很多人都会称它为 “重量级锁” 。
但是,在JavaSE 1.6之后进行了主要包括为了减少获得锁和释放锁带来的性能消耗而引入的 偏向锁 和 轻量级锁
以及其它各种优化之后变得在某些情况下并不是那么重了。synchronized的底层实现主要依靠 Lock-Free 的队列,基本思路是
自旋后阻塞,竞争切换后继续竞争锁,稍微牺牲了公平性,但获得了高吞吐量。
在线程冲突较少的情况下,可以获得和CAS类似的性能;
而线程冲突严重的情况下,性能远高于CAS。
177. MySQL 问题排查都有哪些手段?
使用 show processlist 命令查看当前所有连接信息。
使用 explain 命令查询 SQL 语句执行计划。
开启慢查询日志,查看慢查询的 SQL。
178. 如何做 MySQL 的性能优化?
为搜索字段创建索引。
避免使用 select *,列出需要查询的字段。
垂直分割分表。
选择正确的存储引擎。
Redis
179. Redis 是什么?都有哪些使用场景?
Redis是一个高性能的key-value数据库。
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。