大部分知识点来源于该博主——骆昊 知识点来源于网络,知道的可以在评论区贴上来源喔
@Reference、@Autowired和@Resource的区别:
@Reference:是dubbo的注解,也是注入,他一般注入的是分布式的远程服务的对象,需要dubbo配置使用。
@Autowired:org.springframework.beans.factory.annotation.Autowired
SpringBoot项目中常用。简单来说就是引入由Spring容器管理的bean。
@Resource:javax.annotation.Resource
作用相当于@Autowired,只不过@Autowired是byType自动注入,而@Resource默认byName自动注入。
简单来说他们的区别:
@Reference注入的是分布式中的远程服务对象,@Resource和@Autowired注入的是本地spring容器中的对象。
Dubbo
Dobbo:阿里巴巴公司开源的一个高性能优秀的(分布式)服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 [1] Spring框架无缝集成。 (RPC:远程过程调用) 三大核心能力: 面向接口的远程方法调用, 智能容错和负载均衡, 以及服务自动注册和发现。
Dubbo提供的注册中心有如下几种类型可供选择:
Multicast注册中心
Zookeeper注册中心(推荐)
Redis注册中心(缓存推荐)
Simple注册中心
Dubbo优缺点 优点: 1.透明化的远程方法调用- 像调用本地方法一样调用远程方法;只需简单配置,没有任何API侵入。 2.软负载均衡及容错机制-可在内网替代nginx lvs等硬件负载均衡器。 3.服务注册中心自动注册 & 配置管理-不需要写死服务提供者地址,注册中心基于接口名自动查询提供者ip。 使用类似zookeeper等分布式协调服务作为服务注册中心,可以将绝大部分项目配置移入zookeeper集群。 4.服务接口监控与治理-Dubbo-admin与Dubbo-monitor提供了完善的服务接口管理与监控功能,针对不同应用的不同接口,可以进行 多版本,多协议,多注册中心管理。
缺点:只支持JAVA语言
Zookeeper是一个分布式的服务框架,是树型的目录服务的数据存储,能做到集群管理数据 ,这里能很好的作为Dubbo服务的注册中心。 Dubbo能与Zookeeper做到集群部署,当提供者出现断电等异常停机时,Zookeeper注册中心能自动删除提供者信息, 当提供者重启时,能自动恢复注册数据,以及订阅请求。
Dubbo 的整体架构设计有哪些分层?
接口服务层(Service):该层与业务逻辑相关,根据 provider (服务提供者)和 consumer (服务消费者)的业务设计对应的接口和实现
配置层(Config):对外配置接口,以 ServiceConfig 和 ReferenceConfig 为 中心
服务代理层(Proxy):服务接口透明代理,生成服务的客户端 Stub 和 服务端 的 Skeleton,以 ServiceProxy 为中心,扩展接口为 ProxyFactory
服务注册层(Registry):封装服务地址的注册和发现,以服务 URL 为中心, 扩展接口为 RegistryFactory、Registry、RegistryService
路由层(Cluster):封装多个提供者的路由和负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster、Directory、Router 和 LoadBlancce
监控层(Monitor):RPC 调用次数和调用时间监控,以 Statistics 为中心,扩 展接口为 MonitorFactory、Monitor 和 MonitorService
远程调用层(Protocal):封装 RPC 调用,以 Invocation 和 Result 为中心, 扩展接口为 Protocal、Invoker 和 Exporter
信息交换层(Exchange):封装请求响应模式,同步转异步。以 Request 和 Response 为中心,扩展接口为 Exchanger、ExchangeChannel、 ExchangeClient 和 ExchangeServer
网络传输层(Transport):抽象 mina 和 netty 为统一接口,以 Message 为 中心,扩展接口为 Channel、Transporter、Client、Server 和 Codec
数据序列化层(Serialize):可复用的一些工具,扩展接口为 Serialization、 ObjectInput、ObjectOutput 和 ThreadPool
默认使用的是什么通信框架,还有别的选择吗?
默认推荐使用netty 框架,还有 mina
服务调用是阻塞的吗?
默认是阻塞的,可以异步调用,没有返回值的可以这么做。 Dubbo 是基于 NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成 并行调用多个远程服务,相对多线程开销较小,异步调用会返回一个 Future 对 象。
一般使用什么注册中心?还有别的选择吗?
推荐使用 Zookeeper 作为注册中心,还有 Redis、Multicast、Simple 注册中 心,但不推荐。
默认使用什么序列化框架,你知道的还有哪些?
推荐使用 Hessian 序列化,还有 Duddo、FastJson、Java 自带序列化。
服务提供者能实现失效踢出是什么原理?
服务失效踢出基于 zookeeper 的临时节点原理。
服务上线怎么不影响旧版本?
采用多版本开发,不影响旧版本。
服务上线怎么兼容旧版本?
可以用版本号(version)过渡,多个不同版本的服务注册到注册中心,版本号不 同的服务相互间不引用。这个和服务分组的概念有一点类似。
如何解决服务调用链过长的问题?
可以结合 zipkin 实现分布式服务追踪。
说说核心的配置有哪些?
dubbo推荐用什么协议?
- dubbo://(推荐)
- rmi://
- hessian://
- http://
- webservice://
- thrift://
- memcached://
- redis://
- rest://
同一个服务多个注册的情况下可以直连某一个服务吗?
可以点对点直连,修改配置即可,也可以通过 telnet 直接某个服务。
画一画服务注册与发现的流程图?
dubbo容错方案
集群容错方案 | 说明 |
---|
Failover Cluster | 失败自动切换,自动重试其它服务器(默认) | Failfast Cluster | 快速失败,立即报错,只发起一次调用 | Failsafe Cluster | 失败安全,出现异常时,直接忽略 | Failback Cluster | 失败自动恢复,记录失败请求,定时重发 | Forking Cluster | 并行调用多个服务器,只要一个成功即返回 | Broadcast Cluster | 广播逐个调用所有提供者,任意一个报错则报错 |
Dubbo 服务降级,失败重试怎么做?
可以通过 dubbo:reference 中设置 mock=“return null”。mock 的值也可以修 改为 true,然后再跟接口同一个路径下实现一个 Mock 类,命名规则是 “接口 名称+Mock” 后缀。然后在 Mock 类里实现自己的降级逻辑
Dubbo 使用过程中都遇到了些什么问题?
在注册中心找不到对应的服务,检查 service 实现类是否添加了@service 注解 无法连接到注册中心,检查配置文件中的对应的测试 ip 是否正确
Dubbo 配置文件是如何加载到 Spring 中的?
Spring 容器在启动的时候,会读取到 Spring 默认的一些 schema 以及 Dubbo 自 定义的 schema,每个 schema 都会对应一个自己的 NamespaceHandler, NamespaceHandler 里面通过 BeanDefinitionParser 来解析配置信息并转化为 需要加载的 bean 对象!
Dubbo 支持分布式事务吗?
目前暂时不支持,可与通过 tcc-transaction 框架实现 介绍:tcc-transaction 是开源的 TCC 补偿性分布式事务框架 Git 地址 TCC-Transaction 通过 Dubbo 隐式传参的功能,避免自己对业务代码的入侵。
Dubbo 可以对结果进行缓存吗?
可以(声明式缓存,提高数据访问速度,减少用户加缓存的工作量)
<dubbo:reference cache="true" />
其实比普通的配置文件就多了一个标签 cache="true
Dubbo 必须依赖的包有哪些?
Dubbo 必须依赖 JDK,其他为可选。
Dubbo telnet 命令能做什么?
dubbo 服务发布之后,我们可以利用 telnet 命令进行调试、管理。 Dubbo2.0.5 以上版本服务提供端口支持 telnet 命令
连接服务 telnet localhost 20880 //键入回车进入 Dubbo 命令模式。
查看服务列表
dubbo>ls
com.test.TestService
dubbo>ls com.test.TestService
create
delete
query
- ls (list services and methods)
- ls : 显示服务列表。
- ls -l : 显示服务详细信息列表。
- ls XxxService:显示服务的方法列表。
- ls -l XxxService:显示服务的方法详细信息列表
Dubbo 支持服务降级吗?
以通过 dubbo:reference 中设置 mock=“return null”。mock 的值也可以修改 为 true,然后再跟接口同一个路径下实现一个 Mock 类,命名规则是 “接口名 称+Mock” 后缀。然后在 Mock 类里实现自己的降级逻辑
Dubbo 如何优雅停机?
Dubbo 是通过 JDK 的 ShutdownHook 来完成优雅停机的,所以如果使用 kill -9 PID 等强制关闭指令,是不会执行优雅停机的,只有通过 kill PID 时,才 会执行。
Dubbo 和 Dubbox 之间的区别?
Dubbox 是继 Dubbo 停止维护后,当当网基于 Dubbo 做的一个扩展项目,如 加了服务可 Restful 调用,更新了开源组件等。
Dubbo 和 Spring Cloud 的区别?
根据微服务架构在各方面的要素,看看 Spring Cloud 和 Dubbo 都提供了哪些支持。
| Dubbo | Spring Cloud |
---|
服务注册中心 | Zookeeper | Spring Cloud Netflix Eureka | 服务调用方式 | RPC | REST API | 服务网关 | 无 | Spring Cloud Netflix Zuul | 断路器 | 不完善 | Spring Cloud Netflix Hystrix | 分布式配置 | 无 | Spring Cloud Config | 服务跟踪 | 无 | Spring Cloud Sleuth | 消息总线 | 无 | Spring Cloud Bus | 数据流 | 无 | Spring Cloud Stream | 批量任务 | 无 | Spring Cloud Task | …… | …… | …… |
使用 Dubbo 构建的微服务架构就像组装电脑,各环节我们的选择自由度很高,但 是最终结果很有可能因为一条内存质量不行就点不亮了,总是让人不怎么放心, 但是如果你是一名高手,那这些都不是问题;而 Spring Cloud 就像品牌机,在 Spring Source 的整合下,做了大量的兼容性测试,保证了机器拥有更高的稳定性, 但是如果要在使用非原装组件外的东西,就需要对其基础有足够的了解
你还了解别的分布式框架吗?
别的还有 spring 的 spring cloud,facebook 的 thrift,twitter 的 finagle 等
http和https
跨域:协议、域名(子/主)端口号任意一个不同,相互请求资源都可以称为跨域。 域名地址组成----例如: http://www.abc.com:8080/scripts/jquery.js http://(协议); www(子域名); abc.com(主域名); 8080(端口号); scripts/jquery.js(请求资源地址);
HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。(最广泛、明文传输安全性较差、端口80)
HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。(要到ca申请证书,一般免费证书较少,因而需要一定费用、是由http+SSL加密传输的,身份认证的网络协议,安全性较高、端口443)
HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
http 和RPC 的区别
什么是RPC?
RPC两大核心:通讯,序列化 什么是RPC,推荐阅读 https://www.jianshu.com/p/2accc2840a1b http 和RPC 都是很常见的服务远程调用的方式,那么它们之间有什么区别呢 https://www.cnblogs.com/helloworldmybokeyuan/p/11626833.html
RPC:Remote Produce Call远程过程调用,类似的还有RMI(Remote Methods Invoke 远程方法调用,是JAVA中的概念,是JAVA十三大技术之一)。自定义数据格式,基于原生TCP通信,速度快,效率高。早期的webservice,现在热门的dubbo,都是RPC的典型
RPC的框架:webservie(cxf)、dubbo RMI的框架:hessian
Http:(前面也有提到)http其实是一种网络传输协议,基于TCP,规定了数据传输的格式。现在客户端浏览器与服务端通信基本都是采用Http协议。也可以用来进行远程服务调用。缺点是消息封装臃肿。
现在热门的Rest风格,就可以通过http协议来实现。
http的实现技术:HttpClient
相同点:底层通讯都是基于socket,都可以实现远程调用,都可以实现服务调用服务
不同点: RPC:框架有:dubbo、cxf、(RMI远程方法调用)Hessian 当使用RPC框架实现服务间调用的时候,要求服务提供方和服务消费方都必须使用统一的RPC框架,要么都dubbo,要么都cxf
跨操作系统在同一编程语言内使用 优势:调用快、处理快
http:框架有:httpClient 当使用http进行服务间调用的时候,无需关注服务提供方使用的编程语言,也无需关注服务消费方使用的编程语言,服务提供方只需要提供restful风格的接口,服务消费方,按照restful的原则,请求服务,即可
跨系统跨编程语言的远程调用框架 优势:通用性强
总结:对比RPC和http的区别 1 RPC要求服务提供方和服务调用方都需要使用相同的技术,要么都hessian,要么dubbo而http无需关注语言的实现,只需要遵循rest规范 2 RPC的开发要求较多,像Hessian框架还需要服务器提供完整的接口代码(包名.类名.方法名必须完全一致),否则客户端无法运行 3 Hessian只支持POST请求 4 Hessian只支持JAVA语言
vue.js跟thymeleaf 的区别
首先说,这两种技术在本质上属于不同类型的产品。Vue.js属于前端框架,thymeleaf属于模板引擎。
虽然它们可以实现相同的功能(如列表),但它们的工作流程是不同的:vue.Js通过异步请求数据,后端向前端返回json,
前端通过列表呈现vue指令循环。Thymeleaf是在后端实现页面的渲染,将页面直接呈现给浏览器显示。
一般来说,后台管理我们会使用前端框架,而网站前台的部分有些页面会用thymeleaf。
有两个原因:
(1) 因为使用vuejs进行异步请求,打开页面看到的信息显示会出现延迟,而使用thymeleaf,页面的信息就会很快看到。
(2)异步加载数据不会被搜索引擎抓取。所以当我们希望数据被搜索引擎收录,就需要使用thymeleaf这样的模板引擎。
web开发,提供3个@Component注解衍生注解(功能一样)取代
@Repository(“名称”):dao层 @Service(“名称”):service层 @Controller(“名称”):web层
@Autowired:自动根据类型注入 @Qualifier(“名称”):指定自动注入的id名称
@Resource(“名称”) @ PostConstruct 自定义初始化 @ PreDestroy 自定义销毁
mybatis
什么是 Mybatis?
1、Mybatis 是一个半 ORM(Object relational mapping对象关系映射)框架,它内部封装了 JDBC,开发时 只需要关注 SQL 语句本身,不需要花费精力去处理加载驱动、创建连接、创建 statement (声明)等繁杂的过程。程序员直接编写原生态 sql,可以严格控制 sql 执行性 能,灵活度高。 2、MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO 映射成数 据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。 3、通过 xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过 java 对象和 statement 中 sql 的动态参数进行映射生成最终执行的 sql 语句,最 后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。(从执行 sql 到返 回 result 的过程)。
Mybaits 的优点:
1、基于 SQL 语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任 何影响,SQL 写在 XML 里,解除 sql 与程序代码的耦合,便于统一管理;提供 XML 标签,支持编写动态 SQL 语句,并可重用。 2、与 JDBC 相比,减少了 50%以上的代码量,消除了 JDBC 大量冗余的代码,不 需要手动开关连接; 3、很好的与各种数据库兼容(因为 MyBatis 使用 JDBC 来连接数据库,所以只要 JDBC 支持的数据库 MyBatis 都支持)。 4、能够与 Spring 很好的集成; 5、提供映射标签,支持对象与数据库的 ORM 字段关系映射;提供对象关系映射 标签,支持对象关系组件维护。
MyBatis 框架的缺点:
1、SQL 语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写 SQL 语句的功底有一定要求。 2、SQL 语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
MyBatis 框架适用场合:
1、MyBatis 专注于 SQL 本身,是一个足够灵活的 DAO 层解决方案。 2、对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis 将是 不错的选择。
MyBatis 与 Hibernate 有哪些不同?
1、Mybatis 和 hibernate 不同,它不完全是一个 ORM 框架,因为 MyBatis 需要 程序员自己编写 Sql 语句。 2、Mybatis 直接编写原生态 sql,可以严格控制 sql 执行性能,灵活度高,非常 适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需 求变化要求迅速输出成果。但是灵活的前提是 mybatis 无法做到数据库无关性, 如果需要实现支持多种数据库的软件,则需要自定义多套 sql 映射文件,工作量大。 3、Hibernate 对象/关系映射能力强,数据库无关性好,对于关系模型要求高的 软件,如果用 hibernate 开发可以节省很多代码,提高效率
#{}和${}的区别是什么?
#{}是预编译处理,$ {}是字符串替换。 Mybatis 在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement(预声明) 的 set 方法来赋值; Mybatis 在处理$ {}时,就是把${}替换成变量的值。 使用#{}可以有效的防止 SQL 注入,提高系统安全性。
当实体类中的属性名和表中的字段名不一样 ,怎么办 ?
1.通过在xml里面的sql 查询语句中 定义字段的别名,别名跟实体类的属性名一致
<select id=”selectorder” parametertype=”int” resultetype=”
me.gacl.domain.order”>
select order_id id, order_no orderno ,order_price price form
orders where order_id=#{id};
</select>
2.通过来映射字段名和实体类属性名的一一对应的关系
<select id="getOrder" parameterType="int"
resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>
<resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
<
<id property=”id” column=”order_id”>
<
为数据表中的属性–>
<result property = “orderno” column =”order_no”/>
<result property=”price” column=”order_price” />
</reslutMap>
模糊查询 like 语句该怎么写?
1.在 Java 代码中添加 sql 通配符。
string wildcardname = “%smi%”;
list<name> names = mapper.selectlike(wildcardname);
<select id=”selectlike”>
select * from foo where bar like #{value}
</select>
2.在 sql 语句中拼接通配符,会引起 sql 注入
string wildcardname = “smi”;
list<name> names = mapper.selectlike(wildcardname);
<select id=”selectlike”>
select * from foo where bar like "%"#{value}"%"
</select>
###通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应, 请问,这个 Dao 接口的工作原理是什么?Dao 接口里的方法, 参数不同时,方法能重载吗?
Dao 接口即 Mapper 接口。接口的全限名,就是映射文件中的 namespace 的值; 接口的方法名,就是映射文件中 Mapper 的 Statement 的 id 值;接口方法内的 参数,就是传递给 sql 的参数。 Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符 串作为 key 值,可唯一定位一个 MapperStatement。在 Mybatis 中,每一个 、、、标签,都会被解析为一个 MapperStatement 对象。
举例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯 一找到 namespace 为 com.mybatis3.mappers.StudentDao 下面 id 为 findStudentById 的 MapperStatement。 Mapper 接口里的方法,是不能重载的,因为是使用 全限名+方法名 的保存和寻 找策略。Mapper 接口的工作原理是 JDK 动态代理,Mybatis 运行时会使用 JDK 动态代理为 Mapper 接口生成代理对象 proxy,代理对象会拦截接口方法,转而 执行 MapperStatement 所代表的 sql,然后将 sql 执行结果返回。
Mybatis 是如何进行分页的?分页插件的原理是什么?
Mybatis 使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集执行的内 存分页,而非物理分页。可以在 sql 内直接书写带有物理分页的参数来完成物理分 页功能,也可以使用分页插件来完成物理分页。 分页插件的基本原理是使用 Mybatis 提供的插件接口,实现自定义插件,在插件 的拦截方法内拦截待执行的 sql,然后重写 sql,根据 dialect 方言,添加对应的物 理分页语句和物理分页参数。
Mybatis是如何将sql执行结果封装为目标对象并返回的?
都有哪些映射形式? 第一种是使用< resultMap >标签,逐一定义数据库列名和对象属性名之间的映 射关系。 第二种是使用 sql 列的别名功能,将列的别名书写为对象属性名。 有了列名与属性名的映射关系后,Mybatis 通过反射创建对象,同时使用反射给 对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
如何执行批量插入?
首先,创建一个简单的 insert 语句:
<insert id=”insertname”>
insert into names (name) values (#{value})
</insert>
然后在 java 代码中像下面这样执行批处理插入
list < string > names = new arraylist();
names.add(“fred”);
names.add(“barney”);
names.add(“betty”);
names.add(“wilma”);
// 注意这里 executortype.batch
sqlsession sqlsession =
sqlsessionfactory.opensession(executortype.batch);
try {
namemapper mapper = sqlsession.getmapper(namemapper.class);
for (string name: names) {
mapper.insertname(name);
}
sqlsession.commit();
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback();
throw e;
}
finally {
sqlsession.close();
}
如何获取自动生成的(主)键值?
insert 方法总是返回一个 int 值 ,这个值代表的是插入的行数。 如果采用自增长策略,自动生成的键值在 insert 方法执行完后可以被设置到传入 的参数对象中。 示例:
<insert id=”insertname” usegeneratedkeys=”true” keyproperty=”
id”>
insert into names (name) values (#{name})
</insert>
name name = new name();
name.setname(“fred”);
int rows = mapper.insertname(name);
// 完成后,id 已经被设置到对象中
system.out.println(“rows inserted = ” + rows);
system.out.println(“generated key value = ” + name.getid());
在 mapper 中如何传递多个参数?
1.DAO层的函数
public UserselectUser(String name,String area);
对应的 xml,#{0}代表接收的是 dao 层中的第一个参数,#{1}代表 dao 层中第二
参数,更多参数一致往后加即可。
<select id="selectUser" resultMap="BaseResultMap">
select * fromuser_user_t where user_name = #{0}
and user_area=#{1}
</select>
2.使用 @param 注解:
public interface usermapper {
user selectuser(@param(“username”) string username,
@param(“hashedpassword”) string hashedpassword);
}
然后,就可以在 xml 像下面这样使用(推荐封装为一个 map,作为单个参数传递给 mapper):
<select id=”selectuser” resulttype=”user”>
select id, username, hashedpassword
from some_table
where username = #{username}
and hashedpassword = #{hashedpassword}
</select>
3.多个参数封装成 map
try {
//映射文件的命名空间.SQL 片段的 ID,就可以调用对应的映射文件中的SQL
//由于我们的参数超过了两个,而方法中只有一个 Object 参数收集,因此
我们使用 Map 集合来装载我们的参数
Map < String, Object > map = new HashMap();
map.put("start", start);
map.put("end", end);
return sqlSession.selectList("StudentID.pagination", map);
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback();//回滚
throw e;
} finally {
MybatisUtil.closeSqlSession();//关闭sqlsession
}
Mybatis 动态 sql 有什么用?执行原理?有哪些动态 sql?
Mybatis 动态 sql 可以在 Xml 映射文件内,以标签的形式编写动态 sql,执行原理 是根据表达式的值 完成逻辑判断并动态拼接 sql 的功能。
Mybatis 提供了 9 种动态 sql 标签:
trim | where | set | foreach | if | choose| when | otherwise | bind
Xml 映射文件中,除了常见的 select|insert|updae|delete标签之外,还有哪些标签?
<resultMap>、<parameterMap>、<sql>、<include>、
<selectKey>,加上动态 sql 的 9 个标签,其中<sql>为 sql 片段标签,通过
<include>标签引入 sql 片段,<selectKey>为不支持自增的主键生成策略标
签。
Mybatis 的 Xml 映射文件中,不同的 Xml 映射文件,id 是否可以重复?
不同的 Xml 映射文件,如果配置了 namespace,那么 id 可以重复;如果没有配 置 namespace,那么 id 不能重复;
原因就是 namespace+id 是作为 Map<String, MapperStatement>的 key 使用的,如果没有 namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。 有了 namespace,自然 id 就可以重复,namespace 不同,namespace+id 自然 也就不同。
为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?
Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联 集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而 Mybatis 在查询关联对象或关联集合对象时,需要手动编写 sql 来完成,所以,称之为半自动 ORM 映射工具。
关于XML文件——configuration核心配置文件里面的标签排序
"(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,
objectWrapperFactory?,reflectorFactory?,plugins?,environments?,
databaseIdProvider?,mappers?)"
一对一、一对多的关联查询 ?
<mapper namespace="com.lcb.mapping.userMapper">
<
<select id="getClass" parameterType="int" resultMap="ClassesResultMap">
select * from class c,teacher t where c.teacher_id=t.t_id and c.c_id=#{id}
</select>
<resultMap type="com.lcb.user.Classes" id="ClassesResultMap">
<
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="com.lcb.user.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
</resultMap>
<
<select id="getClass2" parameterType="int" resultMap="ClassesResultMap2">
select * from class c,teacher t,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id=#{id}
</select>
<resultMap type="com.lcb.user.Classes" id="ClassesResultMap2">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="com.lcb.user.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
<collection property="student" ofType="com.lcb.user.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
</collection>
</resultMap>
</mapper>
MyBatis 实现一对一有几种方式?具体怎么操作的?
有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次, 通过在 resultMap 里面配置 association 节点配置一对一的类就可以完成;
嵌套查询是先查一个表,根据这个表里面的结果的 外键 id,去再另外一个表里面 查询数据,也是通过 association 配置,但另外一个表的查询通过 select 属性配置。
MyBatis 实现一对多有几种方式,怎么操作的?
有联合查询和嵌套查询。联合查询是几个表联合查询,只查询一次,通过在 resultMap 里面的 collection 节点配置一对多的类就可以完成;
嵌套查询是先查一个表,根据这个表里面的 结果的外键 id,去再另外一个表里面查询数据,也是通过配置 collection,但另外一个表的查询通过 select 节点配置。
Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么?
Mybatis 仅支持 association【 /??s??si?e??n; ??s???i?e??n/】 关联对象和 collection 关联集合对象的延迟加载,association 指的就是一对一,collection 指的就是一对多查询。在 Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。
它的原理是,使用 CGLIB 创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用 a.getB().getName(),拦截器 invoke()方法发现 a.getB()是null 值,那么就会单独发送事先保存好的查询关联 B 对象的 sql,把 B 查询上来,然后调用 a.setB(b),于是 a 的对象 b 属性就有值了,接着完成 a.getB().getName() 方法的调用。这就是延迟加载的基本原理。
当然了,不光是 Mybatis,几乎所有的包括 Hibernate,支持延迟加载的原理都 是一样的。
Mybatis 的一级、二级缓存以及缓存失效的情况
1)一级缓存 一级缓存也叫本地缓存: SqlSession 与数据库同一次会话期间查询到的数据会放在本地缓存中。 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;
Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言。所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。
一次会话中有效
为什么要使用一级缓存,不用多说也知道个大概。但是还有几个问题我们要注意一下。 1、一级缓存的生命周期有多长? a、MyBatis在开启一个数据库会话时,会 创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象。Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。 b、如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用。 c、如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用。 d、SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用 2、怎么判断某两次查询是完全相同的查询? mybatis认为,对于两次查询,如果以下条件都完全一样,那么就认为它们是完全相同的两次查询。 2.1 传入的statementId 2.2 查询时要求的结果集中的结果范围 2.3. 这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql() ) 2.4 传递给java.sql.Statement要设置的参数值
缓存失效的情况: 1.查询不同的东西 2.执行CRUD操作(改变原来的数据所以必定会刷新缓存) 3.查询不同的Mapper.xml 4.手动清理缓存 sqlSession.clearCache(); 小结:一级缓存默认是开启的,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段! 一级缓存就是一个Map。
2)二级缓存 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存 基于namespace级别的缓存,一个名称空间,对应一个二级缓存; 工作机制 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中; 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中; 新的会话查询信息,就可以从二级缓存中获取内容; 不同的mapper查出的数据会放在自己对应的缓存(map)中;
MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。 MyBatis的缓存机制整体设计以及二级缓存的工作模式
SqlSessionFactory层面上的二级缓存默认是不开启的,二级缓存的开席需要进行配置,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。 也就是要求实现Serializable接口,配置方法很简单,只需要在映射XML文件配置就可以开启缓存了,如果我们配置了二级缓存就意味着:
- 映射语句文件中的所有select语句将会被缓存。
- 映射语句文件中的所欲insert、update和delete语句会刷新缓存。
- 缓存会使用默认的Least Recently Used(LRU,最近最少使用的)算法来收回。
- 根据时间表,比如No Flush Interval,(CNFI没有刷新间隔),缓存不会以任何时间顺序来刷新。
- 缓存会存储列表集合或对象(无论查询方法返回什么)的1024个引用
- 缓存会被视为是read/write(可读/可写)的缓存,意味着对象检索不是共享的,而且可以安全的被调用者修改,不干扰其他调用者或线程所做的潜在修改。
小结: 只要开启了二级缓存,在同一个Mapper下就有效 所有的数据都会先放在一级缓存中; 只有当会话提交,或者关闭的时候,才会提交到二级缓中!
在一级缓存和二级缓存同时开启时(一级默认开启,二级手动开启),默认先调用二级缓存
什么是 MyBatis 的接口绑定?有哪些实现方式?
接口绑定,就是在 MyBatis 中任意定义接口,然后把接口里面的方法和 SQL 语句绑 定, 我们直接调用接口方法就可以,这样比起原来了 SqlSession 提供的方法我们可 以有更加灵活的选择和设置。 接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加上 @Select、@Update 等注解,里面包含 Sql 语句来绑定;另外一种就是通过 xml 里面写 SQL 来绑定, 在这种情况下,要指定 xml 映射文件里面的 namespace 必须 为接口的全路径名。当 Sql 语句比较简单时候,用注解绑定, 当 SQL 语句比较复杂 时候,用 xml 绑定,一般用 xml 绑定的比较多。
使用 MyBatis 的 mapper 接口调用时有哪些要求?
1、Mapper 接口方法名和 mapper.xml 中定义的每个 sql 的 id 相同; 2、Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的 parameterType 的类型相同; 3、Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的 resultType 的类型相同; 4、Mapper.xml 文件中的 namespace 即是 mapper 接口的类路径。 详情图解:
Mapper 编写有哪几种方式?
第一种:接口实现类继承 SqlSessionDaoSupport:使用此种方法需要编写 mapper 接口,mapper 接口实现类、mapper.xml 文件。 1、在 sqlMapConfig.xml 中配置 mapper.xml 的位置
<mappers>
<mapper resource="mapper.xml 文件的地址" />
<mapper resource="mapper.xml 文件的地址" />
</mappers>
2、定义 mapper 接口 3、实现类集成 SqlSessionDaoSupport mapper 方法中可以 this.getSqlSession()进行数据增删改查。 4、spring 配置
<bean id=" " class="mapper 接口的实现">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
第二种:使用 org.mybatis.spring.mapper.MapperFactoryBean: 1、在 sqlMapConfig.xml 中配置 mapper.xml 的位置,如果 mapper.xml 和 mappre 接口的名称相同且在同一个目录,这里可以不用配置
<mappers>
<mapper resource="mapper.xml 文件的地址" />
<mapper resource="mapper.xml 文件的地址" />
</mappers>
2、定义 mapper 接口: 1、mapper.xml 中的 namespace 为 mapper 接口的地址 2、mapper 接口中的方法名和 mapper.xml 中的定义的 statement 的 id 保持一致 3、Spring 中定义
<bean id="" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="mapper 接口地址" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
第三种:使用 mapper 扫描器: 1、mapper.xml 文件编写: mapper.xml 中的 namespace 为 mapper 接口的地址; mapper 接口中的方法名和 mapper.xml 中的定义的 statement 的 id 保持一致; 如果将 mapper.xml 和 mapper 接口的名称保持一致则不用在 sqlMapConfig.xml 中进行配置。 2、定义 mapper 接口: 注意 mapper.xml 的文件名和 mapper 的接口名称保持一致,且放在同一个目录 3、配置 mapper 扫描器:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="mapper 接口包地址"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
4、使用扫描器后从 spring 容器中获取 mapper 的实现对象。
简述 Mybatis 的插件运行原理,以及如何编写一个插件。
Mybatis 仅可以编写针对 ParameterHandler、ResultSetHandler、 StatementHandler、Executor 这 4 种接口的插件,Mybatis 使用 JDK 的动态代 理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种 接口对象的方法时,就会进入拦截方法,具体就是 InvocationHandler 的 invoke() 方法,当然,只会拦截那些你指定需要拦截的方法。 编写插件:实现 Mybatis 的 Interceptor 接口并复写 intercept()方法,然后在给 插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文 件中配置你编写的插件。
zookeeper
什么是zookeeper ?
ZooKeeper 是一个开放源码的分布式协调服务,它是集群的管理者,监视着集群 中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用 的接口和性能高效、功能稳定的系统提供给用户。 分布式应用程序可以基于 Zookeeper 实现诸如数据发布/订阅、负载均衡、命名 服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。
Zookeeper 保证了如下分布式一致性特性:
1、顺序一致性
2、原子性
3、单一视图
4、可靠性
5、实时性(最终一致性)
客户端的读请求可以被集群中的任意一台机器处理,如果读请求在节点上注册了 监听器,这个监听器也是由所连接的 zookeeper 机器来处理。对于写请求,这些 请求会同时发给其他 zookeeper 机器并且达成一致后,请求才会返回成功。因此, 随着 zookeeper 的集群机器增多,读请求的吞吐会提高但是写请求的吞吐会下降。 有序性是 zookeeper 中非常重要的一个特性,所有的更新都是全局有序的,每个 更新都有一个唯一的时间戳,这个时间戳称为 zxid(Zookeeper Transaction Id)。 而读请求只会相对于更新有序,也就是读请求的返回结果中会带有这个 zookeeper 最新的 zxid。
ZooKeeper 提供了什么?
1、文件系统 2、通知机制
zookeeper 文件系统
Zookeeper 提供一个多层级的节点命名空间(节点称为 znode)。与文件系统不 同的是,这些节点都可以设置关联的数据,而文件系统中只有文件节点可以存放 数据而目录节点不行。 Zookeeper 为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性使得 Zookeeper 不能用于存放大量的数据,每个节点的存放数据上限为 1M。
服务器角色
Leader 1、事务请求的唯一调度和处理者,保证集群事务处理的顺序性 2、集群内部各服务的调度者
Follower 1、处理客户端的非事务请求,转发事务请求给 Leader 服务器 2、参与事务请求 Proposal 的投票 3、参与 Leader 选举投票
Observer 1、3.0 版本以后引入的一个服务器角色,在不影响集群事务处理能力的基础上提 升集群的非事务处理能力 2、处理客户端的非事务请求,转发事务请求给 Leader 服务器 3、不参与任何形式的投票
ZAB 协议?
ZAB 协议是为分布式协调服务 Zookeeper 专门设计的一种支持崩溃恢复的原子广播协议。 ZAB 协议包括两种基本的模式:崩溃恢复和消息广播。
当整个 zookeeper 集群刚刚启动或者 Leader 服务器宕机、重启或者网络故障导 致不存在过半的服务器与 Leader 服务器保持正常通信时,所有进程(服务器)进入崩溃恢复模式,首先选举产生新的 Leader 服务器,然后集群中 Follower(追随者或者说子服务) 服务器开始与新的 Leader 服务器进行数据同步,当集群中超过半数机器与该 Leader服务器完成数据同步之后,退出恢复模式进入消息广播模式,Leader 服务器开始接收客户端的事务请求生成事物提案来进行事务请求处理。
简单比喻总结:zookeeper是以树状结构存在的,在服务过程中如果leader(领导者/父节点)挂掉了,那么整个服务就会进入瘫痪的状态,然后会从其他的follower(追随者/子节点)选举新的leader,同步数据后又可以继续使用了
Zookeeper 下 Server 工作状态
服务器具有四种状态,分别是 LOOKING、FOLLOWING、LEADING、OBSERVING。
1、LOOKING:寻找 Leader 状态。当服务器处于该状态时,它会认为当前集群中没有 Leader,因此需要进入 Leader 选举状态。 2、FOLLOWING:跟随者状态。表明当前服务器角色是 Follower。 3、LEADING:领导者状态。表明当前服务器角色是 Leader。 4、OBSERVING:观察者状态。表明当前服务器角色是 Observer。
数据同步
整个集群完成 Leader 选举之后,Learner(Follower 和 Observer 的统称)回向 Leader 服务器进行注册。当 Learner 服务器想 Leader 服务器完成注册后,进入 数据同步环节。
数据同步流程:(均以消息传递的方式进行)
Learner 向 Learder 注册
数据同步
同步确认
Zookeeper 的数据同步通常分为四类: 1、直接差异化同步(DIFF 同步) 2、先回滚再差异化同步(TRUNC+DIFF 同步) 3、仅回滚同步(TRUNC 同步) 4、全量同步(SNAP 同步)
在进行数据同步前,Leader 服务器会完成数据同步初始化:
peerLastZxid:
- 从 learner 服务器注册时发送的 ACKEPOCH 消息中提取 lastZxid(该Learner 服务器最后处理的 ZXID)
minCommittedLog:
- Leader 服务器 Proposal 缓存队列 committedLog 中最小 ZXID
maxCommittedLog:
- Leader 服务器 Proposal 缓存队列 committedLog 中最大 ZXID
直接差异化同步(DIFF 同步)
- 场景:peerLastZxid 介于 minCommittedLog 和 maxCommittedLog之间先回滚再差异化
同步(TRUNC+DIFF 同步)
- 场景:当新的 Leader 服务器发现某个 Learner 服务器包含了一条自己没有的事务记录,那么就需要让该 Learner 服务器进行事务回滚–回滚到 Leader 服务器上存在的,同时也是最接近于 peerLastZxid 的 ZXID
仅回滚同步(TRUNC 同步)
- 场景:peerLastZxid 大于 maxCommittedLog
全量同步(SNAP 同步)
- 场景一:peerLastZxid 小于 minCommittedLog
- 场景二:Leader 服务器上没有 Proposal 缓存队列且 peerLastZxid 不等于 lastProcessZxid
zookeeper 是如何保证事务的顺序一致性的?
zookeeper 采用了全局递增的事务 Id 来标识,所有的 proposal(提议)都在被 提出的时候加上了 zxid,zxid 实际上是一个 64 位的数字,高 32 位是 epoch(时 期; 纪元; 世; 新时代)用来标识 leader 周期,如果有新的 leader 产生出来,epoch 会自增,低 32 位用来递增计数。当新产生 proposal 的时候,会依据数据库的两 阶段过程,首先会向其他的 server 发出事务执行请求,如果超过半数的机器都能 执行并且能够成功,那么就会开始执行。
四种类型的数据节点 Znode
1、PERSISTENT-持久节点 除非手动删除,否则节点一直存在于 Zookeeper 上
2、EPHEMERAL-临时节点 临时节点的生命周期与客户端会话绑定,一旦客户端会话失效(客户端与 zookeeper 连接断开不一定会话失效),那么这个客户端创建的所有临时节点都 会被移除。
3、PERSISTENT_SEQUENTIAL-持久顺序节点 基本特性同持久节点,只是增加了顺序属性,节点名后边会追加一个由父节点维 护的自增整型数字。
4、EPHEMERAL_SEQUENTIAL-临时顺序节点 基本特性同临时节点,增加了顺序属性,节点名后边会追加一个由父节点维护的 自增整型数字。
Zookeeper Watcher 机制 – 数据变更通知
Zookeeper 允许客户端向服务端的某个 Znode 注册一个 Watcher 监听,当服务 端的一些指定事件触发了这个 Watcher,服务端会向指定客户端发送一个事件通 知来实现分布式的通知功能,然后客户端根据 Watcher 通知状态和事件类型做出 业务上的改变。
工作机制: 1、客户端注册 watcher 2、服务端处理 watcher 3、客户端回调 watcher
Watcher 特性总结: 1、一次性 无论是服务端还是客户端,一旦一个 Watcher 被触发,Zookeeper 都会将其从相 应的存储中移除。这样的设计有效的减轻了服务端的压力,不然对于更新非常频 繁的节点,服务端会不断的向客户端发送事件通知,无论对于网络还是服务端的 压力都非常大。
2、客户端串行执行 客户端 Watcher 回调的过程是一个串行同步的过程。
3、轻量 3.1、Watcher 通知非常简单,只会告诉客户端发生了事件,而不会说明事件的具 体内容。 3.2、客户端向服务端注册 Watcher 的时候,并不会把客户端真实的 Watcher 对 象实体传递到服务端,仅仅是在客户端请求中使用 boolean 类型属性进行了标记。 4、watcher event 异步发送 watcher 的通知事件从 server 发送到 client 是异步 的,这就存在一个问题,不同的客户端和服务器之间通过 socket 进行通信,由于 网络延迟或其他因素导致客户端在不通的时刻监听到事件,由于 Zookeeper 本身 提供了 ordering guarantee,即客户端监听事件后,才会感知它所监视 znode 发生了变化。所以我们使用 Zookeeper 不能期望能够监控到节点每次的变化。 Zookeeper 只能保证最终的一致性,而无法保证强一致性。 5、注册 watcher getData、exists、getChildren 6、触发 watcher create、delete、setData 7、当一个客户端连接到一个新的服务器上时,watch 将会被以任意会话事件触发。 当与一个服务器失去连接的时候,是无法接收到 watch 的。而当 client 重新连接 时,如果需要的话,所有先前注册过的 watch,都会被重新注册。通常这是完全 透明的。只有在一个特殊情况下,watch 可能会丢失:对于一个未创建的 znode 的 exist watch,如果在客户端断开连接期间被创建了,并且随后在客户端连接上 之前又删除了,这种情况下,这个 watch 事件可能会被丢失。
客户端注册 Watcher 实现
1、调用 getData()/getChildren()/exist()三个 API,传入 Watcher 对象 2、标记请求 request,封装 Watcher 到 WatchRegistration 3、封装成 Packet 对象,发服务端发送 request 4、收到服务端响应后,将 Watcher 注册到 ZKWatcherManager 中进行管理 5、请求返回,完成注册。
服务端处理 Watcher 实现
1、服务端接收 Watcher 并存储 接收到客户端请求,处理请求判断是否需要注册 Watcher,需要的话将数据节点 的节点路径和 ServerCnxn(ServerCnxn 代表一个客户端和服务端的连接,实现 了 Watcher 的 process 接口,此时可以看成一个 Watcher 对象)存储在 WatcherManager 的 WatchTable 和 watch2Paths 中去。 2、Watcher 触发 以服务端接收到 setData() 事务请求触发 NodeDataChanged 事件为例: 2.1 封装 WatchedEvent 将通知状态(SyncConnected)、事件类型(NodeDataChanged)以及节点路 径封装成一个 WatchedEvent 对象 2.2 查询 Watcher 从 WatchTable 中根据节点路径查找 Watcher 2.3 没找到;说明没有客户端在该数据节点上注册过 Watcher 2.4 找到;提取并从 WatchTable 和 Watch2Paths 中删除对应 Watcher(从这里 可以看出 Watcher 在服务端是一次性的,触发一次就失效了) 3、调用 process 方法来触发 Watcher 这里 process 主要就是通过 ServerCnxn 对应的 TCP 连接发送 Watcher 事件通知。
客户端回调
客户端 SendThread 线程接收事件通知,交由 EventThread 线程回调 Watcher。 客户端的 Watcher 机制同样是一次性的,一旦被触发后,该 Watcher 就失效了。
ACL 权限控制机制
UGO(User/Group/Others) 目前在 Linux/Unix 文件系统中使用,也是使用最广泛的权限控制方式。是一种粗 粒度的文件系统权限控制模式。
ACL(Access Control List)访问控制列表 包括三个方面: 权限模式(Scheme) 1、IP:从 IP 地址粒度进行权限控制 2、Digest:最常用,用类似于 username:password 的权限标识来进行权限配 置,便于区分不同应用来进行权限控制 3、World:最开放的权限控制方式,是一种特殊的 digest 模式,只有一个权限标 识“world:anyone” 4、Super:超级用户
授权对象 授权对象指的是权限赋予的用户或一个指定实体,例如 IP 地址或是机器灯。
权限 Permission 1、CREATE:数据节点创建权限,允许授权对象在该 Znode 下创建子节点 2、DELETE:子节点删除权限,允许授权对象删除该数据节点的子节点 3、READ:数据节点的读取权限,允许授权对象访问该数据节点并读取其数据内 容或子节点列表等 4、WRITE:数据节点更新权限,允许授权对象对该数据节点进行更新操作 5、ADMIN:数据节点管理权限,允许授权对象对该数据节点进行 ACL 相关设置操作
分布式集群中为什么会有 Master?
在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,其他的机 器可以共享这个结果,这样可以大大减少重复计算,提高性能,于是就需要进行 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 有哪几种几种部署模式?
部署模式:单机模式、伪集群模式、集群模式。
集群最少要几台机器,集群规则是怎样的?
集群规则为 2N+1 台,N>0,即 3 台。
集群支持动态添加机器吗?
其实就是水平扩容了,Zookeeper 在这方面不太好。两种方式: 全部重启:关闭所有 Zookeeper 服务,修改配置之后启动。不影响之前客户端的 会话。 逐个重启:在过半存活即可用的原则下,一台机器重启不影响整个集群对外提供 服务。这是比较常用的方式。 3.5 版本开始支持动态扩容。
Zookeeper 对节点的 watch监听通知是永久的吗?为什么
不是永久的? 不是。官方声明:一个 Watch 事件是一个一次性的触发器,当被设置了 Watch 的数据发生了改变的时候,则服务器将这个改变发送给设置了 Watch 的客户端, 以便通知它们。 为什么不是永久的,举个例子,如果服务端变动频繁,而监听的客户端很多情况 下,每次变动都要通知到所有的客户端,给网络和服务器造成很大压力。 一般是客户端执行 getData(“/节点 A”,true),如果节点 A 发生了变更或删除, 客户端会得到它的 watch 事件,但是在之后节点 A 又发生了变更,而客户端又没 有设置 watch 事件,就不再给客户端发送。 在实际应用中,很多情况下,我们的客户端不需要知道服务端的每一次变动,我 只要最新的数据即可。
Zookeeper 的 java 客户端都有哪些?
java 客户端:zk 自带的 zkclient 及 Apache 开源的 Curator。
zookeeper常用的命令
Is get set create delete……
基于 Zookeeper 的实现方式
? 数据存储:将数据(配置信息)存储到 Zookeeper 上的一个数据节点 ? 数据获取:应用在启动初始化节点从 Zookeeper 数据节点读取数据,并 在该节点上注册一个数据变更 Watcher ? 数据变更:当变更数据时,更新 Zookeeper 对应节点数据,Zookeeper 会将数据变更通知发到各客户端,客户端接到通知后重新读取变更后的数据即 可。
负载均衡
zookeeper 的命名服务
命名服务是指通过指定的名字来获取资源或者服务的地址,利用 zk 创建一个全局的路径,这个路径就可以作为一个名字,指向集群中的集群,提供的服务的地址,或者一个远程的对象等等。
分布式通知和协调
对于系统调度来说:操作人员发送通知实际是通过控制台改变某个节点的状态, 然后 zk 将这些变化发送给注册了这个节点的 watcher 的所有客户端。 对于执行情况汇报:每个工作进程都在某个目录下创建一个临时节点。并携带工 作的进度数据,这样汇总的进程可以监控目录子节点的变化获得工作进度的实时 的全局情况。
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 一样,编号最小的获得锁,用完删除,依次方便。
Zookeeper 队列管理(文件系统、通知机制)
两种类型的队列: 1、同步队列,当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达。 2、队列按照 FIFO 方式进行入队和出队操作。 第一类,在约定目录下创建临时目录节点,监听节点数目是否是我们要求的数目。 第二类,和分布式锁服务中的控制时序场景基本原理一致,入列有编号,出列按 编号。在特定的目录下创建 PERSISTENT_SEQUENTIAL 节点,创建成功时 Watcher 通知等待的队列,队列删除序列号最小的节点用以消费。此场景下 Zookeeper 的 znode 用于消息存储,znode 存储的数据就是消息队列中的消息内 容,SEQUENTIAL 序列号就是消息的编号,按序取出即可。由于创建的节点是持久化的,所以不必担心队列消息的丢失问题。
CAP 原则和ACID原则
CAP是什么?(NoSQL (Redis\MongoDB) ===> CAP)
- C (Consistency) 强一致性
- A (Availability:/??ve?l??b?l?ti/ ) 可用性
- P (Partition tolerance) 分区容错性【必备的】
CAP的三进二: CA、 AP(Eureka — 例如:阿里、京东)、 CP(Zookeeper — )
CAP理论的核心
- 一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求
- 根据CAP原理,将NoSQL数据库分成了满足CA原则,满足CP原则和满足AP原则三大类
- CA:单点集群,满足一致性,可用性的系统,通常可扩展性较差
- CP:满足一致性,分区容错的系统,通常性能不是特别高
- AP:满足可用性,分区容错的系统,通常可能对一致性要求低一些
ACID是什么?(RDBMS (MySQL\Oracle\sqlServer) ===> ACID)
- A (Atomicity) 原子性
- C (Consistency) 一致性
- I (Isolation) 隔离性
- D (Durability) 持久性
zookeeper和dubbo的关系?
原博主:zookeeper和dubbo最本质的区别
Dubbo建议使用Zookeeper作为服务的注册中心。 https://www.cnblogs.com/xiaofei1208/p/7077733.html
-
Zookeeper的作用: zookeeper用来注册服务和进行负载均衡,哪一个服务由哪一个机器来提供必需让调用者知道,简单来说就是ip地址和服务名称的对应关系。当然也可以 通过硬编码的方式把这种对应关系在调用方业务代码中实现,但是如果提供服务的机器挂掉调用者无法知晓,如果不更改代码会继续请求挂掉的机器提供服务。 zookeeper通过心跳机制可以检测挂掉的机器并将挂掉机器的ip和服务对应关系从列表中删除。至于支持高并发,简单来说就是横向扩展,在不更改代码 的情况通过添加机器来提高运算能力。通过添加新的机器向zookeeper注册服务,服务的提供者多了能服务的客户就多了。 -
dubbo: 是管理中间层的工具,在业务层到数据仓库间有非常多服务的接入和服务提供者需要调度,dubbo提供一个框架解决这个问题。 注意这里的dubbo只是一个框架,至于你架子上放什么是完全取决于你的,就像一个汽车骨架,你需要配你的轮子引擎。这个框架中要完成调度必须要有一个分布式的注册中心,储存所有服务的元数据,你可以用zk,也可以用别的,只是大家都用zk。 -
zookeeper和dubbo的关系: Dubbo的将注册中心进行抽象,是得它可以外接不同的存储媒介给注册中心提供服务,有ZooKeeper,Memcached,Redis等。 引入了ZooKeeper作为存储媒介,也就把ZooKeeper的特性引进来。首先是负载均衡,单注册中心的承载能力是有限的,在流量达到一定程度的时 候就需要分流,负载均衡就是为了分流而存在的,一个ZooKeeper群配合相应的Web应用就可以很容易达到负载均衡;资源同步,单单有负载均衡还不 够,节点之间的数据和资源需要同步,ZooKeeper集群就天然具备有这样的功能;命名服务,将树状结构用于维护全局的服务地址列表,服务提供者在启动 的时候,向ZK上的指定节点/dubbo/${serviceName}/providers目录下写入自己的URL地址,这个操作就完成了服务的发布。 其他特性还有Mast选举,分布式锁等。
Zookeeper 和 Eureka的区别
两者区别图解: Zookeeper:保证的是CP(一致性和容错性)。zookeeper是树形结构,结点不是平等的,有leader,一旦出现网络故障,在重选leader的过程整个服务都将瘫痪,这就导致了zookeeper的可用性变低了。 Eureka:保证的是AP(可用性和容错性)。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册时,如果发现连接失败,则会自动切换至其他节点,只要有一台Eureka还在,就能保住注册服务的可用性,只不过查到的信息可能不是最新的,除此之外,Eureka还有之中自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
- Eureka不在从注册列表中移除因为长时间没收到心跳而应该过期的服务
- Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上 (即保证当前节点依然可用)
- 当网络稳定时,当前实例新的注册信息会被同步到其他节点中
因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪
Elasticsearch
说说ES的集群架构,索引数据大小,分片有多少,以及一些调优手段
比如:ES 集群架构 13 个节点,索引根据通道不同共 20+索引,根据日期,每日 递增 20+,索引:10 分片,每日递增 1 亿+数据, 每个通道每天索引大小控制:150GB 之内。
仅索引层面调优手段:
1.1、设计阶段调优
1. 根据业务增量需求,采取基于日期模板创建索引,通过 roll over API 滚动索引;
2. 使用别名进行索引管理;
3. 每天凌晨定时对索引做 force_merge 操作,以释放空间;
4. 采取冷热分离机制,热数据存储到 SSD,提高检索效率;冷数据定期进行 shrink操作,以缩减存储;
5. 采取 curator 进行索引的生命周期管理;
6. 仅针对需要分词的字段,合理的设置分词器;
7. Mapping 阶段充分结合各个字段的属性,是否需要检索、是否需要存储等。……..
1.2、写入调优
1. 写入前副本数设置为 0;
2. 写入前关闭 refresh_interval 设置为-1,禁用刷新机制;
3. 写入过程中:采取 bulk 批量写入;
4. 写入后恢复副本数和刷新间隔;
5. 尽量使用自动生成的 id。
1.3、查询调优
1、禁用 wildcard;
2、禁用批量 terms(成百上千的场景);
3、充分利用倒排索引机制,能 keyword 类型尽量 keyword;
4、数据量大时候,可以先基于时间敲定索引再检索;
5、设置合理的路由机制。
1.4、其他调优
部署调优,业务调优等。
上面的提及一部分,面试者就基本对你之前的实践或者运维经验有所评估了。
elasticsearch 是如何实现master选举的
前置前提: 1、只有候选主节点(master:true)的节点才能成为主节点。 2、最小主节点数(min_master_nodes)的目的是防止脑裂
核心入口为 findMaster,选择主节点成功返回对应 Master,否 则返回 null。选举流程大致描述如下:
第一步:确认候选主节点数达标,elasticsearch.yml 设置的值 discovery.zen.minimum_master_nodes;
第二步:比较:先判定是否具备 master 资格,具备候选主节点资格的优先返回; 若两节点都为候选主节点,则 id 小的值会主节点。注意这里的 id 为 string 类型。 题外话:获取节点 id 的方法。
1 GET /_cat/nodes?v&h=ip,port,heapPercent,heapMax,id,name
2 ip port heapPercent heapMax id name
Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法
1、关闭缓存 swap; 2、堆内存设置为:Min(节点内存/2, 32GB); 3、设置最大文件句柄数; 4、线程池+队列大小根据业务需要做调整; 5、磁盘存储 raid 方式——存储有条件使用 RAID10,增加单节点性能以及避免单 节点存储故障。
Elasticsearch 中的节点(比如共 20 个),其中的 10 个
选了一个 master,另外 10 个选了另一个 master,怎么办? 1、当集群 master 候选数量不小于 3 个时,可以通过设置最少投票通过数量 (discovery.zen.minimum_master_nodes)超过所有候选节点一半以上来解 决脑裂问题; 2、当候选数量为两个时,只能修改为唯一的一个 master 候选,其他作为 data 节点,避免脑裂问题。
详细描述一下 Elasticsearch 更新和删除文档的过程。
1、删除和更新也都是写操作,但是 Elasticsearch 中的文档是不可变的,因此不 能被删除或者改动以展示其变更; 2、磁盘上的每个段都有一个相应的.del 文件。当删除请求发送后,文档并没有真 的被删除,而是在.del 文件中被标记为删除。该文档依然能匹配查询,但是会在 结果中被过滤掉。当段合并时,在.del 文件中被标记为删除的文档将不会被写入 新段。 3、在新的文档被创建时,Elasticsearch 会为该文档指定一个版本号,当执行更新 时,旧版本的文档在.del 文件中被标记为删除,新版本的文档被索引到一个新段。 旧版本的文档依然能匹配查询,但是会在结果中被过滤掉。
详细描述一下 Elasticsearch 搜索的过程。
推荐:详细描述一下 Elasticsearch 搜索的过程
在并发情况下,Elasticsearch 如果保证读写一致?
1、可以通过版本号使用乐观并发控制,以确保新版本不会被旧版本覆盖,由应用
层来处理具体的冲突;
2、另外对于写操作,一致性级别支持 quorum/one/all,默认为 quorum,即只
有当大多数分片可用时才允许写操作。但即使大多数可用,也可能存在因为网络
等原因导致写入副本失败,这样该副本被认为故障,分片将会在一个不同的节点
上重建。
3、对于读操作,可以设置 replication 为 sync(默认),这使得操作在主分片和副
本分片都完成后才会返回;如果设置 replication 为 async 时,也可以通过设置搜
索请求参数_preference 为 primary 来查询主分片,确保文档是最新版本。
Redis
什么是redis?
Redis 是完全开源免费的,遵守 BSD 协议,是一个高性能的 key-value 数库。
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis 支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis 不仅仅支持简单的 key-value 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。
- Redis 支持数据的备份,即 master-slave 模式的数据备份。
Redis 优势 性能极高 – Redis 能读的速度是 110000 次/s,写的速度是 81000 次/s 。 丰富的数据类型 – Redis 支持二进制案例的 Strings, Lists, Hashes, Sets 及Ordered Sets 数据类型操作。 原子 – Redis 的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过 MULTI 和 EXEC指令包起来。 丰富的特性 – Redis 还支持 publish/subscribe, 通知, key 过期等等特性。
Redis 与其他 key-value 存储有什么不同? Redis 有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis 的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。 Redis 运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时 需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点 是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样 Redis 可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加 的方式产生的,因为他们并不需要进行随机访问。
Redis 的数据类型?
Redis 支持五种数据类型:
- string(字符串)
- hash(哈希)
- list(列表)
- set(集合)
- zsetsorted set:(有序集合)。
我们实际项目中比较常用的是 string,hash 如果你是 Redis 中高级用户,还需要加上下面几种数据结构 HyperLogLog、Geo、Pub/Sub。
使用 Redis 有哪些好处?
1、速度快,因为数据存在内存中,类似于 HashMap,HashMap 的优势就是查 找和操作的时间复杂度都是 O1) 2、支持丰富数据类型,支持 string,list,set,Zset,hash 等 3、支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行, 要么全部不执行 4、丰富的特性:可用于缓存,消息,按 key 设置过期时间,过期后将会自动删除
redis 与 memcached 的区别?
什么是Memcached ?
Memcached是一个自由开源的,高性能,分布式内存对象缓存系统。Memcached是一种基于内存的key-value存储,用来存储小块的任意数据(字符串、对象)。这些数据可以是数据库调用、API调用或者是页面渲染的结果。 Memcached简洁而强大。它的简洁设计便于快速开发,减轻开发难度,解决了大数据量缓存的很多问题。它的API兼容大部分流行的开发语言。 本质上,它是一个简洁的key-value存储系统。 一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性。 特征
memcached作为高速运行的分布式缓存服务器,具有以下的特点。
- 协议简单
- 基于libevent的事件处理
- 内置内存存储方式
- memcached不互相通信的分布式
redis 与 memcached 的区别: 1、存储方式 Memecache 把数据全部存在内存之中,断电后会挂掉,数据不能 超过内存大小。 Redis 有部份存在硬盘上,这样能保证数据的持久性。 2、数据支持类型 Memcache 对数据类型支持相对简单。 Redis 有复杂的数据类型。 3、使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。 Redis 直接自己构建了 VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
Redis 相比 Memcached 有哪些优势?
1、Memcached 所有的值均是简单的字符串,redis 作为其替代者,支持更为丰 富的数据类 2、Redis 的速度比 Memcached 快很多 3、Redis 可以持久化其数据(在数据量大又出现宕机时最能体现出来了)
Redis 是单进程单线程的?
Redis 是单进程单线程的,redis 利用队列技术将并发访问变为串行访问,消 除了传统数据库串行控制的开销。
###一个字符串类型的值能存储最大容量是多少? 512M
Redis 的持久化机制是什么?各自的优缺点?
Redis 提供两种持久化机制 RDB 和 AOF 机制: 1、RDB(Redis DataBase)持久化方式: 是指用数据集快照的方式半持久化模式)记录 redis 数据库的所有键值对,在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。
优点:
1、只有一个文件 dump.rdb,方便持久化。
2、容灾性好,一个文件可以保存到安全的磁盘。
3、性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis的高性能)
4.相对于数据集大时,比 AOF 的启动效率更高。
缺点:
数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候)
2、AOF(Append-only file)持久化方式: 是指所有的命令行记录以 redis 命令请求协议的格式完全持久化存储)保存为 aof 文件。
优点:
1、数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次命令操作就记录到 aof 文件中一次。
2、通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof工具解决数据一致性问题。
3、AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的 flushall))
缺点:
1、AOF 文件比 RDB 文件大,且恢复速度慢。
2、数据集大的时候,比 rdb 启动效率低
redis 过期键的删除策略?
1、定时删除:在设置键的过期时间的同时,创建一个定时器 timer). 让定时器在键的过期时间来临时,立即执行对键的删除操作。 2、惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。 3、定期删除:每隔一段时间程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。
为什么 Redis 需要把所有数据放到内存中?
Redis 为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数 据写入磁盘。所以 redis 具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘 I/O 速度为严重影响 redis 的性能。在内存越来越便宜的今天,redis 将会越来越受欢迎。如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。
Redis 的同步机制了解么?
Redis 可以使用主从同步,从从同步。第一次同步时,主节点做一次 bgsave, 并同时将后续修改操作记录到内存 buffer,待完成后将 rdb 文件全量同步到复制 节点,复制节点接受完成后将 rdb 镜像加载到内存。加载完成后,再通知主节点 将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。
是否使用过 Redis 集群,集群的原理是什么?
1)、Redis Sentinal 着眼于高可用,在 master 宕机时会自动将 slave 提升为 master,继续提供服务。 2)、Redis Cluster 着眼于扩展性,在单个 redis 内存不足时,使用 Cluster 进行 分片存储。
Redis 集群方案什么情况下会导致整个集群不可用?
有 A,B,C 三个节点的集群,在没有复制模型的情况下,如果节点 B 失败了, 那么整个集群就会以为缺少 5501-11000 这个范围的槽而不可用。
Redis 支持的 Java 客户端都有哪些?官方推荐用哪个?
Redisson、Jedis、lettuce 等等,官方推荐使用 Redisson。
Jedis 与 Redisson 对比有什么优缺点?
Jedis 是 Redis 的 Java 实现的客户端,其 API 提供了比较全面的 Redis 命令 的支持;Redisson 实现了分布式和可扩展的 Java 数据结构,和 Jedis 相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等 Redis 特性。Redisson 的宗旨是促进使用者对 Redis 的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。
Redis 如何设置密码及验证密码?
设置密码:config set requirepass 123456 授权密码:auth 123456
说说 Redis 哈希槽的概念?
Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有 16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。
Redis 集群的主从复制模型是怎样的?
为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所 以集群使用了主从复制模型,每个节点都会有 N-1 个复制品.
Redis 集群会有写操作丢失吗?为什么?
答:Redis 并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操作。
Redis 集群之间是如何复制的?集群最大节点数是?
异步复制 16384个
Redis 集群如何选择数据库?
Redis 集群目前无法做数据库选择,默认在 0 数据库。
怎么测试 Redis 的连通性?
使用 ping 命令。
怎么理解 Redis 事务?
1)事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。 2)事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
Redis 事务相关的命令有哪几个?
答:MULTI、EXEC、DISCARD、WATCH
Redis key 的过期时间和永久有效分别怎么设置?
EXPIRE【expire:到期,失效】 和 PERSIST 【persist:持续】命令
Redis 如何做内存优化?
尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用 的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比 如你的 web 系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码 ,设置单独的 key,而是应该把这个用户的所有信息存储到一张散列表里面.
Redis 回收进程如何工作的?
一个客户端运行了新的命令,添加了新的数据。Redi 检查内存使用情况,如 果大于 maxmemory 的限制, 则根据设定好的策略进行回收。一个新的命令被执 行,等等。所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地 回收回到边界以下。如果一个命令的结果导致大量内存被使用(例如很大的集合 的交集保存到一个新的键),不用多久内存限制就会被这个内存使用量超越。
都有哪些办法可以降低 Redis 的内存使用情况呢?
如果你使用的是 32 位的 Redis 实例,可以好好利用 Hash,list,sorted set,set 等集合类型数据,因为通常情况下很多小的 Key-Value 可以用更紧凑的方式存放到一起
redis的内存用完了会发生什么?
如果达到设置的上限,Redis 的写命令会返回错误信息(但是读命令还可以正 常返回。)或者你可以将 Redis 当缓存来使用配置淘汰机制,当 Redis 达到内存上限时会冲刷掉旧的内容。
MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 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(驱逐):禁止驱逐数据
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,你可以从这里去查看。
4,排行榜/计数器 Redis 在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis 只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的 10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可: 当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行: ZRANGE user_scores 0 10 WITHSCORES Agora Games 就是一个很好的例子,用 Ruby 实现的,它的排行榜就是使用 Redis 来存储数据的,你可以在这里看到。
5、发布/订阅 最后(但肯定不是最不重要的)是 Redis 的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用 Redis 的发布/订阅功能来建立聊天系统!
假如 Redis 里面有 1 亿个 key,其中有 10w 个 key 是以某个固定的已知的前缀开头的,如何将它们全部找出来?
使用 keys 指令可以扫出指定模式的 key 列表。 弊端:如果这个 redis 正在给线上的业务提供服务,那使用 keys 指令会导致线程阻塞(因为redis是单线程的)。 解决:使用 scan 指令,scan 指令可以无阻塞的提取出指定模式的 key 列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用 keys 指令长。
使用过 Redis 分布式锁么,它是什么回事?
先拿 setnx 来争抢锁,抢到之后,再用 expire 给锁加一个过期时间防止锁忘记了释放。如果在 setnx 之后执行 expire之前进程意外 crash 或者要重启维护了,这个时候可以考虑同时把 setnx 和expire 合成一条指令来用。
|