JVM 面试题目
1.请简单描述下 JVM 运行时数据区包括哪些部分?
JVM 在执行 Java 程序的过程中会把它管理的内存分为若干个不同的区域,这些组成部
分有些是线程私有的,有些则是线程共享的
线程私有的:程序计数器,虚拟机栈,本地方法栈
线程共享的:方法区,堆
2.JVM 中是怎么判断对象可回收的?
可达性分析算法
这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节
点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链
相连的话,则证明此对象是不可用的,可以被回收的。
3.方法区主要存储什么信息?
方法区是所有线程共享。主要用于存储类的信息、常量池、方法数据、方法代码等。方
法区逻辑上属于堆的一部分,但是为了与堆进行区分,通常又叫“非堆”。
4.请简单描述下 JVM 出现的几种异常?
主要是两种:StackOverFlowError 和 OutOfMemoryError.
StackOverFlowError:
当线程请求栈的深度超过当前 Java 虚拟机栈的最大深度的时候,就抛出
StackOverFlowError 异常。
OutOfMemoryError:
5.怎么理解面向切面编程的切面?
答:
切面指的是一类功能,比如事务,缓存,日志等。切面的作用是在目标对象方法执行前
或者后执行切面方法
6.什么是 IOC 容器?
答:
Spring IOC 负责创建对象、管理对象(通过依赖注入)、整合对象、配置对象以及管理
这些对象的生命周期。
Ioc 是把对象的控制权较给框架或容器,容器中存储了众多我们需要的对象,然后我们
就无需再手动的在代码中创建对象。需要什么对象就直接告诉容器我们需要什么对象,容器
会把对象根据一定的方式注入到我们的代码中。注入的过程被称为 DI。有时候需要动态的
指定我们需要什么对象,这个时候要让容器在众多对象中去寻找,容器寻找需要对象的过程,
称为 DL(Dependency Lookup, 依赖查找)。按照上面的理解,那么 IOC 包含了 DI 与 DL,并
且多了对象注册的过程。
7.为什么需要代理模式?
答:
代理其实是对开闭原则和里氏代换原则的一种实现,它强调在不修改老代码的基础上扩
展功能,代理模式大大提高了代码的灵活性,同时也使代码的可读性变差,同时动态代理也
加大了内存溢出的风险。
8.讲讲静态代理模式的优点及其瓶颈?
答:
静态代理一种傻瓜式的对目标类的增强,其核心就两点,1、跟目标类实现同一接口 2、
持有目标类的引用。 如果需要对目标类方法进行增强,就只要调用代理类的方法,在方法
里面写增强功能然后调用目标类方法即可。优点就是代码直观且执行速度快,缺点就是不够
灵活,代码量比较大,每一种类型的目标类都需要单独写一个代理类。
9.讲解 Spring 框架中基于 Schema 的 AOP 实现原理?
答:
这个是基于 xml 配置方式的 aop
AOP 实现流程
1、aop:config 自定义标签解析
2、自定义标签解析时封装对应的 aop 入口类,类的类型就是 BeanPostProcessor 接口
类型
3、Bean 实现化过程中会执行到 aop 入口类中
4、在 aop 入口类中,判断当前正在实例化的类是否在 pointcut 中,pointcut 可以理
解为一个模糊匹配,是一个 joinpoint 的集合
5、如果当前正在实例化的类在 pointcut 中,则返回该 bean 的代理,同时把所有配置
的 advice 封装成 MethodInterceptor 对象加入到容器中,封装成一个过滤器链
代理对象调用,jdk 调到 invocationHandler 中,cglib 调到 MethodInterceptor 的
callback 类中,然后在 invoke 方法中执行过滤器链。
10. 讲解 Spring 框架中如何基于 AOP 实现的事务管
理?
答:
事务管理,是一个切面。在 aop 环节中,其他环节都一样,事务管理就是有自己单独的
advice,有单独的通知,是 TransactionInterceptor,它一样的会在拦截器链中被执行到,
这个 TransactionInterceptor 拦截器类是通过解析tx:advice自定义标签得到的。
11. Spring 在 Bean 创建过程中是如何解决循环依赖
的?
答:
循环依赖只会存在在单例实例中,多例循环依赖直接报错。
A 类实例化后,把实例放 map 容器中,A 类中有一个 B 类属性,A 类实例化要进行 IOC
依赖注入,这时候 B 类需要实例化,B 类实例化跟 A 类一样,实例化后方 map 容器中。B 类
中有一个 A 类属性,接着 B 类的 IOC 过程,又去实例化 A 类,这时候实例化 A 类过程中从
map 容器发现 A 类已经在容器中了,就直接返回了 A 的实例,依赖注入到 B 类中 A 属性中,
B 类 IOC 完成后,B 实例化就完全完成了,就返回给 A 类的 IOC 过程。这就是循环依赖的解
决。
{enviornment}。在加载主应用程序属性文件后,Spring 将在
(application{environment} .properties)中加载后续的应用程序属性文件。
3.什么是 JavaConfig?
Spring JavaConfig 是 Spring 社区的产品,它提供了配置 Spring IoC 容器的纯 Java
方法。因此它有助于避免使用 XML 配置。使用 JavaConfig 的优点在于:
面向对象的配置。由于配置被定义为 JavaConfig 中的类,因此用户可以充分利用 Java
中的面向对象功能。一个配置类可以继承另一个,重写它的@Bean 方法等。
减少或消除 XML 配置。基于依赖注入原则的外化配置的好处已被证明。但是,许多开
发人员不希望在 XML 和 Java 之间来回切换。JavaConfig 为开发人员提供了一种纯 Java
方法来配置与 XML 配置概念相似的 Spring 容器。从技术角度来讲,只使用 JavaConfig 配
置类来配置容器是可行的,但实际上很多人认为将 JavaConfig 与 XML 混合匹配是理想的。
类型安全和重构友好。JavaConfig 提供了一种类型安全的方法来配置 Spring 容器。由于
Java 5.0 对泛型的支持,现在可以按类型而不是按名称检索 bean,不需要任何强制转换或
基于字符串的查找。
4.如何重新加载 Spring Boot 上的更改,而无需重
新启动服务器?
这可以使用 DEV 工具来实现。通过这种依赖关系,您可以节省任何更改,嵌入式 tomcat
将重新启动。Spring Boot 有一个开发工具(DevTools)模块,它有助于提高开发人员的生
产力。Java 开发人员面临的一个主要挑战是将文件更改自动部署到服务器并自动重启服务
器。开发人员可以重新加载 Spring Boot 上的更改,而无需重新启动服务器。这将消除每
次手动部署更改的需要。Spring Boot 在发布它的第一个版本时没有这个功能。这是开发人
员最需要的功能。DevTools 模块完全满足开发人员的需求。该模块将在生产环境中被禁用。
它还提供 H2 数据库控制台以更好地测试应用程序。
org.springframework.boot spring-boot-devtools true
5. Spring Boot 中的监视器是什么?
Spring boot actuator 是 spring 启动框架中的重要功能之一。Spring boot 监视器
可帮助您访问生产环境中正在运行的应用程序的当前状态。有几个指标必须在生产环境中进
行检查和监控。即使一些外部应用程序可能正在使用这些服务来向相关人员触发警报消息。
监视器模块公开了一组可直接作为 HTTP URL 访问的 REST 端点来检查状态。
6.如何在 Spring Boot 中禁用 Actuator 端点安全
性?
默认情况下,所有敏感的 HTTP 端点都是安全的,只有具有 ACTUATOR 角色的用户才能
访问它们。安全性是使用标准的 HttpServletRequest.isUserInRole 方法实施的。 我们可
以使用 management.security.enabled = false 来禁用安全性。只有在执行机构端点在防
火墙后访问时,才建议禁用安全性。
7.如何在自定义端口上运行 Spring Boot 应用程
序?
为了在自定义端口上运行 Spring Boot 应用程序,您可以在 application.properties
中指定端口。
server.port = 8090
8.什么是 YAML?
YAML 是一种人类可读的数据序列化语言。它通常用于配置文件。
与属性文件相比,如果我们想要在配置文件中添加复杂的属性,YAML 文件就更加结构
化,而且更少混淆。可以看出 YAML 具有分层配置数据。
9.如何实现 Spring Boot 应用程序的安全性?
为了实现 Spring Boot 的安全性,我们使用 spring-boot-starter-security 依赖项,
并且必须添加安全配置 。它只需要很少的代码。配置类 将必须扩展
WebSecurityConfigurerAdapter 并覆盖其方法。
10. 如何集成 Spring Boot 和 ActiveMQ?
对于集成 Spring Boot 和 ActiveMQ,我们使用 spring-boot-starter-activemq 依赖
关系。 它只需要很少的配置,并且不需要样板代码。
11. 如何使用 Spring Boot 实现分页和排序?
使用 Spring Boot 实现分页非常简单。使用 Spring Data-JPA 可以实现将可分页的
org.springframework.data.domain.Pageable 传递给存储库方法。
12. 什么是 Swagger?你用 Spring Boot 实现了它
吗?
Swagger 广泛用于可视化 API,使用 Swagger UI 为前端开发人员提供在线沙箱。
Swagger 是用于生成 RESTful Web 服务的可视化表示的工具,规范和完整框架实现。它使
文档能够以与服务器相同的速度更新。当通过 Swagger 正确定义时,消费者可以使用最少
量的实现逻辑来理解远程服务并与其进行交互。因此,Swagger 消除了调用服务时的猜测。
13. 什么是 Spring Profiles?
Spring Profiles 允许用户根据配置文件(dev,test,prod 等)来注册 bean。因此,
当应用程序在开发中运行时,只有某些 bean 可以加载,而在 PRODUCTION 中,某些其他
bean 可以加载。假设我们的要求是 Swagger 文档仅适用于 QA 环境,并且禁用所有其他文
档。这可以使用配置文件来完成。Spring Boot 使得使用配置文件非常简单。
14. 什么是 Spring Batch?
Spring Boot Batch 提供可重用的函数,这些函数在处理大量记录时非常重要,包括日
志/跟踪,事务管理,作业处理统计信息,作业重新启动,跳过和资源管理。它还提供了更
先进的技术服务和功能,通过优化和分区技术,可以实现极高批量和高性能批处理作业。简
单以及复杂的大批量批处理作业可以高度可扩展的方式利用框架处理重要大量的信息。
15. 什么是 FreeMarker 模板?
FreeMarker 是一个基于 Java 的模板引擎,最初专注于使用 MVC 软件架构进行动态网
页生成。使用 Freemarker 的主要优点是表示层和业务层的完全分离。程序员可以处理应用
程序代码,而设计人员可以处理 html 页面设计。最后使用 freemarker 可以将这些结合起
来,给出最终的输出页面。
16. 如何使用 Spring Boot 实现异常处理?
Spring 提供了一种使用 ControllerAdvice 处理异常的非常有用的方法。我们通过实
现一个 ControlerAdvice 类,来处理控制器类抛出的所有异常。
17. 您使用了哪些 starter maven 依赖项?
使用了下面的一些依赖项 spring-boot-starter-activemq
spring-boot-starter-security
spring-boot-starter-web
这有助于增加更少的依赖关系,并减少版本的冲突。
18. 什么是 CSRF 攻击?
CSRF 代表跨站请求伪造。这是一种攻击,迫使最终用户在当前通过身份验证的 Web 应
用程序上执行不需要的操作。CSRF 攻击专门针对状态改变请求,而不是数据窃取,因为攻
击者无法查看对伪造请求的响应。
19. 什么是 WebSockets?
WebSocket 是一种计算机通信协议,通过单个 TCP 连接提供全双工通信信道。
WebSocket 是双向的 -使用 WebSocket 客户端或服务器可以发起消息发送。
WebSocket 是全双工的 -客户端和服务器通信是相互独立的。
单个 TCP 连接 -初始连接使用 HTTP,然后将此连接升级到基于套接字的连接。然后这
个单一连接用于所有未来的通信
Light -与 http 相比,WebSocket 消息数据交换要轻得多。
20. 什么是 AOP?
在软件开发过程中,跨越应用程序多个点的功能称为交叉问题。这些交叉问题与应用程
序的主要业务逻辑不同。因此,将这些横切关注与业务逻辑分开是面向方面编程(AOP)的
地方。
21. 什么是 Apache Kafka?
Apache Kafka 是一个分布式发布 - 订阅消息系统。它是一个可扩展的,容错的发布 -
订阅消息系统,它使我们能够构建分布式应用程序。这是一个 Apache 顶级项目。Kafka 适
合离线和在线消息消费。
22. 我们如何监视所有 Spring Boot 微服务?
Spring Boot 提供监视器端点以监控各个微服务的度量。这些端点对于获取有关应用程
序的信息(如它们是否已启动)以及它们的组件(如数据库等)是否正常运行很有帮助。但
是,使用监视器的一个主要缺点或困难是,我们必须单独打开应用程序的知识点以了解其状
态或健康状况。想象一下涉及 50 个应用程序的微服务,管理员将不得不击中所有 50 个应
用程序的执行终端。
SpringCloud 面试题目
1.什么是 Spring Cloud?
Spring cloud 流应用程序启动器是基于 Spring Boot 的 Spring 集成应用程序,提供
与外部系统的集成。
Spring cloud Task,一个生命周期短暂的微服务框架,用于快速构建执行有限数据处
理的应用程序。
2.使用 Spring Cloud 有什么优势?
使用 Spring Boot 开发分布式微服务时,我们面临以下问题
与分布式系统相关的复杂性-这种开销包括网络问题,延迟开销,带宽问题,安全问题。
服务发现-服务发现工具管理群集中的流程和服务如何查找和互相交谈。它涉及一个服
务目录,在该目录中注册服务,然后能够查找并连接到该目录中的服务。
冗余-分布式系统中的冗余问题。
负载平衡 --负载平衡改善跨多个计算资源的工作负荷,诸如计算机,计算机集群,网
络链路,中央处理单元,或磁盘驱动器的分布。
性能-问题 由于各种运营开销导致的性能问题。
部署复杂性-Devops 技能的要求。
3.服务注册和发现是什么意思?Spring Cloud 如何
实现?
当我们开始一个项目时,我们通常在属性文件中进行所有的配置。随着越来越多的服务
开发和部署,添加和修改这些属性变得更加复杂。有些服务可能会下降,而某些位置可能会
发生变化。手动更改属性可能会产生问题。 Eureka 服务注册和发现可以在这种情况下提供
帮助。由于所有服务都在 Eureka 服务器上注册并通过调用 Eureka 服务器完成查找,因此
无需处理服务地点的任何更改和处理。
4.负载平衡的意义什么?
在计算中,负载平衡可以改善跨计算机,计算机集群,网络链接,中央处理单元或磁盘
驱动器等多种计算资源的工作负载分布。负载平衡旨在优化资源使用,最大化吞吐量,最小
化响应时间并避免任何单一资源的过载。使用多个组件进行负载平衡而不是单个组件可能会
通过冗余来提高可靠性和可用性。负载平衡通常涉及专用软件或硬件,例如多层交换机或域
名系统服务器进程。
5.什么是 Hystrix?它如何实现容错?
Hystrix 是一个延迟和容错库,旨在隔离远程系统,服务和第三方库的访问点,当出现
故障是不可避免的故障时,停止级联故障并在复杂的分布式系统中实现弹性。
通常对于使用微服务架构开发的系统,涉及到许多微服务。这些微服务彼此协作。
思考以下微服务
假设如果上图中的微服务 9 失败了,那么使用传统方法我们将传播一个异常。但这仍
然会导致整个系统崩溃。
随着微服务数量的增加,这个问题变得更加复杂。微服务的数量可以高达 1000.这是
hystrix 出现的地方
我们将使用 Hystrix 在这种情况下的 Fallback 方法功能。我们有两个服务
employee-consumer 使用由 employee-consumer 公开的服务。
简化图如下所示
现在假设由于某种原因,employee-producer 公开的服务会抛出异常。我们在这种情况
下使用 Hystrix 定义了一个回退方法。这种后备方法应该具有与公开服务相同的返回类型。
如果暴露服务中出现异常,则回退方法将返回一些值。
6.什么是 Hystrix 断路器?我们需要它吗?
由于某些原因,employee-consumer 公开服务会引发异常。在这种情况下使用 Hystrix
我们定义了一个回退方法。如果在公开服务中发生异常,则回退方法返回一些默认值。
如果 firstPage method() 中的异常继续发生,则 Hystrix 电路将中断,并且员工使
用者将一起跳过 firtsPage 方法,并直接调用回退方法。 断路器的目的是给第一页方法或
第一页方法可能调用的其他方法留出时间,并导致异常恢复。可能发生的情况是,在负载较
小的情况下,导致异常的问题有更好的恢复机会 。
7.什么是 Netflix Feign?它的优点是什么?
Feign 是受到 Retrofit,JAXRS-2.0 和 WebSocket 启发的 Java 客户端联编程序。
Feign 的第一个目标是将约束分母的复杂性统一到 http apis,而不考虑其稳定性。在
employee-consumer 的例子中,我们使用了 employee-producer 使用 REST 模板公开的
REST 服务。
但是我们必须编写大量代码才能执行以下步骤
使用功能区进行负载平衡。
获取服务实例,然后获取基本 URL。
利用 REST 模板来使用服务。 前面的代码如下
@Controller
public class ConsumerControllerClient {
@Autowired
private LoadBalancerClient loadBalancer;
public void getEmployee() throws RestClientException, IOException {
ServiceInstance serviceInstance=loadBalancer.choose(“employee-producer”);
System.out.println(serviceInstance.getUri());
String baseUrl=serviceInstance.getUri().toString();
baseUrl=baseUrl+"/employee";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity response=null;
try{
response=restTemplate.exchange(baseUrl,
HttpMethod.GET, getHeaders(),String.class);
}catch (Exception ex)
{
System.out.println(ex);
}
System.out.println(response.getBody());
}
之前的代码,有像 NullPointer 这样的例外的机会,并不是最优的。我们将看到如何
使用 Netflix Feign 使呼叫变得更加轻松和清洁。如果 Netflix Ribbon 依赖关系也在类
路径中,那么 Feign 默认也会负责负载平衡。
8.什么是 Spring Cloud Bus?我们需要它吗?
考虑以下情况:我们有多个应用程序使用 Spring Cloud Config 读取属性,而 Spring
Cloud Config 从 GIT 读取这些属性。
下面的例子中多个员工生产者模块从 Employee Config Module 获取 Eureka 注册的财
产。如果假设 GIT 中的 Eureka 注册属性更改为指向另一台 Eureka 服务器,会发生什么
情况。在这种情况下,我们将不得不重新启动服务以获取更新的属性。
还有另一种使用执行器端点/刷新的方式。但是我们将不得不为每个模块单独调用这个
url。例如,如果 Employee Producer1 部署在端口 8080 上,则调用 http:// localhost:
8080 / refresh。同样对于 Employee Producer2 http:// localhost:8081 / refresh 等
等。这又很麻烦。这就是 Spring Cloud Bus 发挥作用的地方。Spring Cloud Bus 提供了
跨多个实例刷新配置的功能。因此,在上面的示例中,如果我们刷新 Employee Producer1,
则会自动刷新所有其他必需的模块。如果我们有多个微服务启动并运行,这特别有用。这是
通过将所有微服务连接到单个消息代理来实现的。无论何时刷新实例,此事件都会订阅到侦
听。
Mybatis 面试题目
1.什么是 MyBatis?
MyBatis 是一个可以自定义 SQL、存储过程和高级映射的持久层框架。
2.讲下 MyBatis 的缓存
答:MyBatis 的缓存分为一级缓存和二级缓存,一级缓存放在 session 里面,默认就有,
二级缓存放在它的命名空间里,默认是不打开的,使用二级缓存属性类需要实现
Serializable 序列化接口(可用来保存对象的状态),可在它的映射文件中配置
Mybatis 是如何进行分页的?分页插件的原理是
什么?
1)Mybatis 使用 RowBounds 对象进行分页,也可以直接编写 sql 实现分页,也可以
使用
Mybatis 的分页插件。
2)分页插件的原理:实现 Mybatis 提供的接口,实现自定义插件,在插件的拦截方法
内拦
截待执行的 sql,然后重写 sql。
举例:select * from student,拦截 sql 后重写为:select t.* from (select * from
student)t limit 0,10
4.简述 Mybatis 的插件运行原理,以及如何编写一
个插件?
1 ) Mybatis 仅可以编写针对 ParameterHandler 、 ResultSetHandler 、
StatementHandler、Executor 这 4 种接口的插件,Mybatis 通过动态代理,为需要拦截的
接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种接口对象的方法时,就会进
入拦截方法,具体就是 InvocationHandler 的 invoke()方法,当然,只会拦截那些你指定
需要拦截的方法。
2)实现 Mybatis 的 Interceptor 接口并复写 intercept()方法,然后在给插件编写
注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插
件。
Mybatis 动态 sql 是做什么的?都有哪些动态
sql?能简述一下动态 sql 的执行原理不?
1)Mybatis 动态 sql 可以让我们在 Xml 映射文件内,以标签的形式编写动态 sql,
完成逻辑判断和动态拼接 sql 的功能。
2)Mybatis 提供了 9 种动态 sql 标签:
trim|where|set|foreach|if|choose|when|otherwise|bind。
3)其执行原理为,使用 OGNL 从 sql 参数对象中计算表达式的值,根据表达式的值动
态拼接 sql,以此来完成动态 sql 的功能。
#{}和KaTeX parse error: Expected 'EOF', got '#' at position 14: {}的区别是什么? 1)#̲{}是预编译处理,{}是字符串替换。
2)Mybatis 在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的
set 方法来赋值;
3)Mybatis 在处理 时 , 就 是 把 {}时,就是把 时,就是把{}替换成变量的值。
4)使用#{}可以有效的防止 SQL 注入,提高系统安全性。
7.为什么说 Mybatis 是半自动 ORM 映射工具?它
与全自动的区别在哪里?
Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对
象时,可以根据对象关系模型直接获取,所以它是全自动的。而 Mybatis 在查询关联对象
或关联集合对象时,需要手动编写 sql 来完成,所以,称之为半自动 ORM 映射工具。
Mybatis 是否支持延迟加载?如果支持,它的实现
原理是什么?
1)Mybatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载,
association 指的就是一对一,collection 指的就是一对多查询。在 Mybatis 配置文件中,
可以配置是否启用延迟加载 lazyLoadingEnabled=true|false。
2)它的原理是,使用 CGLIB 创建目标对象的代理对象,当调用目标方法时,进入拦截
器方法,比如调用 a.getB().getName(),拦截器 invoke()方法发现 a.getB()是 null 值,
那么就会单独发送事先保存好的查询关联 B 对象的 sql,把 B 查询上来,然后调用
a.setB(b),于是 a 的对象 b 属性就有值了,接着完成 a.getB().getName()方法的调用。
这就是延迟加载的基本原理。
MyBatis 与 Hibernate 有哪些不同?
1)Mybatis 和 hibernate 不同,它不完全是一个 ORM 框架,因为 MyBatis 需要程序
员自己编写 Sql 语句,不过 mybatis 可以通过 XML 或注解方式灵活配置要运行的 sql 语
句,并将 Java 对象和 sql 语句映射生成最终执行的 sql,最后将 sql 执行的结果再映射
生成 Java 对象。
2)Mybatis 学习门槛低,简单易学,程序员直接编写原生态 sql,可严格控制 sql 执
行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业
运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的
前提是 mybatis 无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定
义多套 sql 映射文件,工作量大。
3)Hibernate 对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例
如需求固定的定制化软件)如果用 hibernate 开发可以节省很多代码,提高效率。但是
Hibernate 的缺点是学习门槛高,要精通门槛更高,而且怎么设计 O/R 映射,在性能和对
象模型之间如何权衡,以及怎样用好 Hibernate 需要具有很强的经验和能力才行。
总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构
都是好架构,所以框架只有适合才是最好。
MyBatis 的好处是什么?
1)MyBatis 把 sql 语句从 Java 源程序中独立出来,放在单独的 XML 文件中编写,
给程序的维护带来了很大便利。
2)MyBatis 封装了底层 JDBC API 的调用细节,并能自动将结果集转换成 Java Bean 对
象,大大简化了 Java 数据库编程的重复工作。
3)因为 MyBatis 需要程序员自己去编写 sql 语句,程序员可以结合数据库自身的特
点灵活控制 sql 语句,因此能够实现比 Hibernate 等全自动 orm 框架更高的查询效率,
能够完成复杂查询。
简述 Mybatis 的 Xml 映射文件和 Mybatis 内
部数据结构之间的映射关系?
Mybatis 将所有 Xml 配置信息都封装到 All-In-One 重量级对象 Configuration 内
部。在 Xml 映射文件中,标签会被解析为 ParameterMap 对象,其每个子
元素会被解析为 ParameterMapping 对象。标签会被解析为 ResultMap 对象,
其每个子元素会被解析为 ResultMapping 对象。每一个、、、
标签均会被解析为 MappedStatement 对象,标签内的 sql 会被解析为 BoundSql
对象。
什么是 MyBatis 的接口绑定,有什么好处?
接口映射就是在 MyBatis 中任意定义接口,然后把接口里面的方法和 SQL 语句绑定,
我们直接调用接口方法就可以,这样比起原来了 SqlSession 提供的方法我们可以有更加灵
活的选择和设置.
接口绑定有几种实现方式,分别是怎么实现的?
接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加上
@Select@Update 等注解里面包含 Sql 语句来绑定,另外一种就是通过 xml 里面写 SQL 来
绑定,在这种情况下,要指定 xml 映射文件里面的 namespace 必须为接口的全路径名.
什么情况下用注解绑定,什么情况下用 xml 绑
定?
当 Sql 语句比较简单时候,用注解绑定;当 SQL 语句比较复杂时候,用 xml 绑定,一般
用 xml 绑定的比较多
MyBatis 实现一对一有几种方式?具体怎么操作
的?
有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次,通过在 resultMap
里面配置 association 节点配置一对一的类就可以完成;嵌套查询是先查一个表,根据这个
表里面的结果的外键 id,去再另外一个表里面查询数据,也是通过 association 配置,但另
外一个表的查询通过 select 属性配置。
Mybatis 能执行一对一、一对多的关联查询吗?
都有哪些实现方式,以及它们之间的区别?
能,Mybatis 不仅可以执行一对一、一对多的关联查询,还可以执行多对一,多对多的
关联查询,多对一查询,其实就是一对一查询,只需要把 selectOne()修改为 selectList()
即可;多对多查询,其实就是一对多查询,只需要把 selectOne()修改为 selectList()即
可。
关联对象查询,有两种实现方式,一种是单独发送一个 sql 去查询关联对象,赋给主
对象,然后返回主对象。另一种是使用嵌套查询,嵌套查询的含义为使用 join 查询,一部
分列是 A 对象的属性值,另外一部分列是关联对象 B 的属性值,好处是只发一个 sql 查
询,就可以把主对象和其关联对象查出来。
MyBatis 里面的动态 Sql 是怎么设定的?用什
么语法?
MyBatis 里面的动态 Sql 一般是通过 if 节点来实现,通过 OGNL 语法来实现,但是如
果要写的完整,必须配合 where,trim 节点,where 节点是判断包含节点有内容就插入
where,否则不插入,trim 节点是用来判断如果动态语句是以 and 或 or 开始,那么会自动
把这个 and 或者 or 取掉。
Mybatis 是如何将 sql 执行结果封装为目标对
象并返回的?都有哪些映射形式?
第一种是使用标签,逐一定义列名和对象属性名之间的映射关系。
第二种是使用 sql 列的别名功能,将列别名书写为对象属性名,比如 T_NAME AS NAME,
对象属性名一般是 name,小写,但是列名不区分大小写,Mybatis 会忽略列名大小写,智
能找到与之对应对象属性名,你甚至可以写成 T_NAME AS NaMe,Mybatis 一样可以正常工
作。 有了列名与属性名的映射关系后,Mybatis 通过反射创建对象,同时使用反射给对象
的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
Xml 映射文件中,除了常见的
select|insert|updae|delete 标签之外,还有哪些
标签?
还有很多其他的标签,、、、、,
加上动态 sql 的 9 个标签,trim|where|set|foreach|if|choose|when|otherwise|bind
等,其中为 sql 片段标签,通过标签引入 sql 片段,为不支
持自增的主键生成策略标签。
当实体类中的属性名和表中的字段名不一样,如
果将查询的结果封装到指定 pojo?
1)通过在查询的 sql 语句中定义字段名的别名。
2)通过来映射字段名和实体类属性名的一一对应的关系。
模糊查询 like 语句该怎么写
1)在 Java 中拼接通配符,通过#{}赋值
2)在 Sql 语句中拼接通配符 (不安全 会引起 Sql 注入)
通常一个 Xml 映射文件,都会写一个 Dao 接口
与之对应, Dao 的工作原理,是否可以重载?
不能重载,因为通过 Dao 寻找 Xml 对应的 sql 的时候全限名+方法名的保存和寻找策
略。接口工作原理为 jdk 动态代理原理,运行时会为 dao 生成 proxy,代理对象会拦
截接口方法,去执行对应的 sql 返回数据。
Mybatis 映射文件中,如果 A 标签通过
include 引用了 B 标签的内容,请问,B 标签能否
定义在 A 标签的后面,还是说必须定义在 A 标签的
前面?
虽然 Mybatis 解析 Xml 映射文件是按照顺序解析的,但是,被引用的 B 标签依然可
以定义在任何地方,Mybatis 都可以正确识别。原理是,Mybatis 解析 A 标签,发现 A 标
签引用了 B 标签,但是 B 标签尚未解析到,尚不存在,此时,Mybatis 会将 A 标签标记
为未解析状态,然后继续解析余下的标签,包含 B 标签,待所有标签解析完毕,Mybatis 会
重新解析那些被标记为未解析的标签,此时再解析 A 标签时,B 标签已经存在,A 标签也
就可以正常解析完成了。
Mybatis 的 Xml 映射文件中,不同的 Xml 映射
文件,id 是否可以重复?
不同的 Xml 映射文件,如果配置了 namespace,那么 id 可以重复;如果没有配置
namespace,那么 id 不能重复;毕竟 namespace 不是必须的,只是最佳实践而已。原因就
是 namespace+id 是作为 Map
namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。有了 namespace,自然 id 就
可以重复,namespace 不同,namespace+id 自然也就不同。
Mybatis 中如何执行批处理?
使用 BatchExecutor 完成批处理。
Mybatis 都有哪些 Executor 执行器?它们之
间的区别是什么?
Mybatis 有三种基本的 Executor 执行器, SimpleExecutor 、 ReuseExecutor 、
BatchExecutor。1)SimpleExecutor:每执行一次 update 或 select,就开启一个 Statement
对象,用完立刻关闭 Statement 对象。2)ReuseExecutor:执行 update 或 select,以 sql
作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement
对象,而是放置于 Map3)BatchExecutor:完成批处理。
Mybatis 中如何指定使用哪一种 Executor 执
行器?
在 Mybatis 配置文件中,可以指定默认的 ExecutorType 执行器类型,也可以手动给
DefaultSqlSessionFactory 的创建 SqlSession 的方法传递 ExecutorType 类型参数。
Mybatis 执行批量插入,能返回数据库主键列表
吗?
能,JDBC 都能,Mybatis 当然也能。
Mybatis 是否可以映射 Enum 枚举类?
Mybatis 可以映射枚举类,不单可以映射枚举类,Mybatis 可以映射任何对象到表的一
列上。映射方式为自定义一个 TypeHandler,实现 TypeHandler 的 setParameter()和
getResult()接口方法。TypeHandler 有两个作用,一是完成从 JavaType 至 jdbcType 的
转换,二是完成 jdbcType 至 JavaType 的转换,体现为 setParameter()和 getResult()
两个方法,分别代表设置 sql 问号占位符参数和获取列查询结果。
如何获取自动生成的(主)键值?
配置文件设置 usegeneratedkeys 为 true
在 mapper 中如何传递多个参数?
1)直接在方法中传递参数,xml 文件用#{0} #{1}来获取
2)使用 @param 注解:这样可以直接在 xml 文件中通过#{name}来获取
32、resultType resultMap 的区别?
1)类的名字和数据库相同时,可以直接设置 resultType 参数为 Pojo 类
2)若不同,需要设置 resultMap 将结果名字和 Pojo 名字进行转换
使用 MyBatis 的 mapper 接口调用时有哪些要
求?
1)Mapper 接口方法名和 mapper.xml 中定义的每个 sql 的 id 相同
2 ) Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的
parameterType 的
类型相同
3)Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的 resultType
的类型相同
Mapper.xml 文件中的 namespace 即是 mapper 接口的类路径。
Mybatis 比 IBatis 比较大的几个改进是什
么?
1)有接口绑定,包括注解绑定 sql 和 xml 绑定 Sql
2)动态 sql 由原来的节点配置变成 OGNL 表达式 3)
在一对一,一对多的时候引进了 association,在一对多的时候引入了 collection 节
点,不过都是在 resultMap 里面配置
IBatis 和 MyBatis 在核心处理类分别叫什
么?
IBatis 里面的核心处理类交 SqlMapClient,MyBatis 里面的核心处理类叫做
SqlSession。
IBatis 和 MyBatis 在细节上的不同有哪些?
1)在 sql 里面变量命名有原来的#变量# 变成了#{变量}
2)原来的 变 量 变量 变量变成了${变量}
3)原来在 sql 节点里面的 class 都换名字交 type
4)原来的 queryForObject queryForList 变成了 selectOne selectList5)原来的别
名设置在映射文件里面放在了核心配置文件里
Mysql 面试题目
1.数据库三范式是什么?
第一范式(1NF):字段具有原子性,不可再分。(所有关系型数据库系统都满足第一
范式数据库表中的字段都是单一属性的,不可再分)
第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)
必须先满足第一范式(1NF)。要求数据库表中的每个实例或行必须可以被惟一地区分。通
常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主关键字或主
键。
满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要
求一个数据库表中不包含已在其它表中已包含的非主关键字信息。>所以第三范式具有如下
特征: >>1. 每一列只有一个值 >>2. 每一行都能区分。 >>3. 每一个表都不包含其他表已
经包含的非主关键字信息。
2.有哪些数据库优化方面的经验?
用 PreparedStatement, 一般来说比 Statement 性能高:一个 sql 发给服务器去
执行,涉及步骤:语法检查、语义分析, 编译,缓存。
有外键约束会影响插入和删除性能,如果程序能够保证数据的完整性,那在设计数
据库时就去掉外键。
表中允许适当冗余,譬如,主题帖的回复数量和最后回复时间等
UNION ALL 要比 UNION 快很多,所以,如果可以确认合并的两个结果集中不包含重
复数据且不需要排序时的话,那么就使用 UNION ALL。 >>UNION 和 UNION ALL 关键字都是
将两个结果集合并为一个,但这两者从使用和效率上来说都有所不同。 >1. 对重复结果的
处理:UNION 在进行表链接后会筛选掉重复的记录,Union All 不会去除重复记录。 >2. 对
排序的处理:Union 将会按照字段的顺序进行排序;UNION ALL 只是简单的将两个结果合并
后就返回。
3.请简述常用的索引有哪些种类?
普通索引: 即针对数据库表创建索引
唯一索引: 与普通索引类似,不同的就是:MySQL 数据库索引列的值必须唯一,但
允许有空值
主键索引: 它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创
建主键索引
组合索引: 为了进一步榨取 MySQL 的效率,就要考虑建立组合索引。即将数据库表
中的多个字段联合起来作为一个组合索引。
4.以及在 mysql 数据库中索引的工作机制是什么?
数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库
表中数据。索引的实现通常使用 B 树及其变种 B+树
MySQL 的基础操作命令:
MySQL 是否处于运行状态:Debian 上运行命令 service mysql status,在 RedHat
上运行命令 service mysqld status
开启或停止 MySQL 服务 :运行命令 service mysqld start 开启服务;运行命令
service mysqld stop 停止服务
Shell 登入 MySQL: 运行命令 mysql -u root -p
列出所有数据库:运行命令 show databases;
切换到某个数据库并在上面工作:运行命令 use databasename; 进入名为
databasename 的数据库
列出某个数据库内所有表: show tables;
获取表内所有 Field 对象的名称和类型 :describe table_name;
mysql 的复制原理以及流程。
Mysql 内建的复制功能是构建大型,高性能应用程序的基础。将 Mysql 的数据分布到
多个系统上去,这种分布的机制,是通过将 Mysql 的某一台主机的数据复制到其它主机
(slaves)上,并重新执行一遍来实现的。 * 复制过程中一个服务器充当主服务器,而一
个或多个其它服务器充当从服务器。主服务器将更新写入二进制日志文件,并维护文件的一
个索引以跟踪日志循环。这些日志可以记录发送到从服务器的更新。 当一个从服务器连接
主服务器时,它通知主服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那
时起发生的任何更新,然后封锁并等待主服务器通知新的更新。
过程如下
主服务器把更新记录到二进制日志文件中。
从服务器把主服务器的二进制日志拷贝到自己的中继日志(replay log)中。
从服务器重做中继日志中的时间,把更新应用到自己的数据库上。
mysql 支持的复制类型?
基于语句的复制: 在主服务器上执行的 SQL 语句,在从服务器上执行同样的语句。
MySQL 默认采用基于语句的复制,效率比较高。 一旦发现没法精确复制时,会自动选着基
于行的复制。
基于行的复制:把改变的内容复制过去,而不是把命令在从服务器上执行一遍. 从
mysql5.0 开始支持
混合类型的复制: 默认采用基于语句的复制,一旦发现基于语句的无法精确的复制
时,就会采用基于行的复制。
mysql 中 myisam 与 innodb 的区别?
事务支持 > MyISAM:强调的是性能,每次查询具有原子性,其执行数度比 InnoDB 类
型更快,但是不提供事务支持。 > InnoDB:提供事务支持事务,外部键等高级数据库功能。
具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事
务安全(transaction-safe (ACID compliant))型表。
InnoDB 支持行级锁,而 MyISAM 支持表级锁. >> 用户在操作 myisam 表时,select,
update,delete,insert 语句都会给表自动加锁,如果加锁以后的表满足 insert 并发的
情况下,可以在表的尾部插入新的数据。
InnoDB 支持 MVCC, 而 MyISAM 不支持
InnoDB 支持外键,而 MyISAM 不支持
表主键 > MyISAM:允许没有任何索引和主键的表存在,索引都是保存行的地址。 >
InnoDB:如果没有设定主键或者非空唯一索引,就会自动生成一个 6 字节的主键(用户不可
见),数据是主索引的一部分,附加索引保存的是主索引的值。
InnoDB 不支持全文索引,而 MyISAM 支持。
可移植性、备份及恢复 > MyISAM:数据是以文件的形式存储,所以
在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进
行操作。 > InnoDB:免费的方案可以是拷贝数据文件、备份
binlog,或者用 mysqldump,在数据量达到几十 G 的时候就相对痛
苦了
存储结构 > MyISAM:每个 MyISAM 在磁盘上存储成三个文件。第一个文件的名字以
表的名字开始,扩展名指出文件类型。.frm 文件存储表定义。数据文件的扩展名为.MYD
(MYData)。索引文件的扩展名是.MYI (MYIndex)。 > InnoDB:所有的表都保存在同一个数
据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB 表的大小只受限于操
作系统文件的大小,一般为 2GB。
mysql中varchar与char的区别以及 varchar(50)
中的 50 代表的涵义?
varchar 与 char 的区别: char 是一种固定长度的类型,varchar 则是一种可变长
度的类型.
varchar(50)中 50 的涵义 : 最多存放 50 个字节
int(20)中 20 的涵义: int(M)中的 M indicates the maximum display width (最
大显示宽度)for integer types. The maximum legal display width is 255.
MySQL 中 InnoDB 支持的四种事务隔离级别名
称,以及逐级之间的区别?
Read Uncommitted(读取未提交内容)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用
于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读
(Dirty Read)。
Read Committed(读取提交内容)
这是大多数数据库系统的默认隔离级别(但不是 MySQL 默认的)。它满足了隔离的简
单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复
读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的
commit,所以同一 select 可能返回不同结果。
Repeatable Read(可重读)
这是 MySQL 的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会
看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读(PhantomRead)。简
单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当
用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB 和 Falcon 存储引擎通
过多版本并发控制(MVCC,Multiversion Concurrency Control 间隙锁)机制解决了该问
题。注:其实多版本只是解决不可重复读问题,而加上间隙锁(也就是它这里所谓的并发控
制)才解决了幻读问题。
Serializable(可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问
题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象
和锁竞争。
表中有大字段 X(例如:text 类型),且字段 X
不会经常更新,以读为主,将该字段拆成子表好处是
什么?
如果字段里面有大字段(text,blob)类型的,而且这些字段的访问并不多,这时候放在
一起就变成缺点了。MYSQL 数据库的记录存储是按行存储的,数据块大小又是固定的(16K),
每条记录越小,相同的块存储的记录就越多。此时应该把大字段拆走,这样应付大部分小字
段的查询时,就能提高效率。当需要查询大字段时,此时的关联查询是不可避免的,但也是
值得的。拆分开后,对字段的 UPDAE 就要 UPDATE 多个表了
MySQL 中 InnoDB 引擎的行锁是通过加在什么
上完成(或称实现)的?
InnoDB 行锁是通过给索引上的索引项加锁来实现的,这一点 MySQL 与 Oracle 不同,
后者是通过在数据块中对相应数据行加锁来实现的。InnoDB 这种行锁实现特点意味着:只
有通过索引条件检索数据,InnoDB 才使用行级锁,否则,InnoDB 将使用表锁!
若一张表中只有一个字段 VARCHAR(N)类型,
utf8 编码,则 N 最大值为多少(精确到数量级即
可)?
由于 utf8 的每个字符最多占用 3 个字节。而 MySQL 定义行的长度不能超过 65535,
因此 N 的最大值计算方法为:(65535-1-2)/3。减去 1 的原因是实际存储从第二个字节开
始,减去 2 的原因是因为要在列表长度存储实际的字符长度,除以 3 是因为 utf8 限制:
每个字符最多占用 3 个字节。
[SELECT *] 和[SELECT 全部字段]的 2 种写法
有何优缺点?
前者要解析数据字典,后者不需要
结果输出顺序,前者与建表列顺序相同,后者按指定字段顺序。
表字段改名,前者不需要修改,后者需要改
后者可以建立索引进行优化,前者无法优化
后者的可读性比前者要高
HAVNG 子句 和 WHERE 的异同点?
语法上:where 用表中列名,having 用 select 结果别名
影响结果范围:where 从表读出数据的行数,having 返回客户端的行数
索引:where 可以使用索引,having 不能使用索引,只能在临时结果集操作
where 后面不能使用聚集函数,having 是专门使用聚集函数的。
MySQL 当记录不存在时 insert,当记录存在时
update,语句怎么写?
INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY
UPDATE c=c+1;
一张表,里面有 ID 自增主键,当 insert 了 17
条记录之后,删除了第 15,16,17 条记录,再把
Mysql 重启,再 insert 一条记录,这条记录的 ID
是 18 还是 15 ?
(1)如果表的类型是 MyISAM,那么是 18
因为 MyISAM 表会把自增主键的最大 ID 记录到数据文件里,重启 MySQL 自增主键的
最大 ID 也不会丢失
(2)如果表的类型是 InnoDB,那么是 15
InnoDB 表只是把自增主键的最大 ID 记录到内存中,所以重启数据库或者是对表进行
OPTIMIZE 操作,都会导致最大 ID 丢失
Mysql 的技术特点是什么?
Mysql 数据库软件是一个客户端或服务器系统,其中包括:支持各种客户端程序和库的
多线程 SQL 服务器、不同的后端、广泛的应用程序编程接口和管理工具。
Heap 表是什么?
HEAP 表存在于内存中,用于临时高速存储。BLOB 或 TEXT 字段是不允许的,只能使用
比较运算符=,<,>,=>,= < HEAP 表不支持 AUTO_INCREMENT 索引不可为 NULL
Mysql 服务器默认端口是什么?
Mysql 服务器的默认端口是 3306。
与 Oracle 相比,Mysql 有什么优势?
Mysql 是开源软件,随时可用,无需付费。
Mysql 是便携式的
带有命令提示符的 GUI。
使用 Mysql 查询浏览器支持管理
如何区分 FLOAT 和 DOUBLE?
以下是 FLOAT 和 DOUBLE 的区别:
浮点数以 8 位精度存储在 FLOAT 中,并且有四个字节。
浮点数存储在 DOUBLE 中,精度为 18 位,有八个字节。
区分 CHAR_LENGTH 和 LENGTH?
CHAR_LENGTH 是字符数,而 LENGTH 是字节数。Latin 字符的这两个数据是相同的,但
是对于 Unicode 和其他编码,它们是不同的。
请简洁描述 Mysql 中 InnoDB 支持的四种事务
隔离级别名称,以及逐级之间的区别?
SQL 标准定义的四个隔离级别为:
read uncommited :读到未提交数据
read committed:脏读,不可重复读
repeatable read:可重读
serializable :串行事物
在 Mysql 中 ENUM 的用法是什么?
ENUM 是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用。Create
table size(name ENUM('Smail,‘Medium’,‘Large’);
如何定义 REGEXP?
REGEXP 是模式匹配,其中匹配模式在搜索值的任何位置。
CHAR 和 VARCHAR 的区别?
以下是 CHAR 和 VARCHAR 的区别:
CHAR 和 VARCHAR 类型在存储和检索方面有所不同
CHAR 列长度固定为创建表时声明的长度,长度值范围是 1 到 255
当 CHAR 值被存储时,它们被用空格填充到特定长度,检索 CHAR 值时需删除尾随空格。
列的字符串类型可以是什么?
字符串类型是:
SET
BLOB
ENUM
CHAR
TEXT
VARCHAR
如何获取当前的 Mysql 版本?
SELECT VERSION();用于获取当前 Mysql 的版本。
Mysql 中使用什么存储引擎?
存储引擎称为表类型,数据使用各种技术存储在文件中。
技术涉及:
Storage mechanism
Locking levels
Indexing
Capabilities and functions.
Mysql 驱动程序是什么?
以下是 Mysql 中可用的驱动程序:
PHP 驱动程序
JDBC 驱动程序
ODBC 驱动程序
CWRAPPER
PYTHON 驱动程序
PERL 驱动程序
RUBY 驱动程序
CAP11PHP 驱动程序
Ado.net5.mxj
TIMESTAMP 在 UPDATE CURRENT_TIMESTAMP 数
据类型上做什么?
创建表时 TIMESTAMP 列用 Zero 更新。只要表中的其他字段发生更改,UPDATE
CURRENT_TIMESTAMP 修饰符就将时间戳字段更新为当前时间。
主键和候选键有什么区别?
表格的每一行都由主键唯一标识,一个表只有一个主键。主键也是候选键。按照惯例,
候选键可以被指定为主键,并且可以用于任何外键引用。
如何使用 Unix shell 登录 Mysql?
我们可以通过以下命令登录:
[mysql dir]/bin/mysql -h hostname -u
myisamchk 是用来做什么的?
它用来压缩 MyISAM 表,这减少了磁盘或内存使用。
如何控制 HEAP 表的最大尺寸?
Heal 表的大小可通过称为 max_heap_table_size 的 Mysql 配置变量来控制。
MyISAM Static 和 MyISAM Dynamic 有什么区
别?
在 MyISAM Static 上的所有字段有固定宽度。动态 MyISAM 表将具有像 TEXT,BLOB 等
字段,以适应不同长度的数据类型。MyISAM Static 在受损情况下更容易恢复。
federated 表是什么?
federated 表,允许访问位于其他服务器数据库上的表。
如果一个表有一列定义为 TIMESTAMP,将发生什
么?
每当行被更改时,时间戳字段将获取当前时间戳。
列设置为 AUTO INCREMENT 时,如果在表中达到
最大值,会发生什么情况?
它会停止递增,任何进一步的插入都将产生错误,因为密钥已被使用。
怎样才能找出最后一次插入时分配了哪个自动
增量?
LAST_INSERT_ID 将返回由 Auto_increment 分配的最后一个值,并且不需要指定表名
称。
你怎么看到为表格定义的所有索引?
索引是通过以下方式为表格定义的:
SHOW INDEX FROM
LIKE 声明中的%和_是什么意思?
%对应于 0 个或更多字符,_只是 LIKE 语句中的一个字符。
如何在 Unix 和 Mysql 时间戳之间进行转换?
UNIX_TIMESTAMP 是从 Mysql 时间戳转换为 Unix 时间戳的命令
FROM_UNIXTIME 是从 Unix 时间戳转换为 Mysql 时间戳的命令
列对比运算符是什么?
在 SELECT 语句的列比较中使用=,<>,<=,<,> =,>,<<,>>,<=>,AND,OR 或 LIKE
运算符。
我们如何得到受查询影响的行数?
行数可以通过以下代码获得:
SELECT COUNT(user_id)FROM users;
Mysql 查询是否区分大小写?
不区分
SELECT VERSION(), CURRENT_DATE;
SeLect version(), current_date;
seleCt vErSiOn(), current_DATE;
所有这些例子都是一样的,Mysql 不区分大小写。
LIKE 和 REGEXP 操作有什么区别?
LIKE 和 REGEXP 运算符用于表示^和%。
SELECT * FROM employee WHERE emp_name REGEXP “^b”;
SELECT * FROM employee WHERE emp_name LIKE “%b”;
BLOB 和 TEXT 有什么区别?
BLOB 是一个二进制对象,可以容纳可变数量的数据。有四种类型的 BLOB -
TINYBLOB
BLOB
MEDIUMBLOB 和
LONGBLOB
它们只能在所能容纳价值的最大长度上有所不同。
TEXT 是一个不区分大小写的 BLOB。四种 TEXT 类型
TINYTEXT
TEXT
MEDIUMTEXT 和
LONGTEXT
它们对应于四种 BLOB 类型,并具有相同的最大长度和存储要求。BLOB 和 TEXT 类型
之间的唯一区别在于对 BLOB 值进行排序和比较时区分大小写,对 TEXT
值不区分大小写。
mysql_fetch_array 和 mysql_fetch_object
的区别是什么?
以下是 mysql_fetch_array 和 mysql_fetch_object 的区别:
mysql_fetch_array() - 将结果行作为关联数组或来自数据库的常规数组返回。
mysql_fetch_object - 从数据库返回结果行作为对象。
我们如何在 mysql 中运行批处理模式?
以下命令用于在批处理模式下运行:
mysql;
mysql mysql.out
MyISAM 表格将在哪里存储,并且还提供其存储
格式?
每个 MyISAM 表格以三种格式存储在磁盘上:
·“.frm”文件存储表定义
·数据文件具有“.MYD”(MYData)扩展名
索引文件具有“.MYI”(MYIndex)扩展名
Mysql 中有哪些不同的表格?
共有 5 种类型的表格:
MyISAM
Heap
Merge
INNODB
ISAM
MyISAM 是 Mysql 的默认存储引擎。
ISAM 是什么?
ISAM 简称为索引顺序访问方法。它是由 IBM 开发的,用于在磁带等辅助存储系统上存
储和检索数据。
InnoDB 是什么?
lnnoDB 是一个由 Oracle 公司开发的 Innobase Oy 事务安全存储引擎。
Mysql 如何优化 DISTINCT?
DISTINCT 在所有列上转换为 GROUP BY,并与 ORDER BY 子句结合使用。
1
SELECT DISTINCT t1.a FROM t1,t2 where t1.a=t2.a;
如何输入字符为十六进制数字?
如果想输入字符为十六进制数字,可以输入带有单引号的十六进制数字和前缀(X),
或者只用(Ox)前缀输入十六进制数字。
如果表达式上下文是字符串,则十六进制数字串将自动转换为字符串。
如何显示前 50 行?
在 Mysql 中,使用以下代码查询显示前 50 行:
SELECT*FROM
LIMIT 0,50;
可以使用多少列创建索引?
任何标准表最多可以创建 16 个索引列。
NOW()和 CURRENT_DATE()有什么区别?
NOW()命令用于显示当前年份,月份,日期,小时,分钟和秒。
CURRENT_DATE()仅显示当前年份,月份和日期。
什么样的对象可以使用 CREATE 语句创建?
以下对象是使用 CREATE 语句创建的:
DATABASE
EVENT
FUNCTION
INDEXPROCEDURE
TABLE
TRIGGER
USER
VIEW
Mysql 表中允许有多少个 TRIGGERS?
在 Mysql 表中允许有六个触发器,如下:
BEFORE INSERT
AFTER INSERT
BEFORE UPDATE
AFTER UPDATE
BEFORE DELETE
AFTER DELETE
什么是非标准字符串类型?
以下是非标准字符串类型:
TINYTEXT
TEXT
MEDIUMTEXT
LONGTEXT
什么是通用 SQL 函数?
CONCAT(A, B) - 连接两个字符串值以创建单个字符串输出。通常用于将两个或多个字
段合并为一个字段。
FORMAT(X, D)- 格式化数字 X 到 D 有效数字。
CURRDATE(), CURRTIME()- 返回当前日期或时间。
NOW() - 将当前日期和时间作为一个值返回。
MONTH(),DAY(),YEAR(),WEEK(),WEEKDAY() - 从日期值中提取给定数据。
HOUR(),MINUTE(),SECOND() - 从时间值中提取给定数据。
DATEDIFF(A,B) - 确定两个日期之间的差异,通常用于计算年龄
SUBTIMES(A,B) - 确定两次之间的差异。
FROMDAYS(INT) - 将整数天数转换为日期值。
解释访问控制列表
ACL(访问控制列表)是与对象关联的权限列表。这个列表是 Mysql 服务器安全模型的
基础,它有助于排除用户无法连接的问题。
Mysql 将 ACL(也称为授权表)缓存在内存中。当用户尝试认证或运行命令时,Mysql 会
按照预定的顺序检查 ACL 的认证信息和权限。
Mysql 支持事务吗?
在缺省模式下,MYSQL 是 autocommit 模式的,所有的数据库更新操作都会即时提交,
所以在缺省情况下,mysql 是不支持事务的。
但是如果你的 MYSQL 表类型是使用 InnoDB Tables 或 BDB tables 的话,你的 MYSQL
就可以使用事务处理,使用 SET AUTOCOMMIT=0 就可以使 MYSQL 允许在非 autocommit 模
式,在非 autocommit 模式下,你必须使用 COMMIT 来提交你的更改,或者用 ROLLBACK 来
回滚你的更改。
示例如下:
一
START TRANSACTION;
SELECT @A:=SUM(salary) FROM table1 WHERE type=1;
UPDATE table2 SET summmary=@A WHERE type=1;
COMMIT;
Mysql 里记录货币用什么字段类型好
NUMERIC 和 DECIMAL 类型被 Mysql 实现为同样的类型,这在 SQL92 标准允许。他们
被用于保存值,该值的准确精度是极其重要的值,例如与金钱有关的数据。当声明一个类是
这些类型之一时,精度和规模的能被(并且通常是)指定;
例如:
salary DECIMAL(9,2)
在这个例子中,9(precision)代表将被用于存储值的总的小数位数,而 2(scale)代表
将被用于存储小数点后的位数。
因此,在这种情况下,能被存储在 salary 列中的值的范围是从-9999999.99 到
9999999.99。
在 ANSI/ISO SQL92 中,句法 DECIMAL§等价于 DECIMAL(p,0)。
同样,句法 DECIMAL 等价于 DECIMAL(p,0),这里实现被允许决定值 p。Mysql 当前不
支持 DECIMAL/NUMERIC 数据类型的这些变种形式的任一种。
这一般说来不是一个严重的问题,因为这些类型的主要益处得自于明显地控制精度和规
模的能力。DECIMAL 和 NUMERIC 值作为字符串存储,而不是作为二进制浮点数,以便保存
那些值的小数精度。
一个字符用于值的每一位、小数点(如果 scale>0)和“-”符号(对于负值)。如果 scale
是 0,DECIMAL 和 NUMERIC 值不包含小数点或小数部分。DECIMAL 和 NUMERIC 值得最大的
范围与 DOUBLE 一样,但是对于一个给定的 DECIMAL 或
NUMERIC 列,实际的范围可由制由给定列的 precision 或 scale 限制。
当这样的列赋给了小数点后面的位超过指定 scale 所允许的位的值,该值根据 scale
四舍五入。
当一个 DECIMAL 或 NUMERIC 列被赋给了其大小超过指定(或缺省的)precision 和
scale 隐含的范围的值,Mysql 存储表示那个范围的相应的端点值。
我希望本文可以帮助你提升技术水平。那些,感觉学的好难,甚至会令你沮丧的人,别
担
心,我认为,如果你愿意试一试本文介绍的几点,会向前迈进,克服这种感觉。这些要
点
也许对你不适用,但你会明确一个重要的道理:接受自己觉得受困这个事实是摆脱这个
困
境的第一步。
Mysql 数据表在什么情况下容易损坏?
服务器突然断电导致数据文件损坏。
强制关机,没有先关闭 mysql 服务等。
Mysql 有关权限的表都有哪几个?
Mysql 服务器通过权限表来控制用户对数据库的访问,权限表存放在 mysql 数据库里,
由 mysql_install_db 脚本初始化。这些权限表分别 user,db,table_priv,columns_priv
和 host。
Mysql 中有哪几种锁?
MyISAM 支持表锁,InnoDB 支持表锁和行锁,默认为行锁
表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发
量最低
行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高
Dubbo 面试题目
Dubbo 支持哪些协议,每种协议的应用场景,优缺
点?
dubbo: 单一长连接和 NIO 异步通讯,适合大并发小数据量的服务调用,以及消费者
远大于提供者。传输协议 TCP,异步,Hessian 序列化;
rmi: 采用 JDK 标准的 rmi 协议实现,传输参数和返回参数对象需要实现
Serializable 接口,使用 Java 标准序列化机制,使用阻塞式短连接,传输数据包大小混
合,消费者和提供者个数差不多,可传文件,传输协议 TCP。多个短连接,TCP 协议传输,
同步传输,适用常规的远程服务调用和 rmi 互操作。在依赖低版本的 Common-Collections
包,Java 序列化存在安全漏洞;
webservice: 基于 WebService 的远程调用协议,集成 CXF 实现,提供和原生
WebService 的互操作。多个短连接,基于 HTTP 传输,同步传输,适用系统集成和跨语言
调用;
http: 基于 Http 表单提交的远程调用协议,使用 Spring 的 HttpInvoke 实现。多
个短连接,传输协议 HTTP,传入参数大小混合,提供者个数多于消费者,需要给应用程序
和浏览器 JS 调用;
hessian: 集成 Hessian 服务,基于 HTTP 通讯,采用 Servlet 暴露服务,Dubbo 内
嵌 Jetty 作为服务器时默认实现,提供与 Hession 服务互操作。多个短连接,同步 HTTP 传
输,Hessian 序列化,传入参数较大,提供者大于消费者,提供者压力较大,可传文件;
memcache: 基于 memcached 实现的 RPC 协议
redis: 基于 redis 实现的 RPC 协议
Dubbo 超时时间怎样设置?
Dubbo 超时时间设置有两种方式:
服务提供者端设置超时时间,在 Dubbo 的用户文档中,推荐如果能在服务端多配置就
尽量多配置,因为服务提供者比消费者更清楚自己提供的服务特性。
服务消费者端设置超时时间,如果在消费者端设置了超时时间,以消费者端为主,即优
先级更高。因为服务调用方设置超时时间控制性更灵活。如果消费方超时,服务端线程不会
定制,会产生警告。
Dubbo 有些哪些注册中心?
Multicast 注册中心: Multicast 注册中心不需要任何中心节点,只要广播地址,就
能进行服务注册和发现。基于网络中组播传输实现;
Zookeeper 注册中心: 基于分布式协调系统 Zookeeper 实现,采用 Zookeeper 的
watch 机制实现数据变更;
redis 注册中心: 基于 redis 实现,采用 key/Map 存储,住 key 存储服务名和类
型,Map 中 key 存储服务 URL,value 服务过期时间。基于 redis 的发布/订阅模式通知
数据变更;
Simple 注册中心
Dubbo 集群的负载均衡有哪些策略 Dubbo 提供了常见的集群策略实现,并预扩展点
予以自行实现。
Random LoadBalance: 随机选取提供者策略,有利于动态调整提供者权重。截面碰撞
率高,调用次数越多,分布越均匀;
RoundRobin LoadBalance: 轮循选取提供者策略,平均分布,但是存在请求累积的问
题;
LeastActive LoadBalance: 最少活跃调用策略,解决慢提供者接收更少的请求;
ConstantHash LoadBalance: 一致性 Hash 策略,使相同参数请求总是发到同一提供
者,一台机器宕机,可以基于虚拟节点,分摊至其他提供者,避免引起提供者的剧烈变动;
Dubbo 是什么?
Dubbo 是一个分布式、高性能、透明化的 RPC 服务框架,提供服务自动注册、自动发
现等高效服务治理方案, 可以和 Spring 框架无缝集成。
Dubbo 的主要应用场景?
透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任
何 API 侵入。
软负载均衡及容错机制,可在内网替代 F5 等硬件负载均衡器,降低成本,减少单点。
服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提
供者的 IP 地址,并且能够平滑添加或删除服务提供者。
Dubbo 的核心功能?
主要就是如下 3 个核心功能:
Remoting:网络通信框架,提供对多种 NIO 框架抽象封装,包括“同步转异步”和“请
求-响应”模式的信息交换方式。
Cluster:服务框架,提供基于接口方法的透明远程过程调用,包括多协议支持,以及
软负载均衡,失败容错,地址路由,动态配置等集群支持。
Registry:服务注册,基于注册中心目录服务,使服务消费方能动态的查找服务提供方,
使地址透明,使服务提供方可以平滑增加或减少机器。
?
Dubbo 服务注册与发现的流程?流程说明:
Provider(提供者)绑定指定端口并启动服务
指供者连接注册中心,并发本机 IP、端口、应用信息和提供服务信息发送至注册中心
存储
Consumer(消费者),连接注册中心 ,并发送应用信息、所求服务信息至注册中心
注册中心根据 消费 者所求服务信息匹配对应的提供者列表发送至 Consumer 应用缓
存。
Consumer 在发起远程调用时基于缓存的消费者列表择其一发起调用。
Provider 状态变更会实时通知注册中心、在由注册中心实时推送至 Consumer
设计的原因:
Consumer 与 Provider 解偶,双方都可以横向增减节点数。
注册中心对本身可做对等集群,可动态增减节点,并且任意一台宕掉后,将自动切换到
另一台
去中心化,双方不直接依懒注册中心,即使注册中心全部宕机短时间内也不会影响服务
的调用
服务提供者无状态,任意一台宕掉后,不影响使用
Dubbo 的架构设计?
Dubbo 框架设计一共划分了 10 个层:
服务接口层(Service):该层是与实际业务逻辑相关的,根据服务提供方和服务消费
方的业务设计对应的接口和实现。
配置层(Config):对外配置接口,以 ServiceConfig 和 ReferenceConfig 为中心。
服务代理层(Proxy):服务接口透明代理,生成服务的客户端 Stub 和服务器端
Skeleton。
服务注册层(Registry):封装服务地址的注册与发现,以服务 URL 为中心。
集群层(Cluster):封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker
为中心。
监控层(Monitor):RPC 调用次数和调用时间监控。
远程调用层(Protocol):封将 RPC 调用,以 Invocation 和 Result 为中心,扩展
接口为 Protocol、Invoker 和 Exporter。
信息交换层(Exchange):封装请求响应模式,同步转异步,以 Request 和 Response
为中心。
网络传输层(Transport):抽象 mina 和 netty 为统一接口,以 Message 为中心。
Dubbo 的服务调用流程?Dubbo 支持哪些协议,每
种协议的应用场景,优缺点?
dubbo: 单一长连接和 NIO 异步通讯,适合大并发小数据量的服务调用,以及消费者
远大于提供者。传输协议 TCP,异步,Hessian 序列化;
rmi: 采用 JDK 标准的 rmi 协议实现,传输参数和返回参数对象需要实现
Serializable 接口,使用 Java 标准序列化机制,使用阻塞式短连接,传输数据包大小混
合,消费者和提供者个数差不多,可传文件,传输协议 TCP。 多个短连接,TCP 协议传输,
同步传输,适用常规的远程服务调用和 rmi 互操作。在依赖低版本的 Common-Collections
包,Java 序列化存在安全漏洞;
webservice: 基于 WebService 的远程调用协议,集成 CXF 实现,提供和原生
WebService 的互操作。多个短连接,基于 HTTP 传输,同步传输,适用系统集成和跨语言
调用;
http: 基于 Http 表单提交的远程调用协议,使用 Spring 的 HttpInvoke 实现。多
个短连接,传输协议 HTTP,传入参数大小混合,提供者个数多于消费者,需要给应用程序
和浏览器 JS 调用;
hessian: 集成 Hessian 服务,基于 HTTP 通讯,采用 Servlet 暴露服务,Dubbo 内
嵌 Jetty 作为服务器时默认实现,提供与 Hession 服务互操作。多个短连接,同步 HTTP 传
输,Hessian 序列化,传入参数较大,提供者大于消费者,提供者压力较大,可传文件;
memcache: 基于 memcached 实现的 RPC 协议
redis: 基于 redis 实现的 RPC 协议
dubbo 推荐用什么协议?
默认使用 dubbo 协议
Dubbo 有些哪些注册中心?
Multicast 注册中心: Multicast 注册中心不需要任何中心节点,只要广播地址,就
能进行服务注册和发现。基于网络中组播传输实现;
Zookeeper 注册中心: 基于分布式协调系统 Zookeeper 实现,采用 Zookeeper 的
watch 机制实现数据变更;
redis 注册中心: 基于 redis 实现,采用 key/Map 存储,住 key 存储服务名和类
型,Map 中 key 存储服务 URL,value 服务过期时间。基于 redis 的发布/订阅模式通知
数据变更;
Simple 注册中心
Dubbo 默认采用注册中心?
采用 Zookeeper
为什么需要服务治理?
过多的服务 URL 配置困难
负载均衡分配节点压力过大的情况下也需要部署集群
服务依赖混乱,启动顺序不清晰
过多服务导致性能指标分析难度较大,需要监控
Dubbo 的注册中心集群挂掉,发布者和订阅者之
间还能通信么?
可以的,启动 dubbo 时,消费者会从 zookeeper 拉取注册的生产者的地址接口等数据,
缓存在本地。每次调用时,按照本地存储的地址进行调用。
Dubbo 与 Spring 的关系?
Dubbo 采用全 Spring 配置方式,透明化接入应用,对应用没有任何 API 侵入,只需
用 Spring 加载 Dubbo 的配置即可,Dubbo 基于 Spring 的 Schema 扩展进行加载。
Dubbo 使用的是什么通信框架?
默认使用 NIO Netty 框架
Dubbo 集群提供了哪些负载均衡策略?
Random LoadBalance: 随机选取提供者策略,有利于动态调整提供者权重。截面碰撞
率高,调用次数越多,分布越均匀;
RoundRobin LoadBalance: 轮循选取提供者策略,平均分布,但是存在请求累积的问
题;? LeastActive LoadBalance: 最少活跃调用策略,解决慢提供者接收更少的请求;
ConstantHash LoadBalance: 一致性 Hash 策略,使相同参数请求总是发到同一提供
者,一台机器宕机,可以基于虚拟节点,分摊至其他提供者,避免引起提供者的剧烈变动;
缺省时为 Random 随机调用
Dubbo 的集群容错方案有哪些?
Failover Cluster
失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延
迟。
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记
录。
Failsafe Cluster
失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需
要浪费更多服务资源。可通过 forks=“2” 来设置最大并行数。
Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错 。通常用于通知所有提供者更
新缓存或日志等本地资源信息。
Dubbo 的默认集群容错方案?
Failover Cluster
Dubbo 支持哪些序列化方式?
默认使用 Hessian 序列化,还有 Duddo、FastJson、Java 自带序列化。
Dubbo 超时时间怎样设置?
Dubbo 超时时间设置有两种方式:
服务提供者端设置超时时间,在 Dubbo 的用户文档中,推荐如果能在服务端多配置就
尽量多配置,因为服务提供者比消费者更清楚自己提供的服务特性。
服务消费者端设置超时时间,如果在消费者端设置了超时时间,以消费者端为主,即优
先级更高。因为服务调用方设置超时时间控制性更灵活。如果消费方超时,服务端线程不会
定制,会产生警告。
服务调用超时问题怎么解决?
dubbo 在调用服务不成功时,默认是会重试两次的。
Dubbo 在安全机制方面是如何解决?
Dubbo 通过 Token 令牌防止用户绕过注册中心直连,然后在注册中心上管理授权。
Dubbo 还提供服务黑白名单,来控制服务所允许的调用方。
Dubbo 和 Dubbox 之间的区别?
dubbox 基于 dubbo 上做了一些扩展,如加了服务可 restful 调用,更新了开源组件
等。
Dubbo 和 Spring Cloud 的关系?
Dubbo 是 SOA 时代的产物,它的关注点主要在于服务的调用,流量分发、流量监控和
熔断。而 Spring Cloud 诞生于微服务架构时代,考虑的是微服务治理的方方面面,另外由
于依托了 Spirng、Spirng Boot 的优势之上,两个框架在开始目标就不一致,Dubbo 定位
服务治理、Spirng Cloud 是一个生态。
Dubbo 和 Spring Cloud 的区别?
最大的区别:Dubbo 底层是使用 Netty 这样的 NIO 框架,是基于 TCP 协议传输的,
配合以 Hession 序列化完成 RPC 通信。
而 SpringCloud 是基于 Http 协议+Rest 接口调用远程过程的通信,相对来说,Http
请求会有更大的报文,占的带宽也会更多。但是 REST 相比 RPC 更为灵活,服务提供方和
调用方的依赖只依靠一纸契
Dubbo 中 zookeeper 做注册中心,如果注册中
心集群都挂掉,发布者和订阅者之间还能通信么?
可以通信的,启动 dubbo 时,消费者会从 zk 拉取注册的生产者的地址接口等数据,
缓存在本地。每次调用时,按照本地存储的地址进行调用;
注册中心对等集群,任意一台宕机后,将会切换到另一台;注册中心全部宕机后,服务
的提供者和消费者仍能通过本地缓存通讯。服务提供者无状态,任一台 宕机后,不影响使
用;服务提供者全部宕机,服务消费者会无法使用,并无限次重连等待服务者恢复;
挂掉是不要紧的,但前提是你没有增加新的服务,如果你要调用新的服务,则是不能办
到的。
附文档截图:
dubbo 服务负载均衡策略?
l Random LoadBalance
随机,按权重设置随机概率。在一个截面上碰撞的概率高,但调用量越大分布越均匀,
而且按概率使用权重后也比
较均匀,有利于动态调整提供者权重。(权重可以在 dubbo 管控台配置)
l RoundRobin LoadBalance
轮循,按公约后的权重设置轮循比率。存在慢的提供者累积请求问题,比如:第二台机
器很慢,但没挂,当请求调
到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
l LeastActive LoadBalance
最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。使慢的提供者收到更
少请求,因为越慢的提供者的
调用前后计数差会越大。
l ConsistentHash LoadBalance
一致性 Hash,相同参数的请求总是发到同一提供者。当某一台提供者挂时,原本发往
该提供者的请求,基于虚拟节
点,平摊到其它提供者,不会引起剧烈变动。缺省只对第一个参数 Hash
Dubbo 在安全机制方面是如何解决的
Dubbo 通过 Token 令牌防止用户绕过注册中心直连,然后在注册中心上管理授权。
Dubbo 还提供服务黑白名单,来控制服务所允许的调用方。
dubbo 连接注册中心和直连的区别
在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需
要点对点直连,点对点直联方式,将以服务接口为单位,忽略注册中心的提供者列表,服务
注册中心,动态的注册和发现服务,使服务的位置透明,并通过在消费方获取服务提供方地
址列表,实现软负载均衡和 Failover, 注册中心返回服务提供者地址列表给消费者,如果
有变更,注册中心将基于长连接推送变更数据给消费者。
服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如
果调用失败,再选另一台调用。注册中心负责服务地址的注册与查找,相当于目录服务,服
务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,服务消费者向注册中
心获取服务提供者地址列表,并根据负载算法直接调用提供者,注册中心,服务提供者,服
务消费者三者之间均为长连接,监控中心除外,注册中心通过长连接感知服务提供者的存在,
服务提供者宕机,注册中心将立即推送事件通知消费者注册中心和监控中心全部宕机,不影
响已运行的提供者和消费者,消费者在本地缓存了提供者列表注册中心和监控中心都是可选
的,服务消费者可以直连服务提供者。
dubbo 服务集群配置(集群容错模式)
在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试。可以自行扩
展集群容错策略
l Failover Cluster(默认)
失败自动切换,当出现失败,重试其它服务器。(缺省)通常用于读操作,但重试会带来
更长延迟。可通过 retries="2"来设置重试次数(不含第一次)。
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记
录。
Failsafe Cluster
失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需
要浪费更多服务资源。可通过 forks="2"来设置最大并行数。
dubbo 通信协议 dubbo 协议为什么要消费者比
提供者个数多:
因 dubbo 协议采用单一长连接,假设网络为千兆网卡(1024Mbit=128MByte),根据测试
经验数据每条连接最多只能压满 7MByte(不同的环境可能不一样,供参考),理论上 1 个服
务提供者需要 20 个服务消费者才能压满网卡。
dubbo 通信协议 dubbo 协议为什么不能传大
包:
因 dubbo 协议采用单一长连接,如果每次请求的数据包大小为 500KByte,假设网络为
千兆网卡(1024Mbit=128MByte),每条连接最大 7MByte(不同的环境可能不一样,供参考),
单个服务提供者的 TPS(每秒处理事务数)最大为:128MByte / 500KByte = 262。单个消费
者调用单个服务提供者的 TPS(每秒处理事务数)最大为:7MByte / 500KByte = 14。如果能
接受,可以考虑使用,否则网络将成为瓶颈。
dubbo 通信协议 dubbo 协议为什么采用异步单
一长连接:
因为服务的现状大都是服务提供者少,通常只有几台机器,而服务的消费者多,可能整
个网站都在访问该服务,比如 Morgan 的提供者只有 6 台提供者,却有上百台消费者,每
天有 1.5 亿次调用,如果采用常规的 hessian 服务,服务提供者很容易就被压跨,通过单
一连接,保证单一消费者不会压死提供者,长连接,减少连接握手验证等,并使用异步 IO,
复用线程池,防止 C10K 问题。
dubbo 通信协议 dubbo 协议适用范围和适用场
景
适用范围:传入传出参数数据包较小(建议小于 100K),消费者比提供者个数多,单
一消费者无法压满提供者,尽量不要用 dubbo 协议传输大文件或超大字符串。
适用场景:常规远程服务方法调用
dubbo 协议补充:
连接个数:单连接
连接方式:长连接
传输协议:TCP
传输方式:NIO 异步传输
序列化:Hessian 二进制序列化
RMI 协议
RMI 协议采用 JDK 标准的 Java.rmi.*实现,采用阻塞式短连接和 JDK 标准序列化方
式,Java 标准的远程调用协议。
连接个数:多连接
连接方式:短连接
传输协议:TCP
传输方式:同步传输
序列化:Java 标准二进制序列化
适用范围:传入传出参数数据包大小混合,消费者与提供者个数差不多,可传文件。
适用场景:常规远程服务方法调用,与原生 RMI 服务互操作
Hessian 协议
Hessian 协议用于集成 Hessian 的服务,Hessian 底层采用 Http 通讯,采用 Servlet
暴露服务,Dubbo 缺省内嵌 Jetty 作为服务器实现基于 Hessian 的远程调用协议。
连接个数:多连接
连接方式:短连接
传输协议:HTTP
传输方式:同步传输
序列化:Hessian 二进制序列化适用范围:传入传出参数数据包较大,提供者比消费者
个数多,提供者压力较大,可传文件。
适用场景:页面传输,文件传输,或与原生 hessian 服务互操作
http
采用 Spring 的 HttpInvoker 实现基于 http 表单的远程调用协议。
连接个数:多连接
连接方式:短连接
传输协议:HTTP
传输方式:同步传输
序列化:表单序列化(JSON)
适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,
可用表单或 URL 传入参数,暂不支持传文件。
适用场景:需同时给应用程序和浏览器 JS 使用的服务。
Webservice
基于 CXF 的 frontend-simple 和 transports-http 实现基于 WebService 的远程调
用协议。
连接个数:多连接
连接方式:短连接
传输协议:HTTP
传输方式:同步传输
序列化:SOAP 文本序列化
适用场景:系统集成,跨语言调用。
Thrif
Thrift 是 Facebook 捐给 Apache 的一个 RPC 框架,当前 dubbo 支持的 thrift 协
议是对 thrift 原生协议的扩展,在原生协议的基础上添加了一些额外的头信息,比如
service name,magic number 等
MongoDB 面试题目
你说的 NoSQL 数据库是什么意思?NoSQL 与 RDBMS
直接有什么区别?为什么要使用和不使用 NoSQL 数
据库?说一说 NoSQL 数据库的几个优点?
NoSQL 是非关系型数据库,NoSQL = Not Only SQL。
关系型数据库采用的结构化的数据,NoSQL 采用的是键值对的方式存储数据。
在处理非结构化/半结构化的大数据时;在水平方向上进行扩展时;随时应对动态增加
的数据项时可以优
先考虑使用 NoSQL 数据库。
在考虑数据库的成熟度;支持;分析和商业智能;管理及专业性等问题时,应优先考虑
关系型数据库。
NoSQL 数据库有哪些类型?
NoSQL 数据库的类型
例如:MongoDB, Cassandra, CouchDB, Hypertable, Redis, Riak, Neo4j, HBASE,
Couchbase,MemcacheDB, RevenDB and Voldemort are the examples of NoSQL databases.
详细阅读。
MySQL 与 MongoDB 之间最基本的差别是什么?
MySQL 和 MongoDB 两者都是免费开源的数据库。MySQL 和 MongoDB 有许多基本差别包
括数据的表示(data representation),查询,关系,事务,schema 的设计和定义,标准化
(normalization),速度和性能。
通过比较 MySQL 和 MongoDB,实际上我们是在比较关系型和非关系型数据库,即数据
存储结构不同。
详细阅读
4.你怎么比较 MongoDB、CouchDB 及 CouchBase?
MongoDB 和 CouchDB 都是面向文档的数据库。MongoDB 和 CouchDB 都是开源 NoSQL
数据库的最典型代表。 除了都以文档形式存储外它们没有其他的共同点。MongoDB 和
CouchDB 在数据模型实现、接口、对象存储以及复制方法等方面有很多不同。
细节可以参见下面的链接:
MongDB vs CouchDB
CouchDB vs CouchBase
MongoDB 成为最好 NoSQL 数据库的原因是什么?
以下特点使得 MongoDB 成为最好的 NoSQL 数据库:
面向文件的
高性能
高可用性
易扩展性
丰富的查询语言
6.32 位系统上有什么细微差别?
journaling 会激活额外的内存映射文件。这将进一步抑制 32 位版本上的数据库大小。
因此,现在 journaling 在 32 位系统上默认是禁用的。
journal 回放在条目(entry)不完整时(比如恰巧
有一个中途故障了)会遇到问题吗?
每个 journal (group)的写操作都是一致的,除非它是完整的否则在恢复过程中它不会
回放。
分析器在 MongoDB 中的作用是什么?
MongoDB 中包括了一个可以显示数据库中每个操作性能特点的数据库分析器。通过这个
分析器你可以找到比预期慢的查询(或写操作);利用这一信息,比如,可以确定是否需要添
加索引。
9.名字空间(namespace)是什么?
MongoDB 存储 BSON 对象在丛集(collection)中。数据库名字和丛集名字以句点连结起
来叫做名字空间(namespace)。
10. 如果用户移除对象的属性,该属性是否从存储层
中删除?
是的,用户移除属性然后对象会重新保存(re-save())。
11. 能否使用日志特征进行安全备份?
是的。
12. 允许空值 null 吗?
对于对象成员而言,是的。然而用户不能够添加空值(null)到数据库丛集(collection)
因为空值不是对象。
然而用户能够添加空对象{}。
13. 更新操作立刻 fsync 到磁盘?
不会,磁盘写操作默认是延迟执行的。写操作可能在两三秒(默认在 60 秒内)后到达磁
盘。例如,如果一秒内数据库收到一千个对一个对象递增的操作,仅刷新磁盘一次。(注意,
尽管 fsync 选项在命令行和经过 getLastError_old 是有效的).
14. 如何执行事务/加锁?
MongoDB 没有使用传统的锁或者复杂的带回滚的事务,因为它设计的宗旨是轻量,快速
以及可预计的高性能。可以把它类比成 MySQL MylSAM 的自动提交模式。通过精简对事务的
支持,性能得到了提升,特别是在一个可能会穿过多个服务器的系统里。
15. 为什么我的数据文件如此庞大?
MongoDB 会积极的预分配预留空间来防止文件系统碎片。
16. 启用备份故障恢复需要多久?
从备份数据库声明主数据库宕机到选出一个备份数据库作为新的主数据库将花费 10
到 30 秒时间。这期间在主数据库上的操作将会失败–包括写入和强一致性读取(strong
consistent read)操作。然而,你还能在第二数据库上执行最终一致性查询(eventually
consistent query)(在 slaveOk 模式下),即使在这段时间里。
17. 什么是 master 或 primary?
它是当前备份集群(replica set)中负责处理所有写入操作的主要节点/成员。在一个备
份集群中,当失效备援(failover)事件发生时,一个另外的成员会变成 primary。
18. 什么是 secondary 或 slave?
Seconday 从当前的 primary 上复制相应的操作。它是通过跟踪复制
oplog(local.oplog.rs)做到的。
19. 我必须调用 getLastError 来确保写操作生效
了么?
不用。不管你有没有调用 getLastError(又叫"Safe Mode")服务器做的操作都一样。调
用 getLastError 只是为了确认写操作成功提交了。当然,你经常想得到确认,但是写操作
的安全性和是否生效不是由这个决定的。
20. 我应该启动一个集群分片(sharded)还是一个非
集群分片的 MongoDB 环境?
为开发便捷起见,我们建议以非集群分片(unsharded)方式开始一个 MongoDB 环境,除
非一台服务器不足以存放你的初始数据集。从非集群分片升级到集群分片(sharding)是无缝
的,所以在你的数据集还不是很大的时候没必要考虑集群分片(sharding)。
21. 分片(sharding)和复制(replication)是怎样工
作的?
每一个分片(shard)是一个分区数据的逻辑集合。分片可能由单一服务器或者集群组成,
我们推荐为每一个分片(shard)使用集群。
22. 数据在什么时候才会扩展到多个分片(shard)
里?
MongoDB 分片是基于区域(range)的。所以一个集合(collection)中的所有的对象都被
存放到一个块(chunk)中。只有当存在多余一个块的时候,才会有多个分片获取数据的选项。
现在,每个默认块的大小是 64Mb,所以你需要至少 64 Mb 空间才可以实施一个迁移。
23. 当我试图更新一个正在被迁移的块(chunk)上的
文档时会发生什么?
更新操作会立即发生在旧的分片(shard)上,然后更改才会在所有权转移(ownership
transfers)前复制到新的分片上。
24. 如果在一个分片(shard)停止或者很慢的时候,
我发起一个查询会怎样?
如果一个分片(shard)停止了,除非查询设置了“Partial”选项,否则查询会返回一个
错误。如果一个分片(shard)响应很慢,MongoDB 则会等待它的响应。
25. 我可以把 moveChunk 目录里的旧文件删除吗?
没问题,这些文件是在分片(shard)进行均衡操作(balancing)的时候产生的临时文件。
一旦这些操作已经完成,相关的临时文件也应该被删除掉。但目前清理工作是需要手动的,
所以请小心地考虑再释放这些文件的空间。
26. 我怎么查看 Mongo 正在使用的链接?
db._adminCommand(“connPoolStats”);
27. 如果块移动操作(moveChunk)失败了,我需要手
动清除部分转移的文档吗?
不需要,移动操作是一致(consistent)并且是确定性的(deterministic);一次失败后,
移动操作会不断重试;
当完成后,数据只会出现在新的分片里(shard)。
28. 如果我在使用复制技术(replication),可以一
部分使用日志(journaling)而其他部分则不使用吗?
可以。
29. 当更新一个正在被迁移的块(Chunk)上的文档
时会发生什么?
更新操作会立即发生在旧的块(Chunk)上,然后更改才会在所有权转移前复制到新的
分片上。
30.MongoDB 在 A:{B,C}上建立索引,查询 A:{B,C}
和 A:{C,B}都会使用索引吗?
不会,只会在 A:{B,C}上使用索引。
31.如果一个分片(Shard)停止或很慢的时候,发起
一个查询会怎样?
如果一个分片停止了,除非查询设置了“Partial”选项,否则查询会返回一个错误。
如果一个分片响应很慢,MongoDB 会等待它的响应。
32. MongoDB 支持存储过程吗?如果支持的话,怎么
用?
MongoDB 支持存储过程,它是 Javascript 写的,保存在 db.system.js 表中。
33.如何理解 MongoDB 中的 GridFS 机制,MongoDB
为何使用 GridFS 来存储文件?
GridFS 是一种将大型文件存储在 MongoDB 中的文件规范。使用 GridFS 可以将大文件
分隔成多个小文档存放,这样我们能够有效的保存大文档,而且解决了 BSON 对象有限制的
问题。
分库分表面试题目
1.为什么要分库分表
跟着你的公司业务发展走的,你公司业务发展越好,用户就越多,数据量越大,请求量
越大,那你单个数据库一定扛不住。
比如你单表都几千万数据了,你确定你能抗住么?绝对不行,单表数据量太大,会极
大影响你的 sql 执行的性能,到了后面你的 sql 可能就跑的很慢了。一般来说,就以我的经
验来看,单表到几百万的时候,性能就会相对差一些了,你就得分表了。
分表是啥意思?就是把一个表的数据放到多个表中,然后查询的时候你就查一个表。
比如按照用户 id 来分表,将一个用户的数据就放在一个表中。然后操作的时候你对一个用
户就操作那个表就好了。这样可以控制每个表的数据量在可控的范围内,比如每个表就固定
在 200 万以内。
分库是啥意思?就是你一个库一般我们经验而言,最多支撑到并发 2000,一定要扩容
了,而且一个健康的单库并发值你最好保持在每秒 1000 左右,不要太大。那么你可以将一
个库的数据拆分到多个库中,访问的时候就访问一个库好了。
2.用过哪些分库分表中间件?
比较常见的包括:cobar、TDDL、atlas、sharding-jdbc、mycat
3.不同的分库分表中间件都有什么优点和缺点?
sharding-jdbc 这种 client 层方案的优点在于不用部署,运维成本低,不需要代理层的二
次转发请求,性能很高,但是如果遇到升级啥的需要各个系统都重新升级版本再发布,各个
系统都需要耦合 sharding-jdbc 的依赖;
mycat 这种 proxy 层方案的缺点在于需要部署,自己及运维一套中间件,运维成本高,
但是好处在于对于各个项目是透明的,如果遇到升级之类的都是自己中间件那里搞就行了。
4.你们具体是如何对数据库如何进行垂直拆分或水
平拆分的?
水平拆分的意思,就是把一个表的数据给弄到多个库的多个表里去,但是每个库的表结
构都一样,只不过每个库表放的数据是不同的,所有库表的数据加起来就是全部数据。水平
拆分的意义,就是将数据均匀放更多的库里,然后用多个库来抗更高的并发,还有就是用多
个库的存储容量来进行扩容。
垂直拆分的意思,就是把一个有很多字段的表给拆分成多个表,或者是多个库上去。
每个库表的结构都不一样,每个库表都包含部分字段。一般来说,会将较少的访问频率很高
的字段放到一个表里去,然后将较多的访问频率很低的字段放到另外一个表里去。因为数据
库是有缓存的,你访问频率高的行字段越少,就可以在缓存里缓存更多的行,性能就越好。
这个一般在表层面做的较多一些。
你的项目里该如何分库分表?一般来说,垂直拆分,你可以在表层面来做,对一些字段
特别多的表做一下拆分;水平拆分,你可以说是并发承载不了,或者是数据量太大,容量承
载不了,你给拆了,按什么字段来拆,你自己想好;分表,你考虑一下,你如果哪怕是拆到
每个库里去,并发和容量都 ok 了,但是每个库的表还是太大了,那么你就分表,将这个表
分开,保证每个表的数据量并不是很大。
而且这儿还有两种分库分表的方式,一种是按照 range 来分,就是每个库一段连续的数
据,这个一般是按比如时间范围来的,但是这种一般较少用,因为很容易产生热点问题,大
量的流量都打在最新的数据上了;或者是按照某个字段 hash 一下均匀分散,这个较为常用。
5.现在有一个未分库分表的系统,未来要分库分表,
如何设计才可以让系统从未分库分表动态切换到分
库分表上?
简单来说,就是在线上系统里面,之前所有写库的地方,增删改操作,都除了对老库增
删改,都加上对新库的增删改,这就是所谓双写,同时写俩库,老库和新库。
然后系统部署之后,新库数据差太远,用之前说的导数工具,跑起来读老库数据写新
库,写的时候要根据 gmt_modified 这类字段判断这条数据最后修改的时间,除非是读出来
的数据在新库里没有,或者是比新库的数据新才会写。
接着导万一轮之后,有可能数据还是存在不一致,那么就程序自动做一轮校验,比对
新老库每个表的每条数据,接着如果有不一样的,就针对那些不一样的,从老库读数据再次
写。反复循环,直到两个库每个表的数据都完全一致为止。
接着当数据完全一致了,就 ok 了,基于仅仅使用分库分表的最新代码,重新部署一次,
不就仅仅基于分库分表在操作了么,还没有几个小时的停机时间,很稳。所以现在基本玩儿
数据迁移之类的,都是这么干了。
6.如何设计可以动态扩容缩容的分库分表方案?
一开始上来就是 32 个库,每个库 32 个表,1024 张表
我可以告诉各位同学说,这个分法,第一,基本上国内的互联网肯定都是够用了,第
二,无论是并发支撑还是数据量支撑都没问题, 每个库正常承载的写入并发量是 1000,那么
32 个库就可以承载 32 * 1000 = 32000 的写并发,如果每个库承载 1500 的写并发,32 * 1500
= 48000 的写并发,接近 5 万/s 的写入并发,前面再加一个 MQ,削峰,每秒写入 MQ 8 万
条数据,每秒消费 5 万条数据。
有些除非是国内排名非常靠前的这些公司,他们的最核心的系统的数据库,可能会出
现几百台数据库的这么一个规模,128 个库,256 个库,512 个库 1024 张表,假设每个表放
500 万数据,在 MySQL 里可以放 50 亿条数据 每秒的 5 万写并发,总共 50 亿条数据,对于
国内大部分的互联网公司来说,其实一般来说都够了 谈分库分表的扩容,第一次分库分表,
就一次性给他分个够,32 个库,1024 张表,可能对大部分的中小型互联网公司来说,已经
可以支撑好几年了 一个实践是利用 32 * 32 来分库分表,即分为 32 个库,每个库里一个表
分为 32 张表。一共就是 1024 张表。根据某个 id 先根据 32 取模路由到库,再根据 32 取模
路由到库里的表。
刚开始的时候,这个库可能就是逻辑库,建在一个数据库上的,就是一个 mysql 服务器
可能建了 n 个库,比如 16 个库。后面如果要拆分,就是不断在库和 mysql 服务器之间做迁
移就可以了。然后系统配合改一下配置即可。
7.你们有没有做 MySQL 读写分离?如何实现 mysql 的
读写分离?MySQL 主从复制原理的是啥?如何解决
mysql 主从同步的延时问题?
其实很简单,就是基于主从复制架构,简单来说,就搞一个主库,挂多个从库,然后我
们就单单只是写主库,然后主库会自动把数据给同步到从库上去。
主库将变更写 binlog 日志,然后从库连接到主库之后,从库有一个 IO 线程,将主库的
binlog 日志拷贝到自己本地,写入一个中继日志中。接着从库中有一个 SQL 线程会从中继日
志读取 binlog,然后执行 binlog 日志中的内容,也就是在自己本地再次执行一遍 SQL,这样
就可以保证自己跟主库的数据是一样的。
这里有一个非常重要的一点,就是从库同步主库数据的过程是串行化的,也就是说主
库上并行的操作,在从库上会串行执行。所以这就是一个非常重要的点了,由于从库从主库
拷贝日志以及串行执行 SQL 的特点,在高并发场景下,从库的数据一定会比主库慢一些,
是有延时的。所以经常出现,刚写入主库的数据可能是读不到的,要过几十毫秒,甚至几百
毫秒才能读取到。
要考虑好应该在什么场景下来用这个 mysql 主从同步,建议是一般在读远远多于写,而
且读的时候一般对数据时效性要求没那么高的时候,用 mysql 主从同步。通常来说,我们会
对于那种写了之后立马就要保证可以查到的场景,采用强制读主库的方式。如果主从延迟较
为严重,分库,将一个主库拆分为 4 个主库,每个主库的写并发就 500/s,此时主从延迟可
以忽略不计;打开 mysql 支持的并行复制,多个库并行复制
8.分库分表之后,id 主键如何处理?
数据库自增 id,
这个就是说你的系统里每次得到一个 id,都是往一个库的一个表里插入一条没什么业
务含义的数据,然后获取一个数据库自增的一个 id。拿到这个 id 之后再往对应的分库分表
里去写入。
这个方案的好处就是方便简单,谁都会用;缺点就是单库生成自增 id,要是高并发的
话,就会有瓶颈的;如果你硬是要改进一下,那么就专门开一个服务出来,这个服务每次就
拿到当前 id 最大值,然后自己递增几个 id,一次性返回一批 id,然后再把当前最大 id 值
修改成递增几个 id 之后的一个值;但是无论如何都是基于单个数据库。
UUID
好处就是本地生成,不要基于数据库来了;不好之处就是,UUID 太长了,作为主键性
能太差了,另外 UUID 不具有有序性,会造成 B+ 树索引在写的时候有过多的随机写操作,
频繁修改树结构,从而导致性能下降。
snowflake 算法
网络通讯面试题目
fs.file_max = 1000000
sysctl -p
Netty 调优
设置合理的线程数
对于线程池的调优,主要集中在用于接收海量设备 TCP 连接、TLS 握手的 Acceptor 线程
池( Netty 通常叫 boss NioEventLoop Group)上,以及用于处理网络数据读写、心跳发送的
1O 工作线程池(Nety 通常叫 work Nio EventLoop Group)上。
对于 Nety 服务端,通常只需要启动一个监听端口用于端侧设备接入即可,但是如果服务
端集群实例比较少,甚至是单机(或者双机冷备)部署,在端侧设备在短时间内大量接入时,需
要对服务端的监听方式和线程模型做优化,以满足短时间内(例如 30s)百万级的端侧设备接
入的需要。
服务端可以监听多个端口,利用主从 Reactor 线程模型做接入优化,前端通过 SLB 做 4
层门 7 层负载均衡。
主从 Reactor 线程模型特点如下:服务端用于接收客户端连接的不再是一个单独的 NO
线程,而是一个独立的 NIO 线程池; Acceptor 接收到客户端 TCP 连接请求并处理后(可能包
含接入认证等),将新创建的 Socketchanne 注册到 I/O 线程池(subReactor 线程池)的某个
IO 线程,由它负责 Socketchannel 的读写和编解码工作; Acceptor 线程池仅用于客户端的
登录、握手和安全认证等,一旦链路建立成功,就将链路注册到后端 sub reactor 线程池的
IO 线程,由 IO 线程负责后续的 IO 操作。
对于 IO 工作线程池的优化,可以先采用系统默认值(即 CPU 内核数×2)进行性能测试,
在性能测试过程中采集 IO 线程的 CPU 占用大小,看是否存在瓶颈对于 O 工作线程池的优化,
可以先采用系统默认值(即 CPU 内核数×2)进行性能
测试,在性能测试过程中采集 IO 线程的 CPU 占用大小,看是否存在瓶颈, 具体可以观察
线程堆栈,如果连续采集几次进行对比,发现线程堆栈都停留在 Selectorlmpl. lock
AndDoSelect,则说明 IO 线程比较空闲,无须对工作线程数做调整。
如果发现 IO 线程的热点停留在读或者写操作,或者停留在 Channelhandler 的执行处,
则可以通过适当调大 Nio EventLoop 线程的个数来提升网络的读写性能。
心跳优化
针对海量设备接入的服务端,心跳优化策略如下。
(1)要能够及时检测失效的连接,并将其剔除,防止无效的连接句柄积压,导致 OOM 等问
题
(2)设置合理的心跳周期,防止心跳定时任务积压,造成频繁的老年代 GC(新生代和老年
代都有导致 STW 的 GC,不过耗时差异较大),导致应用暂停
(3)使用 Nety 提供的链路空闲检测机制,不要自己创建定时任务线程池,加重系统的负
担,以及增加潜在的并发安全问题。
当设备突然掉电、连接被防火墙挡住、长时间 GC 或者通信线程发生非预期异常时,会导
致链路不可用且不易被及时发现。特别是如果异常发生在凌晨业务低谷期间,当早晨业务高
峰期到来时,由于链路不可用会导致瞬间大批量业务失败或者超时,这将对系统的可靠性产
生重大的威胁。
从技术层面看,要解决链路的可靠性问题,必须周期性地对链路进行有效性检测。目前最
流行和通用的做法就是心跳检测。心跳检测机制分为三个层面
(1)TCP 层的心跳检测,即 TCP 的 Keep-Alive 机制,它的作用域是整个 TCP 协议栈。
(2)协议层的心跳检测,主要存在于长连接协议中,例如 MQTT。
(3)应用层的心跳检测,它主要由各业务产品通过约定方式定时给对方发送心跳消息实
现。
心跳检测的目的就是确认当前链路是否可用,对方是否活着并且能够正常接收和发送消
息。作为高可靠的 NIO 框架,Nety 也提供了心跳检测机制。
一般的心跳检测策略如下。
(1)连续 N次心跳检测都没有收到对方的 Pong应答消息或者 Ping 请求消息,则认为链路
已经发生逻辑失效,这被称为心跳超时。
(2)在读取和发送心跳消息的时候如果直接发生了 IO 异常,说明链路已经失效,这被称
为心跳失败。无论发生心跳超时还是心跳失败,都需要关闭链路,由客户端发起重连操作,保
证链路能够恢复正常。
Nety 提供了三种链路空闲检测机制,利用该机制可以轻松地实现心跳检测
(1)读空闲,链路持续时间 T 没有读取到任何消息。
(2)写空闲,链路持续时间 T 没有发送任何消息
(3)读写空闲,链路持续时间 T 没有接收或者发送任何消息
对于百万级的服务器,一般不建议很长的心跳周期和超时时长
接收和发送缓冲区调优
在一些场景下,端侧设备会周期性地上报数据和发送心跳,单个链路的消息收发量并不
大,针对此类场景,可以通过调小TCP的接收和发送缓冲区来降低单个TCP连接的资源占用率
当然对于不同的应用场景,收发缓冲区的最优值可能不同,用户需要根据实际场景,结合
性能测试数据进行针对性的调优
合理使用内存池
随着 JVM 虚拟机和 JT 即时编译技术的发展,对象的分配和回收是一个非常轻量级的工
作。但是对于缓冲区 Buffer,情况却稍有不同,特别是堆外直接内存的分配和回收,是一个耗
时的操作。
为了尽量重用缓冲区,Nety 提供了基于内存池的缓冲区重用机制。
在百万级的情况下,需要为每个接入的端侧设备至少分配一个接收和发送缓冲区对象,
采用传统的非池模式,每次消息读写都需要创建和释放 ByteBuf 对象,如果有 100 万个连接,
每秒上报一次数据或者心跳,就会有 100 万次/秒的 ByteBuf 对象申请和释放,即便服务端的
内存可以满足要求,GC 的压力也会非常大。
以上问题最有效的解决方法就是使用内存池,每个 NioEventLoop 线程处理 N 个链路,在
线程内部,链路的处理是串行的。假如 A 链路首先被处理,它会创建接收缓冲区等对象,待解
码完成,构造的 POJO 对象被封装成任务后投递到后台的线程池中执行,然后接收缓冲区会被
释放,每条消息的接收和处理都会重复接收缓冲区的创建和释放。如果使用内存池,则当 A
链路接收到新的数据报时,从 NioEventLoop 的内存池中申请空闲的 ByteBuf,解码后调用
release 将 ByteBuf 释放到内存池中,供后续的 B 链路使用。
Nety 内存池从实现上可以分为两类:堆外直接内存和堆内存。由于 Byte Buf 主要用于
网络 IO 读写,因此采用堆外直接内存会减少一次从用户堆内存到内核态的字节数组拷贝,所
以性能更高。由于 DirectByteBuf 的创建成本比较高,因此如果使用 DirectByteBuf,则需
要配合内存池使用,否则性价比可能还不如 Heap Byte。
Netty 默认的 IO 读写操作采用的都是内存池的堆外直接内存模式,如果用户需要额外使
用 ByteBuf,建议也采用内存池方式;如果不涉及网络 IO 操作(只是纯粹的内存操作),可以
使用堆内存池,这样内存的创建效率会更高一些。
IO 线程和业务线程分离
如果服务端不做复杂的业务逻辑操作,仅是简单的内存操作和消息转发,则可以通过调
大 NioEventLoop 工作线程池的方式,直接在 IO 线程中执行业务 Channelhandler,这样便减
少了一次线程上下文切换,性能反而更高。
如果有复杂的业务逻辑操作,则建议 IO 线程和业务线程分离,对于 IO 线程,由于互相之
间不存在锁竞争,可以创建一个大的 NioEvent Loop Group 线程组,所有 Channel 都共享同
一个线程池。
对于后端的业务线程池,则建议创建多个小的业务线程池,线程池可以与 IO 线程绑定,
这样既减少了锁竞争,又提升了后端的处理性能。
针对端侧并发连接数的流控
无论服务端的性能优化到多少,都需要考虑流控功能。当资源成为瓶颈,或者遇到端侧设
备的大量接入,需要通过流控对系统做保护。流控的策略有很多种,比如针对端侧连接数的
流控。在 Nety 中,可以非常方便地实现流控功能:新增一个 FlowControlchannelhandler,
然后添加到 ChannelPipeline 靠前的位置,覆盖 channelActiveO 方法,创建 TCP 链路后,执
行流控逻辑,如果达到流控阈值,则拒绝该连接,调用 ChannelHandler Context 的 close(方
法关闭连接。
JVM 层面相关性能优化
当客户端的并发连接数达到数十万或者数百万时,系统一个较小的抖动就会导致很严重
的后果,例如服务端的 GC,导致应用暂停(STW)的 GC 持续几秒,就会导致海量的客户端设备掉
线或者消息积压,一旦系统恢复,会有海量的设备接入或者海量的数据发送很可能瞬间就把
服务端冲垮。
JVM 层面的调优主要涉及 GC 参数优化,GC 参数设置不当会导致频繁 GC,甚至 OOM 异常,
对服务端的稳定运行产生重大影响。
确定 GC 优化目标
GC(垃圾收集)有三个主要指标。
(1)吞吐量:是评价GC能力的重要指标,在不考虑GC引起的停顿时间或内存消耗时,吞吐
量是 GC 能支撑应用程序达到的最高性能指标。
(2)延迟:GC 能力的最重要指标之一,是由于 GC 引起的停顿时间,优化目标是缩短延迟时
间或完全消除停顿(STW),避免应用程序在运行过程中发生抖动。
(3)内存占用:GC 正常时占用的内存量。
JVM GC 调优的三个基本原则如下。
(1) Minor go 回收原则:每次新生代 GC 回收尽可能多的内存,减少应用程序发生 Full gc
的频率。
2)GC 内存最大化原则:垃圾收集器能够使用的内存越大,垃圾收集效率越高,应用程序
运行也越流畅。但是过大的内存一次 Full go 耗时可能较长,如果能够有效避免 FullGC,就
需要做精细化调优。
(3)3 选 2 原则:吞吐量、延迟和内存占用不能兼得,无法同时做到吞吐量和暂停时间都
最优,需要根据业务场景做选择。对于大多数应用,吞吐量优先,其次是延迟。当然对于时延
敏感型的业务,需要调整次序。
2.确定服务端内存占用
在优化 GC 之前,需要确定应用程序的内存占用大小,以便为应用程序设置合适的内存,
提升 GC 效率。内存占用与活跃数据有关,活跃数据指的是应用程序稳定运行时长时间存活的
Java 对象。活跃数据的计算方式:通过 GC 日志采集 GC 数据,获取应用程序稳定时老年代占
用的Java堆大小,以及永久代(元数据区)占用的Java堆大小,两者之和就是活跃数据的内存
占用大小。
GC 优化过程
1、GC 数据的采集和研读
2、设置合适的 JVM 堆大小
3、选择合适的垃圾回收器和回收策略
当然具体如何做,请参考 JVM 相关课程。而且 GC 调优会是一个需要多次调整的过程,
期间不仅有参数的变化,更重要的是需要调整业务代码。
消息中间件面试题目
ELK 面试题目
1.ELK 是什么?
ELK 其实并不是一款软件,而是一整套解决方案,是三个软件产品的首字母缩写
Elasticsearch:负责日志检索和储存
Logstash:负责日志的收集和分析、处理
Kibana:负责日志的可视化
这三款软件都是开源软件,通常是配合使用,而且又先后归于 Elastic.co 公司名下,
故被简称为 ELK。加入 Beats 系列组件后,官方名称就变为了 Elastic Stack
2.ELK 能做什么?
ELK 组件在海量日志系统的运维中,可用于解决:
分布式日志数据集中式查询和管理、系统监控,包含系统硬件和应用各个组件的监控、
故障排查、安全信息和事件管理、报表功能等等
3.简要概述 Elasticsearch?
ElasticSearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的
全文搜索引擎,基于 RESTful API 的 web 接口。
Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前
流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装
使用方便
4.Elasticsearch 主要特点
1.实时分析
2.分布式实时文件存储,并将每一个字段都编入索引
3.文档导向,所有的对象全部是文档
4.高可用性,易扩展,支持集群(Cluster)、分片和复制(Shards 和 Replicas)
接口友好,支持 JSON
5.ES 相关概念
Node: 装有一个 ES 服务器的节点。
Cluster: 有多个 Node 组成的集群
Document: 一个可被搜素的基础信息单元
Index: 拥有相似特征的文档的集合
Type: 一个索引中可以定义一种或多种类型
Filed: 是 ES 的最小单位,相当于数据的某一列
Shards: 索引的分片,每一个分片就是一个 Shard
Replicas: 索引的拷贝
6.什么是分词器
分词是将文本转换成一系列单词(Term or Token)的过程,也可以叫文本分析,在 ES
里面称为 Analysis
分词器是 ES 中专门处理分词的组件,英文为 Analyzer,它的组成如下:
Character Filters:针对原始文本进行处理,比如去除 html 标签
Tokenizer:将原始文本按照一定规则切分为单词
Token Filters:针对 Tokenizer 处理的单词进行再加工,比如转小写、删除或增新等
处理
ES 提供了一个可以测试分词的 API 接口,方便验证分词效果,endpoint 是_analyze
ES 也提供了很多内置的分析器。
7.elasticsearch 的倒排索引是什么?
正排索引是以文档的 ID 为关键字,表中记录文档中每个字的位置信息,查找时扫描表
中每个文档中字的信息直到找出所有包含查询关键字的文档。
而倒排索引,是通过分词策略,形成了词和文章的映射关系表,这种词典+映射表即为
倒排索引。
有了倒排索引,就能实现 o(1)时间复杂度的效率检索文章了,极大的提高了检索效
率。
所以总的来说,正排索引是从文档到关键字的映射(已知文档求关键字),倒排索引是
从关键字到文档的映射(已知关键字求文档)。
8.Elasticsearch 是如何实现 Master 选举的?
采用 Bully 算法,它假定所有节点都有一个唯一的 ID,使用该 ID 对节点进行排序。
Elasticsearch 的选主是 ZenDiscovery 模块负责的,主要包含 Ping(节点之间通过这个 RPC
来发现彼此)和 Unicast(单播模块包含一个主机列表以控制哪些节点需要 ping 通)这两
部分;
对所有可以成为 master 的节点(node.master: true)根据 nodeId 字典排序,每次选
举每个节点都把自己所知道节点排一次序,然后选出第一个(第 0 位)节点,暂且认为它是
master 节点。
如果对某个节点的投票数达到一定的值(可以成为 master 节点数 n/2+1)并且该节点
自己也选举自己,那这个节点就是 master。否则重新选举一直到满足上述条件。
补充:master 节点的职责主要包括集群、节点和索引的管理,不负责文档级别的管理;
data 节点可以关闭 http 功能。
7.X 之后的 ES,采用一种新的选主算法,实际上是 Raft 的实现,但并非严格按照 Raft
论文实现,而是做了一些调整。Raft 是工程上使用较为广泛分布式共识协议,是多个节点
对某个事情达成一致的看法,即使是在部分节点故障、网络延时、网络分区的情况下。
9.Elasticsearch 如何避免脑裂?
ES 集群中的节点(比如共 20 个),其中的 10 个选了一个 master,另外 10 个选了另一
个 master,怎么办?
当集群 master 候选数量不小于 3 个时,可以通过设置最少投票通过数量
(discovery.zen.minimum_master_nodes)超过所有候选节点一半以上来解决脑裂问题;
当候选数量为两个时,只能修改为唯一的一个 master 候选,其他作为 data 节点,避免
脑裂问题。
在 Elasticsearch 7.0 里重新设计并重建了的集群协调子系统,移除
minimum_master_nodes 参数,转而由集群自主控制。
10.详细描述一下 Elasticsearch 索引文档的过程
协调节点默认使用文档 ID 参与计算(也支持通过 routing),以便为路由提供合适的
分片。
shard = hash(document_id) % (num_of_primary_shards)
当分片所在的节点接收到来自协调节点的请求后,会将请求写入到 Memory Buffer,然
后定时(默认是每隔 1 秒)写入到 Filesystem Cache,这个从 Momery Buffer 到 Filesystem
Cache 的过程就叫做 refresh;
当然在某些情况下,存在 Momery Buffer 和 Filesystem Cache 的数据可能会丢失,ES
是通过 translog 的机制来保证数据的可靠性的。其实现机制是接收到请求后,同时也会写
入到 translog 中,当 Filesystem cache 中的数据写入到磁盘中时,才会清除掉,这个过程
叫做 flush;
在 flush 过程中,内存中的缓冲将被清除,内容被写入一个新段,段的 fsync 将创建一
个新的提交点,并将内容刷新到磁盘,旧的 translog 将被删除并开始一个新的 translog。
flush 触发的时机是定时触发(默认 30 分钟)或者 translog 变得太大(默认为 512M)
时;
11.请概述 Elasticsearch 搜索的过程?
搜索拆解为“query then fetch” 两个阶段。
query 阶段的目的:定位到位置,但不取。
步骤拆解如下:
1)假设一个索引数据有 5 主+1 副本 共 10 分片,一次请求会命中(主或者副本分片中)
的一个。
2)每个分片在本地进行查询,结果返回到本地有序的优先队列中。
3)第 2)步骤的结果发送到协调节点,协调节点产生一个全局的排序列表。
fetch 阶段的目的:取数据。
路由节点获取所有文档,返回给客户端。
Redis 面试题目
1.什么是 Redis?简述它的优缺点?
Redis 的全称是:Remote Dictionary.Server,本质上是一个 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 适合的场景主要局限在较小数据量的高性能操作和运算
上。
2. Redis 与 memcached 相比有哪些优势?
1.memcached 所有的值均是简单的字符串,redis 作为其替代者,支持更为丰富的数据
类型
2.redis 的速度比 memcached 快很多 redis 的速度比 memcached 快很多
3.redis 可以持久化其数据 redis 可以持久化其数据
3. Redis 支持哪几种数据类型?
String、List、Set、Sorted Set、hash
4. Redis 主要消耗什么物理资源?
内存。
5. Redis 有哪几种数据淘汰策略?
1.noeviction:返回错误当内存限制达到,并且客户端尝试执行会让更多内存被使用的
命令。
2.allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
3.volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添
加的数据有空间存放。
4.allkeys-random: 回收随机的键使得新添加的数据有空间存放。
5.volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集
合的键。
6.volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得
新添加的数据有空间存放。
6. Redis 官方为什么不提供 Windows 版本?
因为目前 Linux 版本已经相当稳定,且 Linux 操作系统自带的 epoll 相关函数, 在高
并发情况下性能一般比 windows 的 select 函数性能较好,为了高性能起见, Redis 官网不
提供 windows 版本。
7.一个字符串类型的值能存储最大容量是多少?
512M
8.为什么 Redis 需要把所有数据放到内存中?
Redis 为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁
盘。
所以 redis 具有快速和数据持久化的特征,如果不将数据放在内存中,磁盘 I/O 速度
为严重影响 redis 的性能。
在内存越来越便宜的今天,redis 将会越来越受欢迎, 如果设置了最大使用的内存,
则数据已有记录数达到内存限值后不能继续插入新值。
9. Redis 集群方案应该怎么做?都有哪些方案?
1.codis2.目前用的最多的集群方案,基本和 twemproxy 一致的效果,但它支持在节点
数量改变情况下,旧节点数据可恢复到新 hash 节点。
2.redis cluster3.0 自带的集群,特点在于他的分布式算法不是一致性 hash,而是
hash 槽的概念,以及自身支持节点设置从节点。具体看官方文档介绍。
3.在业务代码层实现,起几个毫无关联的 redis 实例,在代码层,对 key 进行 hash 计
算,然后去对应的 redis 实例操作数据。这种方式对 hash 层代码要求比较高,考虑部分
包括,节点失效后的替代算法方案,数据震荡后的自动脚本恢复,实例的监控,等等。
10. Redis 集群方案什么情况下会导致整个集群不
可用?
有 A,B,C 三个节点的集群,在没有复制模型的情况下,如果节点 B 失败了,那么整个
集群就会以为缺少 5501-11000 这个范围的槽而不可用。
11. MySQL 里有 2000w 数据,redis 中只存 20w 的
数据,如何保证 redis 中的数据都是热点数据?
redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。
12. Redis 有哪些适合的场景?
(1)会话缓存(Session Cache)
最常用的一种使用 Redis 的情景是会话缓存(session cache),用 Redis 缓存会话
比其他存储(如
Memcached)的优势在于:Redis 提供持久化。当维护一个不是严格要求一致性的缓存
时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?
幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用 Redis 来缓存会话
的文档。甚至广为人知的商业平台 Magento 也提供 Redis 的插件。
(2)全页缓存(FPC)
除基本的会话 token 之外,Redis 还提供很简便的 FPC 平台。回到一致性问题,即使
重启了 Redis 实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一
个极大改进,类似 PHP 本地 FPC。
再次以 Magento 为例,Magento 提供一个插件来使用 Redis 作为全页缓存后端。
此外,对 WordPress 的用户来说,Pantheon 有一个非常好的插件 wp-redis,这个插
件能帮助你以最快速度加载你曾浏览过的页面。
(3)队列
Reids 在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得 Redis 能作
为一个很好的消息队列平台来使用。Redis 作为队列使用的操作,就类似于本地程序语言(如
Python)对 list 的 push/pop 操作。
如果你快速的在 Google 中搜索“Redis queues”,你马上就能找到大量的开源项目,
这些项目的目的就是利用 Redis 创建非常好的后端工具,以满足各种队列需求。例如,
Celery 有一个后台就是使用 Redis 作为 broker,你可以从这里去查看。
排行榜/计数器 Redis 在内存中对数字进行递增或递减的操作实现的非常好。
集合(Set)和有序集合(SortedSet)也使得我们在执行这些操作的时候变的非常简单,
Redis 只是正好提供了这两种数据结构。
所以, 我们要从排序集合中获取到排名最靠前的 10 个用户 – 我们称之为
“user_scores”,我们只需要像下面一样执行即可:
当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,
你需要这样执行:
ZRANGE user_scores 0 10 WITHSCORES
Agora Games 就是一个很好的例子,用 Ruby 实现的,它的排行榜就是使用 Redis 来
存储数据的,你可以在这里看到。
(5)发布/订阅
最后(但肯定不是最不重要的)是 Redis 的发布/订阅功能。发布/订阅的使用场景确
实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,
甚至用 Redis 的发布/订阅功能来建立聊天系统!
13. Redis 支持的 Java 客户端都有哪些?官方推
荐用哪个?
Redisson、Jedis、lettuce 等等,官方推荐使用 Redisson。
14. Redis 和 Redisson 有什么关系?
Redisson 是一个高级的分布式协调 Redis 客服端,能帮助用户在分布式环境中轻松实
现一些 Java 的对象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet,
SortedSet, Map, ConcurrentMap,
List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore,
Lock,
ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。
15. Jedis 与 Redisson 对比有什么优缺点?
Jedis 是 Redis 的 Java 实现的客户端,其 API 提供了比较全面的 Redis 命令的支
持;
Redisson 实现了分布式和可扩展的 Java 数据结构,和 Jedis 相比,功能较为简单,
不支持字符串操作,不支持排序、事务、管道、分区等 Redis 特性。Redisson 的宗旨是促
进使用者对 Redis 的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。
16. 说说 Redis 哈希槽的概念?
Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有 16384 个
哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点
负责一部分 hash 槽。
17. Redis 集群的主从复制模型是怎样的?
为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用
了主从复制模型, 每个节点都会有 N-1 个复制品。
18. Redis 集群会有写操作丢失吗?为什么?
Redis 并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失
写操作。
19. Redis 集群之间是如何复制的?
异步复制
20. Redis 集群最大节点个数是多少?
16384 个
21. Redis 集群如何选择数据库?
Redis 集群目前无法做数据库选择,默认在 0 数据库。
Redis 中的管道有什么用?
一次请求/响应服务器能实现处理新的请求即使旧的请求还未被响应,这样就可以将多
个命令发送到服务 器,而不用等待回复,最后在一个步骤中读取该答复。
这就是管道(pipelining),是一种几十年来广泛使用的技术。例如许多 POP3 协议已
经实现支持这个功能,大大加快了从服务器下载新邮件的过程。23、怎么理解 Redis 事务?
事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行,事务在执
行的过程中,不会被其他客户端发送来的命令请求所打断。
事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
Redis 事务相关的命令有哪几个?
MULTI、EXEC、DISCARD、WATCH
Redis key 的过期时间和永久有效分别怎么设
置?
EXPIRE 和 PERSIST 命令
Redis 如何做内存优化?
尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常
小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。
比如你的 web 系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设
置单独的 key,而是应该把这个用户的所有信息存储到一张散列表里面。
Redis 回收进程如何工作的?
一个客户端运行了新的命令,添加了新的数据。
Redi 检查内存使用情况,如果大于 maxmemory 的限制, 则根据设定好的策略进行回
收。
一个新的命令被执行,等等。
所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地回收回到边界以
下。
如果一个命令的结果导致大量内存被使用(例如很大的集合的交集保存到一个新的键),
不用多久内存限制就会被这个内存使用量超越。
加锁机制
我们先看看 Redisson 这个开源框架对 Redis 分布式锁的实现原理
咱们来看上面那张图,现在某个客户端要加锁。如果该客户端面对的是一个 redis
cluster 集群,他首先会根据 hash 节点选择一台机器。这里注意,仅仅只是选择一台机器!
这点很关键!紧接着,就会发送一段 lua 脚本到 redis 上,那段 lua 脚本如下所示:
为啥要用 lua 脚本呢?因为一大坨复杂的业务逻辑,可以通过封装在 lua 脚本中发送
给 redis,保证这段复杂业务逻辑执行的原子性。
那么,这段 lua 脚本是什么意思呢?这里 KEYS[1]代表的是你加锁的那个 key,比如
说:RLock lock = redisson.getLock(“myLock”);这里你自己设置了加锁的那个锁 key 就
是“myLock”。
ARGV[1]代表的就是锁 key 的默认生存时间,默认 30 秒。ARGV[2]代表的是加锁的客
户端的 ID,类似于下面这样:8743c9c0-0795-4907-87fd-6c719a6b4586:1
给大家解释一下,第一段 if 判断语句,就是用“exists myLock”命令判断一下,如
果你要加锁的那个锁 key 不存在的话,你就进行加锁。如何加锁呢?很简单,用下面的命
令:hset myLock8743c9c0-0795-4907-87fd-6c719a6b4586:1 1,通过这个命令设置一个 hash
数据结构,这行命令执行后,会出现一个类似下面的数据结构:
上述就代表“8743c9c0-0795-4907-87fd-6c719a6b4586:1”这个客户端对“myLock”这
个锁 key 完成了加锁。接着会执行“pexpire myLock 30000”命令,设置 myLock 这个锁 key
的生存时间是 30 秒。好了,到此为止,ok,加锁完成了。
锁互斥机制
那么在这个时候,如果客户端 2 来尝试加锁,执行了同样的一段 lua 脚本,会咋样呢?
很简单,第一个 if 判断会执行“exists myLock”,发现 myLock 这个锁 key 已经存在了。
接着第二个 if 判断,判断一下,myLock 锁 key 的 hash 数据结构中,是否包含客户端 2
的 ID,但是明显不是的,因为那里包含的是客户端 1 的 ID。
所以,客户端 2 会获取到 pttl myLock 返回的一个数字,这个数字代表了 myLock 这
个锁 key 的剩余生存时间。比如还剩 15000 毫秒的生存时间。此时客户端 2 会进入一个
while 循环,不停的尝试加锁。
watch dog 自动延期机制
客户端 1 加锁的锁 key 默认生存时间才 30 秒,如果超过了 30 秒,客户端 1 还想
一直持有这把锁,怎么办呢?
简单!只要客户端 1 一旦加锁成功,就会启动一个 watch dog 看门狗,他是一个后台
线程,会每隔 10 秒检查一下,如果客户端 1 还持有锁 key,那么就会不断的延长锁 key 的
生存时间。
可重入加锁机制
那如果客户端 1 都已经持有了这把锁了,结果可重入的加锁会怎么样呢?比如下面这
种代码:这时我们来分析一下上面那段 lua 脚本。第一个 if 判断肯定不成立,“exists
myLock”会显示锁 key 已经存在了。第二个 if 判断会成立,因为 myLock 的 hash 数据
结构中包含的那个 ID ,就是客户端 1 的那个 ID ,也就是
“8743c9c0-0795-4907-87fd-6c719a6b4586:1”此时就会执行可重入加锁的逻辑,他会用:
incrby myLock 8743c9c0-0795-4907-87fd-6c71a6b4586:1 1 ,通过这个命令,对客户端 1
的加锁次数,累加 1。此时 myLock 数据结构变为下面这样:大家看到了吧,那个 myLock 的
hash 数据结构中的那个客户端 ID,就对应着加锁的次数
释放锁机制
如果执行 lock.unlock(),就可以释放分布式锁,此时的业务逻辑也是非常简单的。其
实说白了,就是每次都对 myLock 数据结构中的那个加锁次数减 1。如果发现加锁次数是 0
了,说明这个客户端已经不再持有锁了,此时就会用:“del myLock”命令,从 redis 里
删除这个 key。
然后呢,另外的客户端 2 就可以尝试完成加锁了。这就是所谓的分布式锁的开源
Redisson 框架的实现机制。
一般我们在生产系统中,可以用 Redisson 框架提供的这个类库来基于 redis 进行分
布式锁的加锁与释放锁。
上述 Redis 分布式锁的缺点
其实上面那种方案最大的问题,就是如果你对某个 redis master 实例,写入了 myLock
这种锁 key 的 value,此时会异步复制给对应的 master slave 实例。但是这个过程中一
旦发生 redis master 宕机,主备切换,redis slave 变为了 redis master。
接着就会导致,客户端 2 来尝试加锁的时候,在新的 redis master 上完成了加锁,
而客户端 1 也以为自己成功加了锁。此时就会导致多个客户端对一个分布式锁完成了加锁。
这时系统在业务语义上一定会出现问题,导致各种脏数据的产生。
所以这个就是 redis cluster,或者是 redis master-slave 架构的主从异步复制导致
的 redis 分布式锁的最大缺陷:在 redis master 实例宕机的时候,可能导致多个客户端
同时完成加锁。
使用过 Redis 分布式锁么,它是怎么实现的?
先拿 setnx 来争抢锁,抢到之后,再用 expire 给锁加一个过期时间防止锁忘记了释
放。如果在 setnx 之后执行 expire 之前进程意外 crash 或者要重启维护了,那会怎么
样?set 指令有非常复杂的参数,这个应该是可以同时把 setnx 和 expire 合成一条指令
来用的!
使用过 Redis 做异步队列么,你是怎么用的?
有什么缺点?
一般使用 list 结构作为队列,rpush 生产消息,lpop 消费消息。当 lpop 没有消息
的时候,要适当 sleep 一会再重试。
缺点:
在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如 rabbitmq 等。
能不能生产一次消费多次呢?
使用 pub/sub 主题订阅者模式,可以实现 1:N 的消息队列。
redis 和 memcached 什么区别?为什么高并发
下有时单线程的 redis 比多线程的 memcached 效
率要高?
区别:
1.mc 可缓存图片和视频。rd 支持除 k/v 更多的数据结构;
2.rd 可以使用虚拟内存,rd 可持久化和 aof 灾难恢复,rd 通过主从支持数据备份;
3.rd 可以做消息队列。
原因:mc 多线程模型引入了缓存一致性和锁,加锁带来了性能损耗。
redis 主从复制如何实现的?redis 的集群模
式如何实现?redis 的 key 是如何寻址的?
主从复制实现:主节点将自己内存中的数据做一份快照,将快照发给从节点,从节点将
数据恢复到内存中。之后再每次增加新数据的时候,主节点以类似于 mysql 的二进制日志
方式将语句发送给从节点,从节点拿到主节点发送过来的语句进行重放。
分片方式:
-客户端分片
-基于代理的分片
● Twemproxy
● codis
-路由查询分片
● Redis-cluster(本身提供了自动将数据分散到 Redis Cluster 不同节点的能力,
整个数据集合的某个数据子集存储在哪个节点对于用户来说是透明的)redis-cluster 分片
原理:Cluster 中有一个 16384 长度的槽(虚拟槽),编号分别为 0-16383。
每个 Master 节点都会负责一部分的槽,当有某个 key 被映射到某个 Master 负责的
槽,那么这个 Master 负责为这个 key 提供服务,至于哪个 Master 节点负责哪个槽,可
以由用户指定,也可以在初始化的时候自动生成,只有 Master 才拥有槽的所有权。Master
节点维护着一个 16384/8 字节的位序列,Master 节点用 bit 来标识对于某个槽自己是否
拥有。比如对于编号为 1 的槽,Master 只要判断序列的第二位(索引从 0 开始)是不是
为 1 即可。
这种结构很容易添加或者删除节点。比如如果我想新添加个节点 D, 我需要从节点 A、
B、C 中得部分槽到 D 上。
使用 redis 如何设计分布式锁?说一下实现思
路?使用 zk 可以吗?如何实现?这两种有什
么区别?
Redis:
1.线程 A setnx(上锁的对象,超时时的时间戳 t1),如果返回 true,获得锁。
2.线程 B 用 get 获取 t1,与当前时间戳比较,判断是是否超时,没超时 false,若超时
执行第 3 步;
3.计算新的超时时间 t2,使用 getset 命令返回 t3(该值可能其他线程已经修改过),
如果
t1==t3,获得锁,如果 t1!=t3 说明锁被其他线程获取了。
4.获取锁后,处理完业务逻辑,再去判断锁是否超时,如果没超时删除锁,如果已超时,
不用处理(防止删除其他线程的锁)。
Zookeeper:
1.客户端对某个方法加锁时,在 zk 上的与该方法对应的指定节点的目录下,生成一个
唯一的瞬时有序节点 node1;
2.客户端获取该路径下所有已经创建的子节点,如果发现自己创建的 node1 的序号是
最小的,就认为这个客户端获得了锁。
3.如果发现 node1 不是最小的,则监听比自己创建节点序号小的最大的节点,进入等
待。4.获取锁后,处理完逻辑,删除自己创建的 node1 即可。
区别: zk 性能差一些,开销大,实现简单。
知道 redis 的持久化吗?底层如何实现的?有
什么优点缺点?
RDB(Redis DataBase:在不同的时间点将 redis 的数据生成的快照同步到磁盘等介质
上):内存到硬盘的快照,定期更新。缺点:耗时,耗性能(fork+io 操作),易丢失数据。
AOF(Append Only File:将 redis 所执行过的所有指令都记录下来,在下次 redis 重
启时,只需要执行指令就可以了):写日志。缺点:体积大,恢复速度慢。
bgsave 做镜像全量持久化,aof 做增量持久化。因为 bgsave 会消耗比较长的时间,
不够实时,在停机的时候会导致大量的数据丢失,需要 aof 来配合,在 redis 实例重启时,
优先使用 aof 来恢复内存的状态,如果没有 aof 日志,就会使用 rdb 文件来恢复。Redis
会定期做 aof 重写,压缩 aof 文件日志大小。Redis4.0 之后有了混合持久化的功能,将
bgsave 的全量和 aof 的增量做了融合处理,这样既保证了恢复的效率又兼顾了数据的安全
性。bgsave 的原理,fork 和 cow, fork 是指 redis 通过创建子进程来进行 bgsave 操作,
cow 指的是 copy onwrite,子进程创建后,父子进程共享数据段,父进程继续提供读写服
务,写脏的页面数据会逐渐和子进程分离开来。
redis 过期策略都有哪些?LRU 算法知道吗?
写一下 Java 代码实现?
过期策略:
定时过期(一 key 一定时器),惰性过期:只有使用 key 时才判断 key 是否已过期,
过期则清除。定期过期:前两者折中。
LRU:new LinkedHashMap
参数置为 true,代表 linkedlist 按访问顺序排序,可作为 LRU 缓存;设为 false 代表
按插入顺序排序,可作为 FIFO 缓存 LRU 算法实现:
1.通过双向链表来实现,新数据插入到链表头部;
2.每当缓存命中(即缓存数据被访问),则将数据移到链表头部;3.当链表满的时候,
将链表尾部的数据丢弃。
LinkedHashMap:HashMap 和双向链表合二为一即是 LinkedHashMap。HashMap 是无序
的,LinkedHashMap 通过维护一个额外的双向链表保证了迭代顺序。该迭代顺序可以是插入
顺序(默认),也可以是访问顺序。
缓存穿透、缓存击穿、缓存雪崩解决方案?
什么是缓存穿透?
指查询一个一定不存在的数据,如果从存储层查不到数据则不写入缓存,这将导致这个
不存在的数据每次请求都要到 DB 去查询,可能导致 DB 挂掉。
穿透解决方案如下:
1.查询返回的数据为空,仍把这个空结果进行缓存,但过期时间会比较短;
2.布隆过滤器:将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存
在的数据会被这个 bitmap 拦截掉,从而避免了对 DB 的查询。
什么是缓存击穿?
对于设置了过期时间的 key,缓存在某个时间点过期的时候,恰好这时间点对这个 Key
有大量的并发请求过来,这些请求发现缓存过期一般都会从后端 DB 加载数据并回设到缓
存,这个时候大并发的请求可能会瞬间把 DB 压垮。
击穿解决方案如下:
1.使用互斥锁:当缓存失效时,不立即去 load db,先使用如 Redis 的 setnx 去设置
一个互斥锁,当操作成功返回时再进行 load db 的操作并回设缓存,否则重试 get 缓存的
方法。
2.永远不过期:物理不过期,但逻辑过期(后台异步线程去刷新)。
什么是缓存雪崩?
设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到
DB,DB 瞬时压力过重雪崩。与缓存击穿的区别:雪崩是很多 key,击穿是某一个 key 缓存。
雪崩解决方案如下:
将缓存失效时间分散开,比如可以在原有的失效时间基础上增加一个随机值,比如 1-5
分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
在选择缓存时,什么时候选择 redis,什么时候
选择 memcached
选择 redis 的情况:
1、复杂数据结构,value 的数据是哈希,列表,集合,有序集合等这种情况下,会选
择 redis, 因为 memcache 无法满足这些数据结构,最典型的的使用场景是,用户订单列表,
用户消息,帖子评论等。
2、需要进行数据的持久化功能,但是注意,不要把 redis 当成数据库使用,如果 redis
挂了,内存能够快速恢复热数据,不会将压力瞬间压在数据库上,没有 cache 预热的过程。
对于只读和数据一致性要求不高的场景可以采用持久化存储
3、高可用,redis 支持集群,可以实现主动复制,读写分离,而对于 memcache 如果
想要实现高可用,需要进行二次开发。
4、存储的内容比较大,memcache 存储的 value 最大为 1M .选择 memcache 的场景:
当纯 KV,数据量非常大的业务,使用 memcache 更合适,原因是如下:
a)memcache 的内存分配采用的是预分配内存池的管理方式,能够省去内存分配的时间,
redis 是临时申请空间,可能导致碎片化。
b)虚拟内存使用,memcache 将所有的数据存储在物理内存里,redis 有自己的 vm 机
制,理论上能够存储比物理内存更多的数据,当数据超量时,引发 swap,把冷数据刷新到磁
盘上,从这点上,数据量大时,memcache 更快
c)网络模型,memcache 使用非阻塞的 IO 复用模型,redis 也是使用非阻塞的 IO 复
用模型,但是 redis 还提供了一些非 KV 存储之外的排序,聚合功能,复杂的 CPU 计算,
会阻塞整个 IO 调度,从这点上由于 redis 提供的功能较多,memcache 更快些
d) 线程模型,memcache 使用多线程,主线程监听,worker 子线程接受请求,执行读
写,这个过程可能存在锁冲突。redis 使用的单线程,虽然无锁冲突,但是难以利用多核的
特性提升吞吐量。
缓存与数据库不一致怎么办
假设采用的主存分离,读写分离的数据库,
如果一个线程 A 先删除缓存数据,然后将数据写入到主库当中,这个时候,主库和从
库同步没有完成,线程 B 从缓存当中读取数据失败,从从库当中读取到旧数据,然后更新
至缓存,这个时候,缓存当中的就是旧的数据。
发生上述不一致的原因在于,主从库数据不一致问题,加入了缓存之后,主从不一致的
时间被拉长了
处理思路:
在从库有数据更新之后,将缓存当中的数据也同时进行更新,即当从库发生了数据更新
之后,向缓存发出删除,淘汰这段时间写入的旧数据。
主从数据库不一致如何解决
场景描述,对于主从库,读写分离,如果主从库更新同步有时差,就会导致主从库数据
的不一致
忽略这个数据不一致,在数据一致性要求不高的业务下,未必需要时时一致性
强制读主库,使用一个高可用的主库,数据库读写都在主库,添加一个缓存,提升数据
读取的性能。
选择性读主库,添加一个缓存,用来记录必须读主库的数据,将哪个库,哪个表,哪个
主键,作为缓存的 key,设置缓存失效的时间为主从库同步的时间,如果缓存当中有这个数
据,直接读取主库,如果缓存当中没有这个主键,就到对应的从库中读取。
Redis 常见的性能问题和解决方案
1、master 最好不要做持久化工作,如 RDB 内存快照和 AOF 日志文件
2、如果数据比较重要,某个 slave 开启 AOF 备份,策略设置成每秒同步一次
3、为了主从复制的速度和连接的稳定性,master 和 Slave 最好在一个局域网内
4、尽量避免在压力大得主库上增加从库
5、主从复制不要采用网状结构,尽量是线性结构,Master<–Slave1<----Slave2 …
Redis 的数据淘汰策略有哪些
voltile-lru 从已经设置过期时间的数据集中挑选最近最少使用的数据淘汰
voltile-ttl 从已经设置过期时间的数据库集当中挑选将要过期的数据
voltile-random 从已经设置过期时间的数据集任意选择淘汰数据
allkeys-lru 从数据集中挑选最近最少使用的数据淘汰
allkeys-random 从数据集中任意选择淘汰的数据
no-eviction 禁止驱逐数据
Redis 当中有哪些数据结构
字符串 String、字典 Hash、列表 List、集合 Set、有序集合 SortedSet。如果是高
级用户,那么还会有,如果你是 Redis 中高级用户,还需要加上下面几种数据结构
HyperLogLog、Geo、Pub/Sub。
假如 Redis 里面有 1 亿个 key,其中有 10w
个 key 是以某个固定的已知的前缀开头的,如果
将它们全部找出来?
使用 keys 指令可以扫出指定模式的 key 列表。
对方接着追问:如果这个 redis 正在给线上的业务提供服务,那使用 keys 指令会有
什么问题?
这个时候你要回答 redis 关键的一个特性:redis 的单线程的。keys 指令会导致线程
阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用 scan
指令,scan 指令可以无阻塞的提取出指定模式的 key 列表,但是会有一定的重复概率,在
客户端做一次去重就可以了,但是整体所花费的时间会比直接用 keys 指令长。
使用 Redis 做过异步队列吗,是如何实现的
使用 list 类型保存数据信息,rpush 生产消息,lpop 消费消息,当 lpop 没有消息
时,可以 sleep 一段时间,然后再检查有没有信息,如果不想 sleep 的话,可以使用 blpop,
在没有信息的时候,会一直阻塞,直到信息的到来。redis 可以通过 pub/sub 主题订阅模
式实现一个生产者,多个消费者,当然也存在一定的缺点,当消费者下线时,生产的消息会
丢失。
Redis 如何实现延时队列
使用 sortedset,使用时间戳做 score, 消息内容作为 key,调用 zadd 来生产消息,
消费者使用 zrangbyscore 获取 n 秒之前的数据做轮询处理。
Zookeeper 面试题目
ZooKeeper 是什么?
ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的
Chubby 一个开源的实现,它是集群的管理者,监视着集群中各个节点的状态根据节点提交
的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供给
用户。
客户端的读请求可以被集群中的任意一台机器处理,如果读请求在节点上注册了监听
器,这个监听器也是由所连接的 zookeeper 机器来处理。对于写请求,这些请求会同时发
给其他 zookeeper 机器并且达成一致后,请求才会返回成功。因此,随着 zookeeper 的集
群机器增多,读请求的吞吐会提高但是写请求的吞吐会下降。
有序性是 zookeeper 中非常重要的一个特性,所有的更新都是全局有序的,每个更新
都有一个唯一的时间戳,这个时间戳称为 zxid(Zookeeper Transaction Id)。而读请求
只会相对于更新有序,也就是读请求的返回结果中会带有这个 zookeeper 最新的 zxid。
ZooKeeper 提供了什么?
1、文件系统
2、通知机制
Zookeeper 文件系统
Zookeeper 提供一个多层级的节点命名空间(节点称为 znode)。与文件系统不同的是,
这些节点都可以设置关联的数据,而文件系统中只有文件节点可以存放数据而目录节点不
行。Zookeeper 为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性
使得 Zookeeper 不能用于存放大量的数据,每个节点的存放数据上限为 1M。
4.四种类型的 znode
1、PERSISTENT-持久化目录节点
客户端与 zookeeper 断开连接后,该节点依旧存在
2、PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点
客户端与 zookeeper 断开连接后,该节点依旧存在,只是 Zookeeper 给该节点名称进
行顺序编号
3、EPHEMERAL-临时目录节点
客户端与 zookeeper 断开连接后,该节点被删除
4、EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点客户端与 zookeeper 断开连接后,
该节点被删除,只是 Zookeeper 给该节点名称进行顺序编号
Zookeeper 通知机制
client 端会对某个 znode 建立一个 watcher 事件,当该 znode 发生变化时,这些
client 会收到 zk 的通知,然后 client 可以根据 znode 变化来做出业务上的改变等。
Zookeeper 做了什么?
1、命名服务
2、配置管理
3、集群管理
4、分布式锁
5、队列管理
7.zk 的命名服务(文件系统)
命名服务是指通过指定的名字来获取资源或者服务的地址,利用 zk 创建一个全局的路
径,即是唯一的路径,这个路径就可以作为一个名字,指向集群中的集群,提供的服务的地
址,或者一个远程的对象等等。
zk 的配置管理(文件系统、通知机制)
程序分布式的部署在不同的机器上,将程序的配置信息放在 zk 的 znode 下,当有配
置发生改变时,也就是 znode 发生变化时,可以通过改变 zk 中某个目录节点的内容,利
用 watcher 通知给各个客户端,从而更改配置。
Zookeeper 集群管理(文件系统、通知机制)
所谓集群管理无在乎两点:是否有机器退出和加入、选举 master。
对于第一点,所有机器约定在父目录下创建临时目录节点,然后监听父目录节点的子节
点变化消息。一旦有机器挂掉,该机器与 zookeeper 的连接断开,其所创建的临时目录节
点被删除,所有其他机器都收到通知:某个兄弟目录被删除,于是,所有人都知道:它上船
了。
新机器加入也是类似,所有机器收到通知:新兄弟目录加入,highcount 又有了,对于
第二点,我们稍微改变一下,所有机器创建临时顺序编号目录节点,每次选取编号最小的机
器作为 master 就好。
Zookeeper 分布式锁(文件系统、通知机制)
有了 zookeeper 的一致性文件系统,锁的问题变得容易。锁服务可以分为两类,一个
是保持独占,另一个是控制时序。
对于第一类,我们将 zookeeper 上的一个 znode 看作是一把锁,通过 createznode 的
方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也
即拥有了这把锁。用完删除掉自己创建的 distribute_lock 节点就释放出锁。对于第二类,
/distribute_lock 已经预先存在,所有客户端在它下面创建临时顺序编号目录节点,和选
master 一样,编号最小的获得锁,用完删除,依次方便。
获取分布式锁的流程
在获取分布式锁的时候在 locker 节点下创建临时顺序节点,释放锁的时候删除该临时
节点。客户端调用 createNode 方法在 locker 下创建临时顺序节点,然后调用
getChildren(“locker”)来获取 locker 下面的所有子节点,注意此时不用设置任何
Watcher。客户端获取到所有的子节点 path 之后,如果发现自己创建的节点在所有创建的
子节点序号最小,那么就认为该客户端获取到了锁。如果发现自己创建的节点并非 locker
所有子节点中最小的,说明自己还没有获取到锁,此时客户端需要找到比自己小的那个节点,
然后对其调用 exist()方法,同时对其注册事件监听器。之后,让这个被关注的节点删除,
则客户端的 Watcher 会收到相应通知,此时再次判断自己创建的节点是否是 locker 子节
点中序号最小的,如果是则获取到了锁,如果不是则重复以上步骤继续获取到比自己小的一
个节点并注册监听。当前这个过程中还需要许多的逻辑判断。
代码的实现主要是基于互斥锁,获取分布式锁的重点逻辑在于 BaseDistributedLock,
实现了基于
Zookeeper 实现分布式锁的细节。
Zookeeper 队列管理(文件系统、通知机制)
两种类型的队列:
1、同步队列,当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员
到达。
2、队列按照 FIFO 方式进行入队和出队操作。
第一类,在约定目录下创建临时目录节点,监听节点数目是否是我们要求的数目。
第二类,和分布式锁服务中的控制时序场景基本原理一致,入列有编号,出列按编号。
在特定的目录下创建 PERSISTENT_SEQUENTIAL 节点,创建成功时 Watcher 通知等待的队
列,队列删除序列号最小的节点用以消费。此场景下 Zookeeper 的 znode 用于消息存储,
znode 存储的数据就是消息队列中的消息内容,SEQUENTIAL 序列号就是消息的编号,按序
取出即可。由于创建的节点是持久化的,所以不必担心队列消息的丢失问题。
Zookeeper 数据复制 Zookeeper 作为一个集群
提供一致的数据服务,自然,它要在所有机器间做
数据复制。数据复制的好处:
1、容错:一个节点出错,不致于让整个系统停止工作,别的节点可以接管它的工作;
2、提高系统的扩展能力 :把负载分布到多个节点上,或者增加节点来提高系统的负载
能力;
3、提高性能:让客户端本地访问就近的节点,提高用户访问速度。
从客户端读写访问的透明度来看,数据复制集群系统分下面两种:
1、写主(WriteMaster) :对数据的修改提交给指定的节点。读无此限制,可以读取任
何一个节点。这种情况下客户端需要对读与写进行区别,俗称读写分离;
2、写任意(Write Any):对数据的修改可提交给任意的节点,跟读一样。这种情况下,
客户端对集群节点的角色与变化透明。
对 zookeeper 来说,它采用的方式是写任意。通过增加机器,它的读吞吐能力和响应
能力扩展性非常好,而写,随着机器的增多吞吐能力肯定下降(这也是它建立 observer 的
原因),而响应能力则取决于具体实现方式,是延迟复制保持最终一致性,还是立即复制快
速响应。
Zookeeper 工作原理
Zookeeper 的核心是原子广播,这个机制保证了各个 Server 之间的同步。实现这个机
制的协议叫做 Zab 协议。Zab 协议有两种模式,它们分别是恢复模式(选主)和广播模式
(同步)。当服务启动或者在领导者崩溃后,Zab 就进入了恢复模式,当领导者被选举出来,
且大多数 Server 完成了和 leader 的状态同步以后,恢复模式就结束了。状态同步保证了
leader 和 Server 具有相同的系统状态。
zookeeper 是如何保证事务的顺序一致性的?
zookeeper 采用了递增的事务 Id 来标识,所有的 proposal(提议)都在被提出的时
候加上了 zxid,zxid 实际上是一个 64 位的数字,高 32 位是 epoch(时期; 纪元; 世; 新
时代)用来标识 leader 是否发生改变,如果有新的 leader 产生出来,epoch 会自增,低
32 位用来递增计数。当新产生 proposal 的时候,会依据数据库的两阶段过程,首先会向
其他的 server 发出事务执行请求,如果超过半数的机器都能执行并且能够成功,那么就会
开始执行。
Zookeeper 下 Server 工作状态每个 Server
在工作过程中有三种状态:
LOOKING:当前 Server 不知道 leader 是谁,正在搜寻
LEADING:当前 Server 即为选举出来的 leader
FOLLOWING:leader 已经选举出来,当前 Server 与之同步
zookeeper 是如何选取主 leader 的?
当 leader 崩溃或者 leader 失去大多数的 follower,这时 zk 进入恢复模式,恢复
模式需要重新选举出一个新的 leader,让所有的 Server 都恢复到一个正确的状态。Zk 的
选举算法有两种:一种是基于 basic paxos 实现的,另外一种是基于 fast paxos 算法实
现的。系统默认的选举算法为 fast paxos。
1、Zookeeper 选主流程(basic paxos)
(1)选举线程由当前 Server 发起选举的线程担任,其主要功能是对投票结果进行统
计,并选出推荐的 Server;
(2)选举线程首先向所有 Server 发起一次询问(包括自己);
(3)选举线程收到回复后,验证是否是自己发起的询问(验证 zxid 是否一致),然后
获取对方的 id(myid),并存储到当前询问对象列表中,最后获取对方提议的 leader 相关
信息(id,zxid),并将这些信息存储到当次选举的投票记录表中;
(4)收到所有 Server 回复以后,就计算出 zxid 最大的那个 Server,并将这个
Server 相关信息设置成下一次要投票的 Server;
(5)线程将当前 zxid 最大的 Server 设置为当前 Server 要推荐的 Leader,如果此
时获胜的 Server 获得 n/2 + 1 的 Server 票数,设置当前推荐的 leader 为获胜的
Server,将根据获胜的 Server 相关信息设置自己的状态,否则,继续这个过程,直到 leader
被选举出来。 通过流程分析我们可以得出:要使 Leader 获得多数 Server 的支持,则
Server 总数必须是奇数 2n+1,且存活的 Server 的数目不得少于 n+1. 每个 Server 启动
后都会重复以上流程。在恢复模式下,如果是刚从崩溃状态恢复的或者刚启动的 server 还
会从磁盘快照中恢复数据和会话信息,zk 会记录事务日志并定期进行快照,方便在恢复时
进行状态恢复。
2、Zookeeper 选主流程(basic paxos)
fast paxos 流程是在选举过程中,某 Server 首先向所有 Server 提议自己要成为
leader,当其它 Server 收到提议以后,解决 epoch 和 zxid 的冲突,并接受对方的提议,
然后向对方发送接受提议完成的消息,重复这个流程,最后一定能选举出 Leader。
Zookeeper 同步流程
选完 Leader 以后,zk 就进入状态同步过程。
1、Leader 等待 server 连接;
2、Follower 连接 leader,将最大的 zxid 发送给 leader;
3、Leader 根据 follower 的 zxid 确定同步点;
4、完成同步后通知 follower 已经成为 uptodate 状态;
5、Follower 收到 uptodate 消息后,又可以重新接受 client 的请求进行服务了。
分布式通知和协调
对于系统调度来说:操作人员发送通知实际是通过控制台改变某个节点的状态,然后 zk
将这些变化发送给注册了这个节点的 watcher 的所有客户端。
对于执行情况汇报:每个工作进程都在某个目录下创建一个临时节点。并携带工作的进
度数据,这样汇总的进程可以监控目录子节点的变化获得工作进度的实时的全局情况。
机器中为什么会有 leader?
在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,其他的机器可以
共享这个结果,这样可以大大减少重复计算,提高性能,于是就需要进行 leader 选举。
zk 节点宕机如何处理?
Zookeeper 本身也是集群,推荐配置不少于 3 个服务器。Zookeeper 自身也要保证当
一个节点宕机时,其他节点会继续提供服务。
如果是一个 Follower 宕机,还有 2 台服务器提供访问,因为 Zookeeper 上的数据是
有多个副本的,数据并不会丢失;
如果是一个 Leader 宕机,Zookeeper 会选举出新的 Leader。
ZK 集群的机制是只要超过半数的节点正常,集群就能正常提供服务。只有在 ZK 节点
挂得太多,只剩一半或不到一半节点能工作,集群才失效。
所以
3 个节点的 cluster 可以挂掉 1 个节点(leader 可以得到 2 票>1.5)
2 个节点的 cluster 就不能挂掉任何 1 个节点了(leader 可以得到 1 票<=1)
zookeeper 负载均衡和 nginx 负载均衡区别
zk 的负载均衡是可以调控,nginx 只是能调权重,其他需要可控的都需要自己写插件;
但是 nginx 的吞吐量比 zk 大很多,应该说按业务选择用哪种方式。
zookeeper watch 机制
Watch 机制官方声明:一个 Watch 事件是一个一次性的触发器,当被设置了 Watch 的
数据发生了改变的时候,则服务器将这个改变发送给设置了 Watch 的客户端,以便通知它
们。
Zookeeper 机制的特点:
1、一次性触发数据发生改变时,一个 watcher event 会被发送到 client,但是 client
只会收到一次这样的信息。
2、watcher event 异步发送 watcher 的通知事件从 server 发送到 client 是异步
的,这就存在一个问题,不同的客户端和服务器之间通过 socket 进行通信,由于网络延迟
或其他因素导致客户端在不通的时刻监听到事件,由于 Zookeeper 本身提供了 ordering
guarantee,即客户端监听事件后,才会感知它所监视 znode 发生了变化。所以我们使用
Zookeeper 不能期望能够监控到节点每次的变化。Zookeeper 只能保证最终的一致性,而无
法保证强一致性。
3、数据监视 Zookeeper 有数据监视和子数据监视 getdata() and exists()设置数据
监视,getchildren()设置了子节点监视。
4、注册 watcher getData、exists、getChildren
5、触发 watcher create、delete、setData
6、setData()会触发 znode 上设置的 data watch(如果 set 成功的话)。一个成功
的 create() 操作会触发被创建的 znode 上的数据 watch,以及其父节点上的 child
watch。而一个成功的 delete()操作将会同时触发一个 znode 的 data watch 和 child
watch(因为这样就没有子节点了),同时也会触发其父节点的 child watch。
7、当一个客户端连接到一个新的服务器上时,watch 将会被以任意会话事件触发。当
与一个服务器失去连接的时候,是无法接收到 watch 的。而当 client 重新连接时,如果
需要的话,所有先前注册过的 watch,都会被重新注册。通常这是完全透明的。只有在一个
特殊情况下,watch 可能会丢失:对于一个未创建的 znode 的 exist watch,如果在客户
端断开连接期间被创建了,并且随后在客户端连接上之前又删除了,这种情况下,这个 watch
事件可能会被丢失。
8、Watch 是轻量级的,其实就是本地 JVM 的 Callback,服务器端只是存了是否有设
置了 Watcher 的布尔类型
数据结构与算法面试题目
1.说说常见的集合有哪些。
Map 接口和Collection 接口是所有集合类框架的父接口:
Collcetion 接口的子接口包括:Set 接口和List 接口。
Map 接口的实现类主要有:HashMap、HashTable、ConcurrentHashMap 以及Properties
等。
Set 接口的实现类主要有:HashSet、TreeSet、LinkedHashSet 等。
List 接口的实现类主要有:ArrayList、LinkedList、Stack 以及 Vector 等。
HashMap 与 HashTable 的区别。
主要有以下几点区别。
HashMap 没有考虑同步,是线程不安全的;HashTable 在关键方法(put、get、contains、
size 等)上使用了Synchronized 关键字,是线程安全的。
HashMap 允许Key/Value 都为null,后者Key/Value 都不允许为null。
HashMap 继承自AbstractMap 类;而HashTable 继承自Dictionary 类。
在jdk1.8 中,HashMap 的底层结构是数组+链表+红黑树,而HashTable 的底层结构是
数组+链表。
HashMap 对底层数组采取的懒加载,即当执行第一次put 操作时才会创建数组;而
HashTable 在初始化时就创建了数组。
HashMap 中数组的默认初始容量是 16 ,并且必须是 2 的指数倍数,扩容时
newCapacity=2oldCapacity;而HashTable 中默认的初始容量是11,并且不要求必须是2 的
指数倍数,扩容时newCapacity=2oldCapacity+1。
在hash 取模计算时,HashTable 的模数一般为素数,简单的做除取模结果会更为均匀,
int index = (hash & 0x7FFFFFFF) % tab.length;
HashMap 的模数为2 的幂,直接用位运算来得到结果,效率要大大高于做除法,i = (n