1、什么是Spring Boot?
Spring Boot 是Spring开源组织下的子项目,是Spring组件一站式解决方案,主要是简化了使用Spring的难度,简省了繁重的配置,提供了各种启动器,开发者能快速上手。
2、为什么要用Spring Boot?
Spring Boot的优点 (1)独立运行 Spring Boot 而且内嵌了各种servlet容器,Tomcat、Jetty等,现在不再需要打成war包部署到容器中,Spring Boot只要打成一个可执行的jar包就能独立运行,所有的依赖包都在一个jar包内。
(2)简化配置 spring-boot-starter-web启动器自动依赖其他组件,简少了maven的配置。除此之外,还提供了各种启动器,开发者能快速上手。
(3)自动配置 Spring Boot 能根据当前类路径下的类、jar包来自动配置bean,如添加一个spring-boot-starter-web启动器就能拥有web的功能,无需其他配置。
(4)无代码生成和XML配置 Spring Boot配置过程中无代码生成,也无需XML配置文件就能完成所有配置工作,这一切都是借助于条件注解完成的,这也是Spring4.x的核心功能之一。
(5)应用监控 Spring Boot提供一系列端点可以监控服务及应用,做健康检测。
3、Spring Boot的核心配置文件有哪几个?它们的区别是什么?
Spring Boot的核心配置文件是application和bootstrap配置文件。 application 配置文件这个容易理解,主要用于Spring Boot项目的自动化配置。
bootstrap配置文件的特性: (1)boostrap由父ApplicationContext 加载,比applicaton优先加载。 (2)boostrap里面的属性不能被覆盖。
bootstrap配置文件有以下几个应用场景: (1)使用Spring Cloud Config配置中心时,这时需要在bootstrap配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息。 (2)一些固定的不能被覆盖的属性。 (3)一些加密解密的场景。
4、Spring Boot 自动配置原理是什么?
注解@EnableAutoConfiguration,@Configuration,@ConditionalOnClass就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下是否有这个类去自动配置。 @EnableAutoConfiguration是实现自动配置的注解 @Configuration表示这是一个配置文件
参考资料网址:https://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247484365&idx=1&sn=a4ab1d977d6b03bf122b4d596d7ee1ab&scene=21
5、你如何理解Spring Boot中的Starters?
Starters 可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成Spring及其他技术,而不需要到处找示例代码和依赖包。如你想使用Spring JPA访问数据库,只要加入spring-boot-starter-data-jpa启动器依赖就能使用了。 Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。
参考资料网址:https://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247484257&idx=1&sn=f06b553cb8695448f7a7e6d07aacae70&scene=21#wechat_redirect
6、如何在Spring Boot启动的时候运行一些特定的代码?
可以实现接口ApplicationRunner 或者CommandLineRunner,这两个接口实现方式一样,它们都只提供了一个run方法。
参考资料网址:
https://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247484366&idx=1&sn=7dc94038861fe9e10cdf132ffc83092f&scene=21#wechat_redirect
7、Spring Boot 有哪几种读取配置的方式?
Spring Boot可以通过@PropertySource,@Value,@Environment, @ConfigurationProperties 来绑定变量。
参考资料网址:https://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247484575&idx=1&sn=56c88cd7283374345d891e85a800539b&scene=21#wechat_redirect
8、Spring Boot 支持哪些日志框架?推荐和默认的日志框架是哪个?
Spring Boot 支持Java Util Logging,Log4j2,Lockback作为日志框架,如果使用Starters 启动器,Spring Boot 将使用Logback作为默认日志框架。
参考资料网址: https://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247484653&idx=1&sn=8a71809471fe69b1fc3b8dec44ed1498&scene=21#wechat_redirect
9、SpringBoot 实现热部署有哪几种方式?
主要有两种方式: (1)Spring Loaded (2)Spring-boot-devtools
Spring-boot-devtools 使用方式参考资料网址: https://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247484791&idx=1&sn=ee172b4fdd6253720807c84d4425a8ee&scene=21#wechat_redirect
10、Eureka和zookeeper的区别
著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性)、A(可用性)和P(分区容错性)。由于分区容错性在是分布式系统中必须要保证的,因此我们只能在A和C之间进行权衡。在此Zookeeper保证的是CP,而Eureka则是AP。
(1)Zookeeper 保证CP 当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是Zookeeper会出现一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题是选举leader的时间太长,大约是30~120s,且选举期间整个Zookeeper集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得Zookeeper集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。
(2)Eureka保证AP Eureka设计时优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况: (1)Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。 (2)Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)。 (3)当网络稳定时,当前实例新的注册信息会被同步到其它节点中。 因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像 zookeeper 那样使整个注册服务瘫痪。
(3)总结 Eureka作为单纯的服务注册中心来说要比zookeeper更加“专业”,因为注册服务更重要的是可用性,我们可以接受短期内达不到一致性的状况。不过Eureka目前1.X版本的实现是基于servlet的java web应用,它的极限性能肯定会受到影响。期待正在开发之中的2.X版本能够从servlet中独立出来成为单独可部署执行的服务。
11、Redis 提供了哪几种持久化方式?
RDB持久化方式能够在指定的时间间隔能对数据进行快照存储。 AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。 如果只希望数据在服务器运行的时候存在,也可以不使用任何持久化方式。 可以同时开启两种持久化方式,在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
(1)RDB持久化 每隔一段时间,将内存中的数据集写到磁盘。 Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。 保存策略: save 900 1 900秒内如果至少有1个key的值变化,则保存。 save 300 10 300秒内如果至少有10个key的值变化,则保存。 save 60 10000 60秒内如果至10000个key的值变化,则保存。
(2)AOF 持久化 以日志形式记录每个更新操作。 Redis 重新启动时读取这个文件,重新执行新建、修改数据的命令恢复数据。
保存策略: appendfsync always: 每次产生一条新的修改数据的命令都执行保存操作;效率低,但是安全!
appendfsync everysec: 每秒执行一次保存操作。如果在未保存当前秒内操作时发生了断电,仍然会导致一部分数据丢失(即1秒钟的数据)。
appendfsync no: 从不保存,将数据交给操作系统来处理。更快,也更不安全的选择。推荐(并且也是默认)的措施为每秒fsync一次,这种fsync策略可以兼顾速度和安全性。
缺点: 1)比起RDB占用更多的磁盘空间。 2)恢复备份速度要慢。 3)每次读写都同步的话,有一定的性能压力。 4)存在个别Bug,造成恢复失败。
(3)选择策略 可读的日志文本,通过操作AOF。 官方推荐: 如果对数据不敏感,可以选单独用RDB;不建议单独用AOF,因为可能出现Bug;如果只是做纯内存缓存,可以都不用。
12、redis是单线程的,为什么那么快?
1)完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)。 2)数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的。 3)采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。 4)使用多路I/O复用模型,非阻塞IO。 5)使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VW机制,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
13、一个Redis 实例最多能存放多少的keys?List、Set、Sorted Set他们最多能存放多少元素?
理论上Redis可以处理多达2的32次方个keys,每个实例至少存放了2亿5千万的keys。
任何list、set、和sorted set都可以放2的32次方个元素。Redis的存储极限是系统中的可用内存值。
14、Redis常见性能问题和解决方案
(1)Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件。 (2)如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次。 (3)为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内。 (4)尽量避免在压力很大的主库上增加从库。
(5)主从复制不要用图状结构,用单向链表结构更为稳定,即:Master<-Slave1<-Slave2<-Slave3..… 这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。
15、Redis 相比memcached 有哪些优势?
(1)memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型。 (2)redis的速度比memcached快很多。 (3)redis 可以持久化其数据。
16、Redis 的数据淘汰策略
(1)noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)。 (2)alkeys-lru:尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。 (3)allkeys-random:回收随机的键使得新添加的数据有空间存放。 (4)volatile-random:回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。 (5)volatile-ttl:回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。 (6)volatile-lru:尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。
17、Redis哈希槽
Redis 集群没有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。
18、Redis 集群方案应该怎么做?都有哪些方案?
(1)twemproxy,大概概念是,它类似于一个代理方式,使用方法和普通redis无任何区别,设置好它下属的多个redis实例后,使用时在本需要连接redis的地方改为连接twemproxy,它会以一个代理的身份接收请求并使用一致性hash算法,将请求转接到具体redis,将结果再返回twemproxy。使用方式简便(相对redis只需修改连接端口),对旧项目扩展的首选。问题:twemproxy自身单端口实例的压力,使用一致性hash后,对redis节点数量改变时候的计算值的改变,数据无法自动移动到新的节点。 (2)codis,目前用的最多的集群方案,基本和twemproxy一致的效果,但它支持在节点数量改变情况下,旧节点数据可恢复到新hash节点。 (3)redis cluster3.0自带的集群,特点在于他的分布式算法不是一致性hash,而是hash槽的概念,以及自身支持节点设置从节点。具体看官方文档介绍。 (4)在业务代码层实现,起几个毫无关联的redis实例,在代码层,对key进行hash计算,然后去对应的redis实例操作数据。这种方式对hash层代码要求比较高,考虑部分包括,节点失效后的替代算法方案,数据震荡后的自动脚本恢复,实例的监控,等等。
19、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的发布/订阅功能来建立聊天系统。
20、ActiveMQ如果消息发送失败怎么办?
Activemq 有两种通信方式,点到点形式和发布订阅模式。 (1)点到点模式 如果消息发送不成功此消息默认会保存到activemq服务端直到有消费者将其消费,所以此时消息是不会丢失的。 (2)发布订阅模式 默认情况下只通知一次,如果接收不到此消息就没有了。这种场景只适用于对消息送达率要求不高的情况。如果要求消息必须送达不可以丢失的话,需要配置持久订阅。每个订阅端定义一个id,在订阅是向activemq注册。发布消息和接收消息时需要配置发送模式为持久化。此时如果客户端接收不到消息,消息会持久化到服务端,直到客户端正常接收后为止。
21、如何使用ActiveMQ解决分布式事务?
在互联网应用中,基本都会有用户注册的功能。在注册的同时,我们会做出如下操作: 收集用户录入信息,保存到数据库向用户的手机或邮箱发送验证码等等… 如果是传统的集中式架构,实现这个功能非常简单:开启一个本地事务,往本地数据库中插入一条用户数据,发送验证码,提交事物。 但是在分布式架构中,用户和发送验证码是两个独立的服务,它们都有各自的数据库,那么就不能通过本地事物保证操作的原子性。这时我们就需要用到ActiveMQ(消息队列)来为我们实现这个需求。 在用户进行注册操作的时候,我们为该操作创建一条消息,当用户信息保存成功时,把这条消息发送到消息队列。 验证码系统会监听消息,一旦接受到消息,就会给该用户发送验证码。
22、如何防止ActiveMQ消息重复发送?
解决方法很简单:增加消息状态表。通俗来说就是一个账本,用来记录消息的处理状态,每次处理消息之前,都去状态表中查询一次,如果已经有相同的消息存在,那么不处理,可以防止重复发送。