Java面试简易版

自我介绍

我毕业后干了一段时间本专业,后来发觉还是对编程感兴趣,就通过同学介绍去北京蚂蚁工匠公司,我⽬前有1年半的⼯作经验,在上⼀个公司我参与了本地商铺微信小程序和一个分布式电⼦交易系统和,主要负项⽬的商品和秒杀模块发开。分布式项目使用Dubbo微服务分布式框架设计,Zookeeper作为注册中心,同时使用RocketMQ做的事务优化,确保数据可靠性。离开上⼀家公司是因为主要还是在想要回到山东发展。

Java SE和JAVA EE的区别

JavaSE:java标准版,就是一般Java程序的开发就可以,可以看做是JavaEE的子集。它允许开发和部署在桌面,服务器 ,嵌入式环境和实施环境中使用的java应用程序。

JavaEE:java企业版,多用于企业级开发, 包括web开发等。

Java内存模型 堆和栈上存储什么

堆:存放由new创建的对象实例和数组。

栈:存的是堆内存空间的访问地址

Java对象的生命周期

  1. 创建阶段(Created)

  2. 应用阶段(In Use)

  3. 不可见阶段(Invisible)

  4. 不可达阶段(Unreachable)

  5. 收集阶段(Collected)

  6. 终结阶段(Finalized)

  7. 对象空间重分配阶段(De-allocated)

GC垃圾回收

确定垃圾:

①引用计数法:给堆中的每一个对象增加一个引用计数器,有一个地方引用这个对象时,就将计数器加1,引用失效时,计数器就减1。引用计数器为0,回收。

②根搜索算法:依据该对象能否访问到,为依据判断,以GC Root的对象作为起始点,从这些节点开始向下搜索。搜索所走的路径成为引用链。一个对象到GC Roots没有任何引用链相连时,回收。

GCroots可以是哪些对象?1、虚拟机栈中的引用对象;2、方法区中的静态属性引用的对象。3、方法区中的常量引用的对象;

常用的gc算法:

①标记清除算法**(Mark Sweep)**

​ 活动对象做标记,其他回收

​ 缺点:易产生内存碎片

②标记复制算法**(Copy)**

​ 堆内存被平均分成了2份,当这一块内存用完的时候,就将还存活着的对象复制到另外一块上面,然后把已经使用过的这一块一次清理掉。

​ 优点:回收后没有碎片,对于大片连续内存回收效率高,存活对象少回收效率高

​ 缺点:内存利用率低,只有50%;存储时有大量存储对象,存储效率低,因为都得复制

③标记整理算法

​ 与标记清除算法类似,只是后续步骤是让所有存活的对象移动到一端,然后直接清除掉端边界以外的内存。

分代收集算法(JVM使用)

​ 堆内存分成新生代、老年代,新生代中使用复制算法,因为对象死得快活的少。在老年代使用标记整理算法处理。新生代经历一次垃圾回收没被回收,年龄增长1,默认经历15次就转到老年代储存。

类加载过程

①加载

​ 先编译→类的全限定名→二进制字节流

​ 再加载→内存中生成这个类的java.lang.Class对象,作为方法区该类的访问入口 。

②连接(验证、准备、解析)

​ 验证-确保加载类的正确性。

​ 准备-为类静态成员分配内存设置默认初始化值

​ 解析-符号引用替换为直接引用 。

③初始化

​ 静态成员变量赋初值,执行静态代码块。

为什么类对象能避免重复加载?如何打破

通过类加载的双亲委派模型

一个类加载器收到了类加载的请求,首先把这个请求委派给父类加载器去完成,每层都是如此,最终传送到最顶的启动类加载器中,只有当它无法完成这个加载请求时,子加载器才会尝试自己去完成加载,可以防止内存中出现多份同样的字节码

打破:

1、自定义类加载器,重写loadClass方法;2、使用线程上下文类加载器;

Spring Bean的生命周期

实例化赋值(Aware接口)→(BeanPostProcessor接口 Before方法)初始化(After方法)→可用销毁

1、 调用构造器 或者是通过工厂的方式完成Bean的实例化(实例化

2、给 bean 对象内属性设置参数(通常为set方法)(属性赋值

3、若实现Aware接口,会执行对应接口的setBeanName、setBeanFactory、setApplicationContext方法设置对应属性。

4、若该ben实现了BeanPostProcessor接口,先执行 Bean 后置处理器中的 BeanpostProcess的Before方法

5、调用初始化方法,进行初始化, 初始化方法是通过 init-method 来指定的. (初始化

6、执行 Bean 后置处理器中的 BeanpostProcess的After方法

7、bean可用

8、IOC 容器关闭时, 销毁 Bean 对象(销毁

两个scope对生命周期的影响

​ 影响的是生命周期开始的时间

​ ①singleton(单例):容器初始化的时候

​ ②prototype:当你获得(getBean)这个组件的时候开始,容器关闭时没有生命周期

**Spring 为啥把bean默认设计成单例?**为了提高性能少创建实例垃圾回收缓存快速获取

Spring注解

Bean声明

@component --表明一个类会作为组件类,将bean的注入到spring容器中。衍生如下

​ @Controller(“名称”):web层

​ @Service(“名称”):service层

​ @Repository(“名称”):dao层

注入

@Autowired 对象的依赖注入

@Resource 对象的依赖注入

​ 都可以用于成员变量和方法上

不同@Autowired@Resource
注解来源Spring带的注解JDK自带
默认方式基于bean的类型去查找的,允许找不到required 属性设置false基于bean的name去查找的,找不到抛异常

配置类注解

@Configuration 声明该类为配置文件。

@Bean 声明该方法返回值为bean实例

@ComponentScan 组件扫描,可自动发现和装配一些Bean

在这里插入图片描述

在这里插入图片描述

SpringBoot注解

注解功能
@SpringBootApplication核心注解,开启Springboot 自动给程序开启组件扫描和自动配置的功能。
@EnableAutoConfiguration自动装配的核心注解
@SpringBootConfiguration(推荐)、@Configuration说明该类是配置类,并且将该类中@Bean声明的方法返回的实例纳入到spring容器中。
@ComponentScan组件扫描,可自动发现和装配一些Bean
@ConfigurationProperties(非常重要)读取配置文件application.properties的属性值
@EnableConfigurationProperties(Class)class对应的值 @ConfigurationProperties对应的类

RESTful风格?

一种软件架构风格、设计风格,而不是标准(资源在网络中以某种表现形式进行状态转移)。

主要用于客户端和服务器交互类软件。更简洁,更有层次。

URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作,通过操作资源的表现形式(XML或HTML)来操作资源,客户端与服务器端间交互请求是无状态的

servlet生命周期

Servlet是一个接口,servlet生命周期依赖servlet容器。

以tomcat为例,生命周期分为,加载—>实例化—>服务—>销毁。

接口中有init,service,destroy三个方法。

init方法,仅执行一次第一次访问当前servlet的时候,会先创建一个servlet对象,然后调用init方法。

service方法,每一次访问当前servlet,都会执行service方法,

destroy方法,当应用被卸载、tomcat服务器关闭时,执行该方法。

IOC AOP

IOC

控制反转、是⼀种设计思想,将创建对象的控制权,交由Spring框架来管理。 它像⼯⼚⼀样,当我们需要创建⼀个对象的时候,只需要配置好配置⽂件**/**注解即可,完全不⽤考虑对象是如何被创建出来的。

场景:

我们在service层想调用另外一个service的方法,不需要去new了,直接把它交给spring管理,然后用注解的方式引入就能使用。

AOP面向切面

而面向切面编程,是将一个个的对象某些类似的方面横向抽成一个切面,对这个切面进行一些如权限控制、事物管理,记录日志等公用操作处理的过程就是面向切面编程的思想。

目的:减少重复代码,降低模块间的耦合度。

AOP 底层是动态代理,如果是接口采用 JDK 动态代理,如果是类采用 CGLIB 方式实现动态代理。

作用范围:1、 动态代理:某一个委托类的全部方法。2、 AOP:容器中的组件当中的 选中的方法,更加灵活。

场景:1、⽇志管理;2、历史记录

概念:

①通知、增强处理(Advice)

切面的工作内容被称为通知。

就是你想要的功能,也就是上说的安全、事物、日子等。你给先定义好,然后再想用的地方用一下。包含Aspect的一段处理代码

连接点(JoinPoint)

就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的钱、后(两者都有也行),或抛出异常是时都可以是连接点。和方法有关的前前后后都是连接点。

③***切入点(Pointcut)***

切点来筛选连接点,只让其中几个,在调用这方法之前、之后或者抛出异常时做增强,那么就用切入点来定义这几个方法。

④***切面(Aspect)***

切面是通知和切入点的结合,通知决定增强什么内容,切入点决定在哪些地方增强。

SpringMVC 架构

架构:

1、 DispatcherServlet(前端控制器),核心组件,负责分发请求,最终分发到Handler方法上。

2、HandlerMapping(处理器映射器),负责根据用户请求找到Handler即处理器。

3、**Controller(处理器)**对具体的用户请求进行处理。

4、HandlerAdapter(处理器适配器)用来执行处理器。

5、View Resolver(视图解析器)进行视图解析,处理结果生成View视图。

6、View(视图)是一个接口实现类支持不同的 View 类型。

前端控制器、处理器映射器、处理器适配器、处理器、视图解析器称为springmvc的五大组件。需要用户实现的组件有Controller、view

流程:

1、请求→前端控制器DispatcherServlet→处理器映射器HandlerMapping,生成处理器对象及处理器拦截器→前端控制器

2、前端控制器→处理器适配器HandlerAdapter,经适配调用具体的处理器(后端控制器),生成ModelAnView→前端控制器DispatcherServlet

3、前端控制器将ModelAnView视图解析器(View Resolver)解析出view→前端控制器

4、前端控制器根据View进行渲染,响应用户

1.用户发送请求至 前端控制器DispatcherServlet,收到请求后调用处理器映射器HandlerMapping,它会根据请求的Url找到具体的处理器,生成处理器对象Handler,及处理器拦截器HandlerIntercepter(如果有则生成) ,之后一并返回给前端控制器。

2、前端控制器,通过处理器适配器HandlerAdapter,经过适配调用具体的处理器Controller(也叫后端控制器),处理器执行完后返回ModelAnView,最终到达前段控制器。

3、前端控制器将ModelAnView传给View Resolver(视图解析器),解析后返回具体的视图(View)给前端控制器,前端控制器根据View进行渲染,响应用户。

HTTP

请求行,请求头都有哪些参数?

请求行:请求方法、请求资源、版本协议

响应行:协议版本、状态码、原因短语

请求头和响应头:

请求头:
    Accept:以接受的文件类型
    Accept-Charset: 支持的字符集
    Accept-Encoding:可以接受的数据编码
    Accept-Language: 使用的浏览语言
    Cookie:存储和用户相关的信息
    User-agent:览器的版本信息
响应头:
	Content-Type:表示媒体类型信息(HTML格式、gif格式等)
	Content-encoding:返回内容的压缩编码类型
	Content-length:返回内容的大小
	Set-cookie:服务器通知浏览器设置一个 Cookie

 

GET请求和POST请求的差别

主要是语义上的区别。GET 的语义就是用来获取资源、POST提交数据,对指定的资源做出处理。

常见状态码及其含义

200 成功

302 重定向

404 资源在服务器不存在

500 服务器内部错误

除了GET和POST还有什么请求?

PUT在服务器更新资源(客户端提供改变后的完整资源)。即更新数据
DELETE从服务器删除资源 。即删除数据
PATCH在服务器更新资源(客户端提供改变的属性)。即更新数据
HEAD只返回响应头,而不会发送响应内容。查看某个页面的状态。
OPTIONS使服务器传回该资源所支持的所有HTTP请求方法。可以测试服务器功能是否正常运作。
TRACE回显服务器收到的请求,主要用于测试或诊断。

HTTP1.1和1.0有什么区别

一、连接方式;1.0默认短连接,长连接需使用keep-alive参数设置,1.1默认长连接。

二、节约宽带:1.0若只需要某对象一部分,服务器却可能将整个对象传过来,1.1,请求头引入了range域,允许只请求资源的某个部分。

三、Host区:1.0是没有host域,HTTP1.1支持,多个虚拟站点可以共享同一个ip和端口。

Http与Https的区别

Http属于哪一层:应用层。

HTTPS是HTTP+SSL,有一个安全验证机制(CA证书)

①安全性:http明文传输,https 加密,加密采⽤对称加密,该秘钥在服务器⽅的证书,是⾮对称加密。

②默认端口:http 80,https 443。

MySQL

个人理解

MySQL 是开源免费的⼀种关系型数据库,它拥性能高、成本低、可靠性好,并且⽅便扩展等特点。可以在各种平台上运行,在企业中比较流行,MySQL的默认端⼝号是3306

索引

是帮助数据库高效获取数据,所以本质上来说,索引就是一种数据结构。那数据结构的话,我们平时熟悉的有比如二叉树、红黑树、Hash表、B树等。

索引的数据结构

主要采用的 B+树。

为什么

Hash索引底层是哈希表,存储上无序,适用于等值查询的场景,区间查询就需要全表扫描,效率低。

二叉树和红黑树,当数据量非常多的时候,树的高度也变高,磁盘IO次数增多,速度较慢。

B树,叶子节点,非叶子节点都会存数据,导致非叶子节点存储主键较少,树高较高。

而B+ 树是一种多路平衡查询树,节点天然有序非叶子节点只存主键降低了树高,减少IO次数,且叶子节点件相连链接,范围查找速度快

主键索引(聚簇索引)和非主键索引

主键索引的叶子节点存放的是整行数据

非主键索引的叶子节点存放的是主键的值,也叫二级索引

联合索引、最左匹配原则

创建sql:

alter table 表名 add index 索引名(字段1,字段2,字段3)

多个字段同时建立一个索引,叫联合索引,在建立时要留意将高频的字段索引放在前面。

最左匹配原则:

​ 对于联合索引,MySQL 会一直向右匹配直到遇到范围查询(> , < ,between,like)就停止匹配。

​ = 和 in 可以乱序。

​ 设置联合索引为(a,b),那么直接采用 where b = 5,用不到索引

成因:

​ 首先根据联合索引中最左边的,第一个字段进行排序,再该排序基础上,再对联合索引中后面的第二个字段进行排序,依此类推,第一个字段是绝对有序的,从第二个字段开始是无序的

引擎和锁

引擎:MyISAM(5.5以前)和Innodb(5.5以后默认)

锁:行锁、表锁、页锁

Innodb支持页锁、行锁(默认,加锁慢,开销大,并发程度高)

MyISAM 采用表级锁(开销小,加搀快,并发程度低)

乐观锁,悲观锁

乐观锁:认为数据一般情况下不会发生冲突,不会上锁,可在表内维护一个版本号字段实现,需要更新数据的时候,会去比较一下版本号,判断是否被更新。

悲观锁: 认为每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,是**“先取锁再访问”**的策略。

使用场景:乐观锁→读取较多场景(冲突概率低)悲观锁→写入较多场景

传播行为、隔离级别

传播行为(共7个):

REQUIRED(默认) 一荣俱荣,一损俱损型:

​ 要么一起提交,要么一起回滚。如果没有事务则新建一个;如果包含事务,则加入进来

REQUIRES_NEW 自私型事务:

​ 外不影响内,内影响外。 如果没有事务则新建一个;如果包含事务,仍新增一个事务

NESTED无私型事务(内部方法相较于外部方法不重要):

​ 外影响内,内不影响外。如果没有事务则新建一个;如果包含事务,以嵌套事务的方式运行。

隔离级别:

①READ-UNCOMMITTED(读取未提交)

②READ-COMMITTED(读取已提交)

REPEATABLE-READ(可重复读) MySQL默认

SERIALIZABLE(可串⾏化)

防范SQL注入

常见使用PreparedStatement预编译sql语句,不会把用户输入的各种参数当做 SQL语句的关键字进行解析。

或者可以使用正则表达式匹配用户输入的数据,或者用字符串过滤等

**#{}${}**的区别是什么?

#{} 是预处理,sql解析时,参数是带引号的,${}是字符串替换,sql解析时,参数是不带引号的。

使用#{}可以有效的防止SQL注入,提高系统安全性。

JDBC链接数据库流程

第一步:Class.forName() 注册驱动;

第二步:DriverManager.getConnection() 获取连接;

第三步:根据 SQL 获取 sql 会话对象,有 2 种方式 Statement、PreparedStatement ;

第四步:执行 SQL 处理结果集,执行 SQL 前如果有参数值就设置参数值 setXXX();

第五步:关闭结果集、关闭会话、关闭连接。

如何批量插入

foreach标签

collection属性,该语句参数映射名。

item属性,对应单条记录值。

separator属性,每条语句间分隔符。

1. <insert id="insertBatch" >
2. insert into tbl_employee(last_name,email,gender,d_id) values
3. <foreach collection="emps" item="curr_emp" separator=",">
4. (#{curr_emp.lastName},#{curr_emp.email},#{curr_emp.gender},#{curr_emp.dept.id})
5. </foreach>
6. </insert>

排查并优化

排查:

​ 通过explain查看sql语句的执行计划,通过执行计划来分析索引使用情况。

优化:

​ 将 where 中用的比较频繁的字段建立索引

​ select 子句中避免使用‘*’

​ 避免改变索引列的类型

​ 避免在索引列上面进行计算

​ 将记录条数最少的表写在from字句最后,最为基础表最先被处理。

分库分表

当 MySQL内数据量到达 1000万条数据之后,性能下降,需要对其切分。

垂直切分:

​ ①垂直分库

​ ②垂直分表

水平切分:

系统突然变慢如何排查

1、查看部署系统的服务器,各系统资源是否达到上限。

2、检查应用服务器线程池配置,请求的排队现象是否严重,检查一下数据库的连接池设置,是否需要增大连接池。再检查是否有慢sql。

3、查看服务调用链的响应时间。

4、检查web服务器的请求日志,看一下是否存在Doss攻击。

熔断、降级、限流

服务熔断:下游服务访问压力过大而响应变慢或失败,上游服务为保护系统整体的可用性,可暂时切断对下游服务的调用。

服务降级:高负荷情况下,预防某些功能(业务场景)出现负荷过载或者响应慢的情况,暂时舍弃一些非核心的接口和数据的请求,直接返回一个提前准备好的 fallback(退路)错误处理信息。

相同点:

​ 1、都是从系统的可用性和可靠性出发,为了防止系统崩溃。

​ 2、用户体验类似,最终都让用户体验到的是某些功能的不可用

​ 不同点:

​ 触发原因不同:服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑。

项目TPS、QPS多少

调优后单机TPS(每秒传输的事物处理个数) 1500左右,QPS(每秒查询率) 2000,和配置有关。

RocketMQ

如何实现分布式事务?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lp4S5yB7-1619334261343)(C:\Users\Simon\AppData\Roaming\Typora\typora-user-images\image-20210414145513622.png)]

分布式事务有哪几种?简单说一下二阶段提交

①刚性事务(强⼀致性)

代表:⼆阶段提交(2PC)、三阶段提交(多了一步确认请求,验证所有事务管理器都能提交成功)。引⼊了事务管理器,执行事务前,先进行一次,状态验请求,根据返回状态,再决定执行事务请求是否提交,的分布式算法

存在的问题:

1、同步阻塞(执行过程中,所有参与节点都是事务阻塞状态,第三方节点访问公共资源不得不处于阻塞状态)。2、不能解决数据不⼀致的问题。(不能保证每个事务管理器的commit请求都能执行成功)

②柔性事务(最终⼀致性)

遵循BASE理论,最终⼀致性;允许⼀定时间内,不同节点的数据不⼀致,但要求最终⼀致。

消息队列都有哪些?你们项目用的 rocketMQ 对比其他消息队列有什么优势?

1、ActiveMQ 放到今天性能不强劲,吞吐量最差万级),消息延迟性高。

2、RabbitMQ 延迟性低(最快微秒级),吞吐量差(万级),不支持批量操作,不支持事务

3、Kafka 吞吐量较高(10万级),但是只支持主要的MQ功能,消息查询,回溯,事务等功能不支持,大数据领域使用多。

4、**RocketMQ ** 性能好,吞吐量(最高10万级),消息延迟低,功能完善(支持事务,支持批量操作)。

如果秒杀服务运行过程中 mq 服务挂掉了怎么办?

1,从设计角度,做集群和主从备份,保证 mq的高可用性。

2, 需要给 MQ 配置消息持久化,防止挂掉了之后消息丢失。

3, 做好监控,防止服务挂了之后没有检测到,并且及时把服务重启起来

4, 从业务角度来保证 MQ 挂了之后用户的体验

mq 消费者如果消费不成功怎么办呢?

1、RocketMQ 会把该消息丢入重试队列当中去,默认重试16次若还没成功则投递到死信队列中去。

2、可通过后台管理系统从死信队列里面把没消费成功的消息取出,然后手动处理。

队列消息的类型有哪些?

1、普通消息:也叫做无序消息,没有顺序的消息。可大规模的并发的发生和消费,吞吐量很高,适合大部分场景

2、有序消息:按照一定的先后顺序的消息类型。可以进一步分为:全局有序消息(1 个MessageQueue)、局部有序消息(多个MessageQueue)

3、延时消息:当MQ发送方将消息发开到MQServer之后,会延时一定时间后才投递给订阅方进行消费。

4、事务消息:本地事务和事务消息的投递保持一致性

Dubbo

注册(发现)流程?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xv6m9rVM-1619334261352)(C:\Users\Simon\AppData\Roaming\Typora\typora-user-images\image-20210415000053855.png)]

Redis

持久化策略,你们项目用的是哪一种?

持久化方式有两种。策略共四种。

1、RDB(数据快照模式,默认),定期存储,保存的是数据本身,存储文件是紧凑的。

​ 优点:保存还原快,,适⽤于容灾备份

​ 缺点:1、可能会丢失数据。2、 数据较大时,可能会影响主进程的业务速度。

2、AOF(追加模式),每次修改数据时,同步到硬盘(写操作日志),保存的是数据的变更记录。

​ 优点:1、数据安全性高。写入的过程中现服务宕机,也可保证之前日志内容。2、操作记录清晰直观。

​ 缺点:1、占空间大,恢复慢。2、运行效率低。

3、也可以同时开启俩种策略,当 Redis 重启时,AOF 文件会用于重建原始数据。

4、俩种策略都可以关闭,数据保存在内存中。

数据类型, setnx,setex作用

String(字符串)

​ 应⽤场景:统计⽹站访问数量 pv(Page view),当前在线⼈数等。

List(列表)
应⽤场景:1.最新消息排⾏榜。

Hash(二维表)

​ 应⽤场景:存储系统中对象数据

Set(无序集合,健值无序唯一)

​ 应⽤场景(去重的场景里):

​ 1.利⽤交集求共同好友。2.利⽤唯⼀性,可以统计访问⽹站IP

​ 3.好友推荐的时候根据tag求交集,⼤于某个threshold(临界值的)就可以推荐。

ZSet(有序集合)

​ 应用场景:积分、礼物排⾏榜等,需要对数据根据某个权重进⾏排序的场景。

是如何配置的?

1、port:6379 指定访问redis服务的端口。

2、bind:0.0.0.0 指定绑定主机地址。

3、timeout:多少闲杂时间后关闭。

4、loglevel:日志级别(debug、verbose、notice默认、warning)。

5、save:在指定时间和操作次数后把缓存同步到本地库。

6、dir:本地数据存放位置。

7、requirepass:访问密码。

8、maxmemory:指定最大内存。

9、appendonly:是否开启日志记录功能。

10、vm-enabled:是否启用虚拟内存。

哨兵模式、集群模式

哨兵模式

是在主从模式架构上升级而来,主从模式是允许用户创建多个主服务器的复制,可将读写分离给不同服务器的模式。哨兵模式是多了一个哨兵角色,他与主服务器间保持着心跳链接机制,主服务器服务挂了,那么会将服务切换到一台从服务器(slave)上,并且可以通过API向管理员或者其他应用发送通知。

集群模式

第一种,相当于哨兵模式的升级版,主服务器,哨兵升级为集群,通过twemproxy去映射请求,分发到主服务器上。

第二种,“去中心化”架构。每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。

主从模式

特点:

允许用户根据一个 Redis 服务器来创建任意多个该服务器的复制, 主服务器中的内容和从服务器中的内容完全一致。该模式下可以做读写分离,主服务器负责写,从服务器负责读,这样可以缓解主服务器的压力。

问题:

1, 无法高可用,一旦主服务器挂了,那么整个写功能都挂了。2, 没有解决主服务器写的压力。

哨兵模式

可以理解为主从架构的升级版,多了一个sentinel角色(哨兵),它和redis的主机之间保持着心跳链接机制,一旦发现redis 的主服务器(master)服务挂了,那么会将服务切换到一台从服务器(slave)上,并且可以通过API向管理员或者其他应用发送通知。

特点:1、保证高可用。2、监控各个节点。3、自动故障迁移

问题:1、主从模式,切换需要时间丢数据,2、没有解决 master 写的压力

集群<代理型>

相当于哨兵模式的升级版,主服务器,哨兵升级为集群,通过twemproxy去映射请求,分发到主服务器上。

映射有多种hash算法:MD5、CRC16、CRC32、CRC32a、hsieh、murmur、Jenkins

特点:1、对比哨兵模式又有了进一步的提升,处理能力更强。2、支持失败节点自动删除。3、后端集群存储透明,和操作单个redis基本一致。

问题:新增了Proxy,维护困难。

集群<直连型>

“去中心化”架构。每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。

优点:1、一台服务的宕机不会立马影响到整个服务。2、可拓展性,拓展节点很方便。3、高可用性,部分节点不可用时,集群仍然可用。

问题:1、 数据通过异步复制,所以不能保证数据的强一致性。2、 资源隔离性差,容易互相影响。

缓存雪崩,缓存穿透

缓存雪崩:

​ 是指在某一段时间,缓存集中失效,会导致大量的请求去请求数据库,引起瘫痪。

​ 解决:设置缓存过期时间分散设置,或者永不过期。

缓存击穿:

​ 查询数据,缓存中没有但数据库中有,会一直 查询数据库,并发量很大时可能击穿数据库。

​ 解决:1, 设置热点数据永不过期。2, 增加互斥锁(Mutex key)。

如何保证redis中全是是热点数据

设置淘汰策略–如allkeys-lru。

淘汰策略:

①volatile-lru:在设置了超时时间key中,优先删除最近最少使用的key。

②volatile-ttl:在设置了超时时间key,删除将要过期的数据淘汰

③volatile-random:在设置了超时时间key中,删除任意选择数据。

④allkeys-lru:在所有key中删除最少使用的数据淘汰。

⑤allkeys-random:在所有key中随机删除一部分key。

⑥no-enviction(驱逐):不删除,超出最大内存容量报错。

Zookeeper

zookeeper 的作用

作为注册中心,协调分布式环境下,各个微服务间相互调用。

zookeeper 在某一个瞬间挂了dubbo 服务还能调用吗?

可以,消费者会从注册中心拉取的接口数据,缓存在本地。每次调用时,按照本地存储的地址进行调用。

如何实现 zookeeper 的高可用?

搭建集群实现高可用。

集群最少需要配置几台机器?为什么?

最少3台(基数)

集群写操作,由leader节点负责,只有半数以上节点反馈成功,才算写成功,若两个节点,必须全部成功。

选举leader节点策略,也需半数以上节点同意才行,偶数节点可能导致票数相同。

分布式锁

简介:

单机环境下,Synchronized锁可保证方法或代码块同一时间只被一个线程执行,该锁是jvm提供的关键字,只能保证在一个jvm中使用,但到了分布式环境下则不行。

三种实现方式

1 基于数据库

​ 利用主键或索引的唯一性,当节点调用方法时,在数据库中加上固定值,只有一个节点能将值插入到这个唯一字段,视为加锁,执行完该方法后删除该字段,视为解锁。

​ 缺点:性能差,不具备阻塞特性,不可重入。

2 Redis(本程序)

​ RedissonClient 框架获取锁对象,在扣减库存前后加锁(tryLock),解锁(unLock)。

​ SETNX 关键字,设置参数如果存在返回 0,如果不存在返回 value(随机生成的UUID) 和 1。

利用setnx关键字加锁,使用expire设置过期时间,超时后释放锁,解决死锁。释放锁时,通过setnx返回的uuid判断,进行delete关键字删除key,释放锁。

​ 优点:性能好,实现方便

3 Zookeeper

线程池

你们项目哪里用了线程池?几种配置方式?缺点是什么?

秒杀接口中,调用下单方法时用了固定数量的线程池。

  1. newCachedThreadPool()

    缓存型池子,有空闲线程用,就使用.如果没有,就建一个新的线程加入池中。

    能保证立即执行(适用于执行大量短期异步任务)

  2. newFixedThreadPool(int nThreads);

    固定线程数的线程池,维护了一个共享无界队列来运行这些线程

  3. newSingleThreadExecutor()

    单例线程,池中只能有一个线程,维护了一个共享无界队列来运行这些线程,可保证执行顺序,。

  4. newScheduledThreadPool(int)

    调度型线程池,它用来处理延时任务或定时任务。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值