锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

java面试整理(+Redis21问)

时间:2022-10-26 17:30:01 影响fpc连接器性能的四因素

一、了解集群、分布式、微服务

集群是一种物理形式,分布式是一种工作方式。

分布式:一个业务分拆多个子业务,部署在不同的服务器上

集群:同一业务部署在多个服务器上

2.分布式是指在不同的地方分布不同的业务。集群是指将多个服务器集中在一起,实现相同的业务。

每个分布式节点都完成不同的业务。如果一个节点崩溃,业务将无法访问。分布式是为了缩短单个任务的执行时间,提高效率,而集群是为了提高单位时间内执行的任务数量。

集群可以作为分布式节点。集群不一定是分布式的。

例如:例如,新浪网络,访问者更多,他可以做一个集合,在响应服务器的前面,几个服务器完成同一业务,如果有业务访问,响应服务器看到哪个服务器负载不是很重,将完成哪个。

从狭窄的意义上看,分布式类似于集群,但其组织相对松散。与集群不同,它有一个组织。如果一个服务器崩溃,其他服务器可以顶部。

3.微服务通过接口将模块分成独立的服务单元,实现数据交互。将系统分成小服务,技术团队通过技术选择独立开发和部署运营各服务。

微服务将单个应用程序分为一组小服务。在每个服务独立运行的过程中,服务相互协调,为用户提供最终价值。

轻量级通信机制在服务之间相互沟通(通常基于 HTTP 的 RESTful API) 。每一项服务都围绕着特定的业务建设,并能独立部署到生产环境、类生产环境等。

二、springboot自动化配置

@SpringBootApplication它包含三个注释

@SpringBootConfiguration

@EnableAutoConfiguration

@ComponentScan

@SpringBootConfiguration:目前的标记类别是配置类。

@EnableAutoConfiguration:打开自动配置,使用AutoConfigurationImportSelector将某些组件导入容器。

@ComponentScan:扫描主类所在的同级包和下级包Bean,组件扫描和自动组装。

关键是@EnableAutoConfiguration。

@AutoConfigurationPackage

@Import({AutoConfigurationImportSelector.class})

三、springcloud组件

SpringCloud分布式开发五个组件详解

服务发现——Netflix Eureka

客户服务端负载均衡——Netflix Ribbon

断路器——Netflix Hystrix,SOA工具/框架在微服务架构中提供服务隔离、熔断和降级机制。Netflix Hystrix高微服务架构的可用性是断路器的实现,是防止服务雪崩的利器。

服务网关——Netflix Zuul

分布式配置——Spring Cloud Config

四、常见负载均衡策略

1、轮询法

要求按顺序轮流分配到后端服务器,它平衡地对待每个后端服务器,而不关心服务器的实际连接数和当前的系统负载。

轮询算法是最简单的负载平衡算法。其原理是将用户的请求轮流分配给内部服务器:从服务器1到服务器N,然后重新开始循环。

算法的优点是简洁,不需要记录所有当前连接的状态,所以是无状态调度。

如果后端服务器按时间顺序分配到不同的后端服务器,每个请求都会按时间顺序分配down掉下来,可以自动去除。

2、随机法

通过系统的随机算法,根据后端服务器的列表值随机选择其中一个服务器进行访问。从概率统计理论可以看出,随着客户端呼叫服务器数量的增加,实际效果越来越接近后端每个服务器的平均分即轮询的结果。

哈希法,源地址

哈希源地址的理念是基于获取客户端IP地址,通过哈希函数计算的一个值,用该值计算服务器列表的大小,结果是客户服务端访问服务器的序列号。采用源地址哈希法平衡负载,相同IP当后端服务器列表不变时,地址的客户端每次都会映射到同一个后端服务器进行访问。

每个请求按访问进行ip的hash结果分配,使每个访问者能够固定地访问后端服务器session的问题。

4.加权轮询法

不同的后端服务器可能置可能与当前系统的负载不同,因此其抗压能力也不同。为配置高负荷、低负荷的机器配置更高的权重,以便处理更多的请求;配置低负荷、低负荷的机器分配较低的权重,减少系统负荷,加权轮询可以很好地处理这个问题,并根据权重将请求顺序分配到后端。

5、加权随机法

与加权轮询法一样,加权随机法也根据后端机器的配置和系统的负载分配不同的权重。不同之处在于,后端服务器是根据权重随机要求的,而不是顺序。

6.最小连接数法

最小连接算法灵活智能,由于后端服务器配置不同,请求处理快慢,根据后端服务器当前连接,动态选择当前积压连接最少的服务器处理当前请求,尽可能提高后端服务的利用效率,负责合理转移到各服务器。

五、spring的理解

1、spring原理

spring它是按照设计模式精心制作的,实现了工厂模式的工厂类别,这个类别叫做BeanFactory(接口)通常用于程序中的子类ApplicationContext(也是接口)。

spring的核心是IOC(反转控制)容器,IOC实现模块之间的解耦也是一种编程思想Spring其作用是控制对象的创建、维护和销毁等生命周期。IOC:给予对象的创建、初始化和销毁spring管理,而不是由开发由开发者控制。

spring大工厂类,spring其特点是基于配置,通过元素在其配置文件中创建实例对象。

根据业务逻辑,对象往往不是独立的,一个对象的创建往往涉及到另一个对象的创建,当然,这个对象也应该由IOC负责容器的方式是依靠注入DI,通过反射机制实现。

(1)接口注入(2)结构器注入(3)Setter方法注入。

2.spring的核心技术

spring核心技术有:IOC,AOP

java 的 高级特性:反射机制,代理

IOC:依赖注入,就是原因IOC在运行过程中,容器动态地将某种依赖某种依赖关系。

AOP:对于切面编程,系统中有许多不相关的方法,如添加日志、权限判断等。AOP横切关注点(如日志、安全、缓存和事务管理)与受影响的对象之间的解耦。

实现AOP 该功能采用代理技术,调用代理类,代理类与目标类相同。

AOP 在spring中主要表现在两个方面:提供声明式的事务管理 、spring支持用户定制截面。在此,我推荐一个架构学习交流圈。交流学习伪欣:1253431195(有大量的面试问题和答案)将分享一些资深架构师录制的视频:Spring,MyBatis,Netty高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等已成为架构师必备的知识体系。还可以获得免费的学习资源,目前受益匪浅

AOP主要包括通知(Advice)切点(PointCut)连接点(JoinPoint)

AspectJ实际上是对AOP编程思想的实践

3、spring 优缺点

Spring核心概念是IOC和AOP,这两个核心服务的对象是bean(POJO)。

它具备以下优点:

spring避免关键词new耦合问题。

spring本身就是工厂,不需要再写工厂类了。

spring无需明确引用关系的传递,通过配置直接完成

几乎所有的框架都可以spring一起使用中集成。

spring编程=factory设计模式 proxy设计模式

当然,它也有很多缺点:

spring基于大量的xml 配置文件,使我们在配置上花费了大量的时间,减缓了开发进度,springboot 提倡代码优于配置来解决问题。

spring内容太大,随便打断点查看时会出现十几二十层代码,阅读性不强。

六、jdk动态代理和cglib代理的区别

JDK动态代理只能生成实现接口的代理,而不是针对类别

CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)

Spring在选择用JDK还是CGLiB的依据:

(1)当Bean实现接口时,Spring就会用JDK的动态代理(java.lang.reflect.Proxy类代理)

优点:由于接口,系统更松耦合

缺点:为每个目标类创建界面

(2)当Bean接口未实现时,Spring使用CGlib

优点:由于代理类和目标类是继承关系,因此不需要有界面。

缺点:由于没有接口,因此没有系统的耦合JDK的动态代理好。

(3)可强制使用CGlib(在spring配置中加入

CGlib比JDK快?

(1)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

(2)在对JDK动态代理与CGlib动态代理的代码实验中看,1W次执行下,JDK7及8的动态代理性能比CGlib要好20%左右。

七、HashMap底层(待完善)

在JDK1.6,JDK1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,HashMap采用位桶+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。

HashMap采用Entry数组来存储key-value对,每一个键值对组成了一个Entry实体,Entry类实际上是一个单向的链表结构,它具有Next指针,可以连接下一个Entry实体,依次来解决Hash冲突的问题,因为HashMap是按照Key的hash值来计算Entry在HashMap中存储的位置的,如果hash值相同,而key内容不相等,那么就用链表来解决这种hash冲突。

HashMap初始容量16,每次扩容的次数是2倍。

1.HashMap jdk 1.8有哪些变化:

在jdk1.6,jdk1.7 中HashMap 采用 位桶+链表 方式

jdk1.8 中采用 位桶 + 链表 + 红黑树 方式(当链表大于8的时候转换为红黑树)优势:查询性能得都很大提升。

2.什么是红黑树,优势劣势:

红黑树是平衡二叉树的一种算法提现(AVL、Treap…),它有很多限制组成,其中包括

(1).每个节点不是红色就是黑色。

(2).跟节点永远是黑色。

(3).所有叶子节点都是黑色。

(4).每个叶子不会有两个连续的节点。

(5).从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点。中和来说 红黑树中最长路径就是一条红黑交替的路径。(可以多维度去理解它在内存中的位置区间)在此我向大家推荐一个架构学习交流圈。交流学习伪鑫:1253431195(里面有大量的面试题及答案)里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

优劣势:优点,由于限制所以红黑树的深度不像二叉树那么深,只要保持平衡,它的检索性能比较高。

缺点,红黑树在进行插入或删除操作的时候由于需要维护红黑树的特点,所以需要提供树结构维护。

  1. HashMap描述

(1). Hash索引的计算,根据HashMap 长度计算与计算出的hashCode值做位于运算决定索引/位置(结论:长度取2次方是减少冲突的最好方式)

(2). Hash冲突 hashMap使用链表发解决冲突,当发生冲突的时候将key/vlaue放在该位置的链表末端。

八、mysql隔离级别

mysql默认隔离级别repeatable可重复读,oracle,sql server默认隔离级别read commited读取提交内容

事务的 四个特征(ACID)

事务具有四个特征:原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持续性( Durability )。这四个特性简称为 ACID 特性。

1 、原子性。事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做

2 、一致性。事 务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。

3 、隔离性。一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。

4 、持续性。也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。

Mysql的四种隔离级别

SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。

Read Uncommitted(读取未提交内容)

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。

Read Committed(读取提交内容)

这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

Repeatable Read(可重读)

这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

Serializable(可串行化)

这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享。在这个级别,可能导致大量的超时现象和锁竞争。在此我向大家推荐一个架构学习交流圈。交流学习伪鑫:1253431195(里面有大量的面试题及答案)里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

出现问题

这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如:

脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。

不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。

幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。

在MySQL中,实现了这四种隔离级别,分别有可能产生问题如下所示:

九、Hibernate 和Mybatis

1 简单简介

1.1 Hibernate 框架

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,建立对象与数据库表的映射。是一个全自动的、完全面向对象的持久层框架。

1.2 Mybatis框架

Mybatis是一个开源对象关系映射框架,原名:ibatis,2010年由谷歌接管以后更名。是一个半自动化的持久层框架。

2 两者区别

2.1 开发方面

在项目开发过程当中,就速度而言:

hibernate开发中,sql语句已经被封装,直接可以使用,加快系统开发;

Mybatis 属于半自动化,sql需要手工完成,稍微繁琐;

但是,凡事都不是绝对的,如果对于庞大复杂的系统项目来说,发杂语句较多,选择hibernate 就不是一个好方案。

2.2 sql优化方面

Hibernate 自动生成sql,有些语句较为繁琐,会多消耗一些性能;

Mybatis 手动编写sql,可以避免不需要的查询,提高系统性能;

2.3 对象管理比对

Hibernate 是完整的对象-关系映射的框架,开发工程中,无需过多关注底层实现,只要去管理对象即可;

Mybatis 需要自行管理 映射关系;

2.4 缓存方面

相同点:

Hibernate和Mybatis的二级缓存除了采用系统默认的缓存机制外,都可以通过实现你自己的缓存或为其他第三方缓 存方案,创建适配器来完全覆盖缓存行为。

不同点:

Hibernate的二级缓存配置在SessionFactory生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置是那种缓存。

MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。

比较:

Hibernate 具有良好的管理机制,用户不需要关注SQL,如果二级缓存出现脏数据,系统会保存,;

Mybatis 在使用的时候要谨慎,避免缓存Cache 的使用。

Hibernate优势

Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。

Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。

Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。

Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。

Mybatis优势

MyBatis可以进行更为细致的SQL优化,可以减少查询字段。

MyBatis容易掌握,而Hibernate门槛较高。

一句话总结

Mybatis:小巧、方便、高效、简单、直接、半自动化

Hibernate:强大、方便、高效、复杂、间接、全自动化

mybatis缓存问题

#使全局的映射器启用或禁用缓存。

mybatis.configuration.cache-enabled=true

#全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。

mybatis.configuration.lazy-loading-enabled=true

#当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。

mybatis.configuration.aggressive-lazy-loading=true

十、Redis21问

1.什么是 redis?

Redis 是一个基于内存的高性能 key-value 数据库。

2.Reids 的特点

Redis 本质上是一个 Key-Value 类型的内存数据库,很像 memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据 flush 到硬盘上进行保存。因为是纯内存操作,Redis 的性能非常出色,每秒可以处理超过 10 万次读写操作,是已知性能最快的 Key-Value DB。

Redis 的出色之处不仅仅是性能,Redis 最大的魅力是支持保存多种数据结构,此外单个 value 的最大限制是 1GB,不像 memcached 只能保存 1MB 的数据,因此 Redis 可以用来实现很多有用的功能,比方说用他的 List 来做 FIFO 双向链表,实现一个轻量级的高性 能消息队列服务,用他的 Set 可以做高性能的 tag 系统等等。另外 Redis 也可以对存入的 Key-Value 设置 expire 时间,因此也可以被当作一 个功能加强版的 memcached 来用。

Redis 的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此 Redis 适合的场景主要局限在较小数据量的高性能操作和运算上。

3.使用 redis 有哪些好处?

1.速度快,因为数据存在内存中,类似于 HashMap,HashMap 的优势就是查找和操作的时间复杂度都是 O(1)

2.支持丰富数据类型,支持 string,list,set,sorted set,hash

1)String

常用命令:set/get/decr/incr/mget 等;

应用场景:String 是最常用的一种数据类型,普通的 key/value 存储都可以归为此类;

实现方式:String 在 redis 内部存储默认就是一个字符串,被 redisObject 所引用,当遇到 incr、decr 等操作时会转成数值型进行计算,此时 redisObject 的 encoding 字段为 int。

2)Hash

常用命令:hget/hset/hgetall 等

应用场景:我们要存储一个用户信息对象数据,其中包括用户 ID、用户姓名、年龄和生日,通过用户 ID 我们希望获取该用户的姓名或者年龄或者生日;

实现方式:Redis 的 Hash 实际是内部存储的 Value 为一个 HashMap,并提供了直接存取这个 Map 成员的接口。Key 是用户 ID, value 是一个 Map。这个 Map 的 key 是成员的属性名,value 是属性值。这样对数据的修改和存取都可以直接通过其内部 Map 的 Key(Redis 里称内部 Map 的 key 为 field), 也就是通过 key(用户 ID) + field(属性标签) 就可以操作对应属性数据。

当前 HashMap 的实现有两种方式:当 HashMap 的成员比较少时 Redis 为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的 HashMap 结构,这时对应的 value 的 redisObject 的 encoding 为 zipmap,当成员数量增大时会自动转成真正的 HashMap,此时 encoding 为 ht。

3)List

常用命令:lpush/rpush/lpop/rpop/lrange 等;

应用场景:Redis list 的应用场景非常多,也是 Redis 最重要的数据结构之一,比如 twitter 的关注列表,粉丝列表等都可以用 Redis 的 list 结构来实现;

实现方式:Redis list 的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis 内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。

4)Set

常用命令:sadd/spop/smembers/sunion 等;

应用场景:Redis set 对外提供的功能与 list 类似是一个列表的功能,特殊之处在于 set 是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set 是一个很好的选择,并且 set 提供了判断某个成员是否在一个 set 集合内的重要接口,这个也是 list 所不能提供的;

实现方式:set 的内部实现是一个 value 永远为 null 的 HashMap,实际就是通过计算 hash 的方式来快速排重的,这也是 set 能提供判断一个成员是否在集合内的原因。

5)Sorted Set

常用命令:zadd/zrange/zrem/zcard 等;

应用场景:Redis sorted set 的使用场景与 set 类似,区别是 set 不是自动有序的,而 sorted set 可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择 sorted set 数据结构,比如 twitter 的 public timeline 可以以发表时间作为 score 来存储,这样获取时就是自动按时间排好序的。

实现方式:Redis sorted set 的内部使用 HashMap 和跳跃表(SkipList)来保证数据的存储和有序,HashMap 里放的是成员到 score 的映射,而跳跃表里存放的是所有的成员,排序依据是 HashMap 里存的 score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。

3.支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行

4.丰富的特性:可用于缓存,消息,按 key 设置过期时间,过期后将会自动删除

4.redis 相比 memcached 有哪些优势?

◎memcached 所有的值均是简单的字符串,redis 作为其替代者,支持更为丰富的数据类型

◎ redis 的速度比 memcached 快很多

◎ redis 可以持久化其数据

5.Memcache 与 Redis 的区别都有哪些?

◎ 存储方式 Memecache 把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。Redis 有部份存在硬盘上,这样能保证数据的持久性。

◎ 数据支持类型 Memcache 对数据类型支持相对简单。Redis 有复杂的数据类型。

◎ 使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。Redis 直接自己构建了 VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。

6.redis 适用于的场景?

Redis 最适合所有数据 in-momory 的场景,如:

1.会话缓存(Session Cache)

最常用的一种使用 Redis 的情景是会话缓存(session cache)。用 Redis 缓存会话比其他存储(如 Memcached)的优势在于:Redis 提供持久化。

2.全页缓存(FPC)

除基本的会话 token 之外,Redis 还提供很简便的 FPC 平台。回到一致性问题,即使重启了 Redis 实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似 PHP 本地 FPC。

3.队列

Reids 在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得 Redis 能作为一个很好的消息队列平台来使用。Redis 作为队列使用的操作,就类似于本地程序语言(如 Python)对 list 的 push/pop 操作。

如果你快速的在 Google 中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用 Redis 创建非常好的后端工具,以满足各种队列需求。例如,Celery 有一个后台就是使用 Redis 作为 broker,你可以从这里去查看。

4.排行榜/计数器

Redis 在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis 只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的 10 个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可:

当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:

ZRANGE user_scores 0 10 WITHSCORES

Agora Games 就是一个很好的例子,用 Ruby 实现的,它的排行榜就是使用 Redis 来存储数据的,你可以在这里看到。

5.发布/订阅

最后(但肯定不是最不重要的)是 Redis 的发布/订阅功能。发布/订阅的使用场景确实非常多。

7、redis 的缓存失效策略和主键失效机制

作为缓存系统都要定期清理无效数据,就需要一个主键失效和淘汰策略.

在 Redis 当中,有生存期的 key 被称为 volatile。在创建缓存时,要为给定的 key 设置生存期,当 key 过期的时候(生存期为 0),它可能会被删除。

1、影响生存时间的一些操作

生存时间可以通过使用 DEL 命令来删除整个 key 来移除,或者被 SET 和 GETSET 命令覆盖原来的数据,也就是说,修改 key 对应的 value 和使用另外相同的 key 和 value 来覆盖以后,当前数据的生存时间不同。

比如说,对一个 key 执行 INCR 命令,对一个列表进行 LPUSH 命令,或者对一个哈希表执行 HSET 命令,这类操作都不会修改 key 本身的生存时间。另一方面,如果使用 RENAME 对一个 key 进行改名,那么改名后的 key 的生存时间和改名前一样。

RENAME 命令的另一种可能是,尝试将一个带生存时间的 key 改名成另一个带生存时间的 another_key ,这时旧的 another_key (以及它的生存时间)会被删除,然后旧的 key 会改名为 another_key ,因此,新的 another_key 的生存时间也和原本的 key 一样。使用 PERSIST 命令可以在不删除 key 的情况下,移除 key 的生存时间,让 key 重新成为一个 persistent key 。

2、如何更新生存时间

可以对一个已经带有生存时间的 key 执行 EXPIRE 命令,新指定的生存时间会取代旧的生存时间。过期时间的精度已经被控制在 1ms 之内,主键失效的时间复杂度是 O(1),EXPIRE 和 TTL 命令搭配使用,TTL 可以查看 key 的当前生存时间。设置成功返回 1;当 key 不存在或者不能为 key 设置生存时间时,返回 0 。

最大缓存配置,在 redis 中,允许用户设置最大使用内存大小

server.maxmemory 默认为 0,没有指定最大缓存,如果有新的数据添加,超过最大内存,则会使 redis 崩溃,所以一定要设置。redis 内存数据集大小上升到一定大小的时候,就会实行数据淘汰策略。

redis 提供 6 种数据淘汰策略:

◎ volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

◎ volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

◎ volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

◎ allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

◎ allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

◎ no-enviction(驱逐):禁止驱逐数据

注意这里的 6 种机制,volatile 和 allkeys 规定了是对已设置过期时间的数据集淘汰数据还是从全部数据集淘汰数据,后面的 lru、ttl 以及 random 是三种不同的淘汰策略,再加上一种 no-enviction 永不回收的策略。

使用策略规则:

◎ 如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用 allkeys-lru

◎ 如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用 allkeys-random

三种数据淘汰策略:

ttl 和 random 比较容易理解,实现也会比较简单。主要是 Lru 最近最少使用淘汰策略,设计上会对 key 按失效时间排序,然后取最先失效的 key 进行淘汰

8.为什么 redis 需要把所有数据放到内存中?

Redis 为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以 redis 具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘 I/O 速度为严重影响 redis 的性能。在内存越来越便宜的今天,redis 将会越来越受欢迎。

如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。

9.Redis 是单进程单线程的

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

10.redis 的并发竞争问题如何解决?

Redis 为单进程单线程模式,采用队列模式将并发访问变为串行访问。Redis 本身没有锁的概念,Redis 对于多个客户端连接并不存在竞争,但是在 Jedis 客户端对 Redis 进行并发访问时会发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成。对此有 2 种解决方法:

1、客户端角度,为保证每个客户端间正常有序与 Redis 进行通信,对连接进行池化,同时对客户端读写 Redis 操作采用内部锁 synchronized。

2、服务器角度,利用 setnx 实现锁。

注:对于第一种,需要应用程序自己处理资源的同步,可以使用的方法比较通俗,可以使用 synchronized 也可以使用 lock;第二种需要用到 Redis 的 setnx 命令,但是需要注意一些问题。

11、redis 常见性能问题和解决方案:

1.Master 写内存快照,save 命令调度 rdbSave 函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以 Master 最好不要写内存快照。

2.Master AOF 持久化,如果不重写 AOF 文件,这个持久化方式对性能的影响是最小的,但是 AOF 文件会不断增大,AOF 文件过大会影响 Master 重启的恢复速度。Master 最好不要做任何持久化工作,包括内存快照和 AOF 日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个 Slave 开启 AOF 备份数据,策略为每秒同步一次。

3.Master 调用 BGREWRITEAOF 重写 AOF 文件,AOF 在重写的时候会占大量的 CPU 和内存资源,导致服务 load 过高,出现短暂服务暂停现象。

4.Redis 主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave 和 Master 最好在同一个局域网内。

12.redis 事务的了解 CAS(check-and-set 操作实现乐观锁 )?

和众多其它数据库一样,Redis 作为 NoSQL 数据库也同样提供了事务机制。在 Redis 中,MULTI/EXEC/DISCARD/WATCH 这四个命令是我们实现事务的基石。相信对有关系型数据库开发经验的开发者而言这一概念并不陌生,即便如此,我们还是会简要的列出 Redis 中事务的实现特征:

1). 在事务中的所有命令都将会被串行化的顺序执行,事务执行期间,Redis 不会再为其它客户端的请求提供任何服务,从而保证了事物中的所有命令被原子的执行。

2). 和关系型数据库中的事务相比,在 Redis 事务中如果有某一条命令执行失败,其后的命令仍然会被继续执行。

3). 我们可以通过 MULTI 命令开启一个事务,有关系型数据库开发经验的人可以将其理解为"BEGIN TRANSACTION"语句。在该语句之后执行的命令都将被视为事务之内的操作,最后我们可以通过执行 EXEC/DISCARD 命令来提交/回滚该事务内的所有操作。这两个 Redis 命令可被视为等同于关系型数据库中的 COMMIT/ROLLBACK 语句。

4). 在事务开启之前,如果客户端与服务器之间出现通讯故障并导致网络断开,其后所有待执行的语句都将不会被服务器执行。然而如果网络中断事件是发生在客户端执行 EXEC 命令之后,那么该事务中的所有命令都会被服务器执行。

5). 当使用 Append-Only 模式时,Redis 会通过调用系统函数 write 将该事务内的所有写操作在本次调用中全部写入磁盘。然而如果在写入的过程中出现系统崩溃,如电源故障导致的宕机,那么此时也许只有部分数据被写入到磁盘,而另外一部分数据却已经丢失。Redis 服务器会在重新启动时执行一系列必要的一致性检测,一旦发现类似问题,就会立即退出并给出相应的错误提示。此时,我们就要充分利用 Redis 工具包中提供的 redis-check-aof 工具,该工具可以帮助我们定位到数据不一致的错误,并将已经写入的部分数据进行回滚。修复之后我们就可以再次重新启动 Redis 服务器了。

13.WATCH 命令和基于 CAS 的乐观锁?

在 Redis 的事务中,WATCH 命令可用于提供 CAS(check-and-set)功能。假设我们通过 WATCH 命令在事务执行之前监控了多个 Keys,倘若在 WATCH 之后有任何 Key 的值发生了变化,EXEC 命令执行的事务都将被放弃,同时返回 Null multi-bulk 应答以通知调用者事务执行失败。例如,我们再次假设 Redis 中并未提供 incr 命令来完成键值的原子性递增,如果要实现该功能,我们只能自行编写相应的代码。

其伪码如下:

val = GET mykey

val = val + 1

SET mykey $val

以上代码只有在单连接的情况下才可以保证执行结果是正确的,因为如果在同一时刻有多个客户端在同时执行该段代码,那么就会出现多线程程序中经常出现的一种错误场景–竞态争用(race condition)。

比如,客户端 A 和 B 都在同一时刻读取了 mykey 的原有值,假设该值为 10,此后两个客户端又均将该值加一后 set 回 Redis 服务器,这样就会导致 mykey 的结果为 11,而不是我们认为的 12。为了解决类似的问题,我们需要借助 WATCH 命令的帮助,见如下代码:

WATCH mykey

val = GET mykey

val = val + 1

MULTI

SET mykey $val

EXEC

和此前代码不同的是,新代码在获取 mykey 的值之前先通过 WATCH 命令监控了该键,此后又将 set 命令包围在事务中,这样就可以有效的保证每个连接在执行 EXEC 之前,如果当前连接获取的 mykey 的值被其它连接的客户端修改,那么当前连接的 EXEC 命令将执行失败。这样调用者在判断返回值后就可以获悉 val 是否被重新设置成功。

14.使用过 Redis 分布式锁么,它是什么回事?

先拿 setnx 来争抢锁,抢到之后,再用 expire 给锁加一个过期时间防止锁忘记了释放。

这时候对方会告诉你说你回答得不错,然后接着问如果在 setnx 之后执行 expire 之前进程意外 crash 或者要重启维护了,那会怎么样?

这时候你要给予惊讶的反馈:唉,是喔,这个锁就永远得不到释放了。紧接着你需要抓一抓自己得脑袋,故作思考片刻,好像接下来的结果是你主动思考出来的,然后回答:我记得 set 指令有非常复杂的参数,这个应该是可以同时把 setnx 和 expire 合成一条指令来用的!对方这时会显露笑容,心里开始默念:摁,这小子还不错。

15.假如 Redis 里面有 1 亿个 key,其中有 10w 个 key 是以某个固定的已知的前缀开头的,如果将它们全部找出来?

使用 keys 指令可以扫出指定模式的 key 列表。

对方接着追问:如果这个 redis 正在给线上的业务提供服务,那使用 keys 指令会有什么问题?

这个时候你要回答 redis 关键的一个特性:redis 的单线程的。keys 指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用 scan 指令,scan 指令可以无阻塞的提取出指定模式的 key 列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用 keys 指令长。

16.使用过 Redis 做异步队列么,你是怎么用的?

一般使用 list 结构作为队列,rpush 生产消息,lpop 消费消息。当 lpop 没有消息的时候,要适当 sleep 一会再重试。

如果对方追问可不可以不用 sleep 呢?list 还有个指令叫 blpop,在没有消息的时候,它会阻塞住直到消息到来。

如果对方追问能不能生产一次消费多次呢?使用 pub/sub 主题订阅者模式,可以实现 1:N 的消息队列。

如果对方追问 pub/sub 有什么缺点?在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如 rabbitmq 等。

如果对方追问 redis 如何实现延时队列?我估计现在你很想把面试官一棒打死如果你手上有一根棒球棍的话,怎么问的这么详细。但是你很克制,然后神态自若的回答道:使用 sortedset,拿时间戳作为 score,消息内容作为 key 调用 zadd 来生产消息,消费者用 zrangebyscore 指令获取 N 秒之前的数据轮询进行处理。

到这里,面试官暗地里已经对你竖起了大拇指。但是他不知道的是此刻你却竖起了中指,在椅子背后。

17.如果有大量的 key 需要设置同一时间过期,一般需要注意什么?

如果大量的 key 过期时间设置的过于集中,到过期的那个时间点,redis 可能会出现短暂的卡顿现象。一般需要在时间上加一个随机值,使得过期时间分散一些。

18.Redis 如何做持久化的?

bgsave 做镜像全量持久化,aof 做增量持久化。因为 bgsave 会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要 aof 来配合使用。在 redis 实例重启时,会使用 bgsave 持久化文件重新构建内存,再使用 aof 重放近期的操作指令来实现完整恢复重启之前的状态。

对方追问那如果突然机器掉电会怎样?取决于 aof 日志 sync 属性的配置,如果不要求性能,在每条写指令时都 sync 一下磁盘,就不会丢失数据。但是在高性能的要求下每次都 sync 是不现实的,一般都使用定时 sync,比如 1s1 次,这个时候最多就会丢失 1s 的数据。

对方追问 bgsave 的原理是什么?你给出两个词汇就可以了,fork 和 cow。fork 是指 redis 通过创建子进程来进行 bgsave 操作,cow 指的是 copy on write,子进程创建后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。

19.Pipeline 有什么好处,为什么要用 pipeline?

可以将多次 IO 往返的时间缩减为一次,前提是 pipeline 执行的指令之间没有因果相关性。使用 redis-benchmark 进行压测的时候可以发现影响 redis 的 QPS 峰值的一个重要因素是 pipeline 批次指令的数目。

20.Redis 的同步机制了解么?

Redis 可以使用主从同步,从从同步。第一次同步时,主节点做一次 bgsave,并同时将后续修改操作记录到内存 buffer,待完成后将 rdb 文件全量同步到复制节点,复制节点接受完成后将 rdb 镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。

21.是否使用过 Redis 集群,集群的原理是什么?

Redis Sentinal 着眼于高可用,在 master 宕机时会自动将 slave 提升为 master,继续提供服务。

Redis Cluster 着眼于扩展性,在单个 redis 内存不足时,使用 Cluster 进行分片存储。

————————————————
image.png

阿里面试面试题:链接:https://pan.baidu.com/s/1ryi6EMUEjZvlaRGEnipryw
提取码:tn3g

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章