小杨总结-杭州

1.Springboot自动配置和运行流程

自动配置

@SpringBootApplication = (默认属性)@Configuration + @EnableAutoConfiguration + @ComponentScan

其中 @EnableAutoConfiguration最重要:

​ ①@EnableAutoConfiguration会根据类路径中的jar依赖为项目进行自动配置.

​ ②@EnableAutoConfiguration也是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器.

​ ③从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器.

运行流程

每个SpringBoot程序都有一个主入口,也就是main方法,main里面调用SpringApplication.run()启动整个spring-boot程序,该方法所在类需要使用@SpringBootApplication注解,以及@ImportResource注解(if need),@SpringBootApplication包括三个注解,功能如下:

@EnableAutoConfiguration:SpringBoot根据应用所声明的依赖来对Spring框架进行自动配置。

@SpringBootConfiguration(内部为@Configuration):被标注的类等于在spring的XML配置文件中(applicationContext.xml),装配所有bean事务,提供了一个spring的上下文环境。

@ComponentScan:组件扫描,可自动发现和装配Bean,默认扫描SpringApplication的run方法里的Booter.class所在的包路径下文件,所以最好将该启动类放到根包路径下。

​ 首先进入run方法,run方法中去创建了一个SpringApplication实例,在该构造方法内,我们可以发现其调用了一个初始化的initialize方法,这里主要是为SpringApplication对象赋一些初值。构造函数执行完毕后,我们回到run方法。该方法中实现了如下几个关键步骤:

1.创建了应用的监听器SpringApplicationRunListeners并开始监听

2.加载SpringBoot配置环境(ConfigurableEnvironment),如果是通过web容器发布,会加载StandardEnvironment,其最终也是继承了ConfigurableEnvironment。

简述

Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,通过@Bean导入到Spring容器中,以Properties结尾命名的类是和配置文件进行绑定的。它能通过这些以Properties结尾命名的类中取得在全局配置文件中配置的属性,我们可以通过修改配置文件对应的属性来修改自动配置的默认值,来完成自定义配置

2.Mysql锁的使用和单例模式

(1)表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

(2)行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

(3)页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

仅从锁的角度来说,表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用;而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理系统。

3.es的底层实现

一、ES基于_version进行乐观锁并发控制

post /index/type/id/_update?retry_on_conflict=5&version=6
①内部_version版本号:
第一次创建document的_version版本号为1,以后每次对这个document修改或删除操作,_version自动加1。
同时带上数据的版本号,确保es中数据的版本号,跟客户端中的数据的版本号是相同的,才能修改。
retry_on_conflict,版本冲突时重试次数。
②external version
可以基于你自己维护的一个版本号来进行并发控制。举个列子,加入你的数据在mysql里也有一份,然后你的应用系统本身就维护了一个版本号,无论是什么自己生成的,程序控制的。这个时候,你进行乐观锁并发控制的时候,可能并不是想要用es内部的_version来进行控制,而是用你自己维护的那个version来进行控制。

二、document路由原理

①路由算法:shard = hash(routing) % number_of_primary_shards
②决定一个document在哪个shard上,最重要的一个值就是routing值,默认是_id,也可手动指定,相同的routing值,每次过来,从hash函数中,产出的hash值一定是相同的
例:手动指定一个routing value,比如 put /index/type/id?routing=user_id
③这就是primary shard数量不可变的原因。

三、写一致性原理

put /index/type/id?consistency=quorum
①one:要求我们这个写操作,只要有一个primary shard是active活跃可用的,就可以执行
②all:要求我们这个写操作,必须所有的primary shard和replica shard都是活跃的,才可以执行这个写操作
③quorum(默认):默认的值,要求所有的shard中,必须是大部分的shard都是活跃的,可用的,才可以执行这个写操作(1个节点例外)
算法:number_of_replicas = int((primary + number_of_replicas) / 2 ) + 1,当number_of_replicas>1时才生效
quorum不齐全时,默认等待1分钟,可设置timeout=100ms,timeout=30s,timeout=1m

四、增删改内部原理

①客户端选择一个节点发送请求,这个节点叫coordinating node(协调节点)
②coordinating node,对document进行路由,将请求转发给对应的node(有primary shard)
③实际的node上的primary shard处理请求,然后将数据同步到replica node
④coordinating node,如果发现primary node和所有replica node都完成操作之后,就返回响应结果给客户端

五、document写入机制原理

①数据写入内存buffer缓冲和translog日志文件
②每隔一秒钟,buffer中的数据被写入新的segment file,并进入os cache,此时segment被打开并供search使用
③buffer被清空
④重复1~3,新的segment不断添加,buffer不断被清空,而translog中的数据不断累加
⑤当translog长度达到一定程度的时候,commit操作发生
(5-1)buffer中的所有数据写入一个新的segment,并写入os cache,打开供使用
(5-2)buffer被清空
(5-3)一个commit ponit被写入磁盘,标明了所有的index segment
(5-4)filesystem cache中的所有index segment file缓存数据,被fsync强行刷到磁盘上
(5-5)现有的translog被清空,创建一个新的translog

每秒一个segment file,文件过多,而且每次search都要搜索所有的segment,很耗时
默认会在后台执行segment merge操作,在merge的时候,被标记为deleted的document也会被彻底物理删除
每次merge操作的执行流程
(1)选择一些有相似大小的segment,merge成一个大的segment
(2)将新的segment flush到磁盘上去
(3)写一个新的commit point,包括了新的segment,并且排除旧的那些segment
(4)将新的segment打开供搜索
(5)将旧的segment删除
POST /my_index/_optimize?max_num_segments=1,尽量不要手动执行,让它自动默认执行就可以了

六、实时书写

数据写入os cache,并被打开供搜索的过程,叫做refresh,默认是每隔1秒refresh一次。也就是说,每隔一秒就会将buffer中的数据写入一个新的index segment file,先写入os cache中。所以,es是近实时的,数据写入到可以被搜索,默认是1秒。

七、查询内部原理

①客户端发送请求到任意一个node,成为coordinate node
②coordinate node对document进行路由,将请求转发到对应的node,此时会使用round-robin随机轮询算法,在primary shard以及其所有replica中随机选择一个,让读请求负载均衡
③接收请求的node返回document给coordinate node
④coordinate node返回document给客户端
⑤特殊情况:document如果还在建立索引过程中,可能只有primary shard有,任何一个replica shard都没有,此时可能会导致无法读取到document,但是document完成索引建立之后,primary shard和replica shard就都有了

八、filter执行原理

为每个在倒排索引中搜索到的结果,构建一个bitset,如[0, 0, 0, 1, 0, 1]
遍历每个过滤条件对应的bitset,优先从最稀疏的开始搜索,查找满足所有filter条件的document,直到bitset遍历完
caching bitset,跟踪query,在最近256个query中超过一定次数的过滤条件,缓存其bitset。对于小segment(<1000,或<3%),不缓存bitset。
如果document有新增或修改,那么cached bitset会被自动更新

九、结果跳跃(Bouncing Results)

preference决定了哪些shard会被用来执行搜索操作
两个document排序,field值相同;不同的shard上,可能排序不同;每次请求轮询打到不同的replica shard上;
每次页面上看到的搜索结果的排序都不一样,这就是bouncing result,也就是跳跃的结果。
解决方案就是将preference设置为一个字符串,比如说user_id,让每个user每次搜索的时候,都使用同一个replica shard去执行,就不会看到bouncing results了

4.分布式锁和分布式事物的实际运用

分布式锁的三种实现:

A.基于数据库实现分布式锁

B.基于redis等实现分布式锁

C.基于Zookeeper实现分布式锁

对分布式事务的理解:

本质上来说,分布式事务就是为了保证不同数据库的数据一致性。

事务的ACID特性 原子性 一致性 隔离性 持久性

消息事务+最终一致性

CC提供了一个编程框架,将整个业务逻辑分为三块:Try、Confirm和Cancel三个操作。以在线下单为例,Try阶段会去扣库存,Confirm阶段则是去更新订单状态,如果更新订单失败,则进入Cancel阶段,会去恢复库存。总之,TCC就是通过代码人为实现了两阶段提交,不同的业务场景所写的代码都不一样,复杂度也不一样,因此,这种模式并不能很好地被复用。

5.计算机底层网络协议

01.ARP(地址解析协议)

- 基本功能为透过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的顺利进行。在每台安装有TCP/IP协议的电脑或路由器里都有一个ARP缓存表,表里的IP地址与MAC地址是一对应的。
- 当发送数据时,主机A会在自己的ARP缓存表中寻找是否有目标IP地址。如果找到就知道目标MAC地址为(00-BB-00-62-C2-02),直接把目标MAC地址写入帧里面发送就可;如果在ARP缓存表中没有找到相对应的IP地址,主机A就会在网络上发送一个 广播(ARP request),目标MAC地址是“FF.FF.FF.FF.FF.FF”,这表示向同一网段内的所有主机发出这样的询问:“192.168.38.11的MAC地址是什么?”网络上其他主机并不响应ARP询问,只有主机B接收到这个帧时,才向主机A做出这样的回应(ARP response):“192.168.38.11的MAC地址是(00-BB-00-62-C2-02)”。这样,主机A就知道主机B的MAC地址,它就可以向主机B发送信息。同时它还更新自己的ARP缓存表,下次再向主机B发送信息时,直接从ARP缓存表里查找就可。ARP缓存表采用老化机制,在一段时间内如果表中的某一行没有使用,就会被删除,这样可以大大减少ARP缓存表的长度,加快查询速度。
- 当发送主机和目的主机不在同一个局域网中时,即便知道目的主机的MAC地址,两者也不能直接通信,必须经过路由转发才可以。所以此时,发送主机通过ARP协议获得的将不是目的主机的真实MAC地址,而是一台可以通往局域网外的路由器的MAC地址。于是此后发送主机发往目的主机的所有帧,都将发往该路由器,通过它向外发送。这种情况称为ARP代理(ARP Proxy)。

02.ICMP(互联网控制消息协议)

- 它 用于TCP/IP网络中发送控制消息,提供可能发生在通信环境中的各种问题反馈,通过这些信息,令管理者可以对所发生的问题作出诊断,然后采取适当的措施解决。它与传输协议最大的不同:它一般不用于在两点间传输数据,而常常 用于返回的错误信息或是分析路由
- ICMP控制的内容包括但不仅限于:echo响应(ping)、目标网络不可达、目标端口不可达、禁止访问的网络、拥塞控制、重定向、TTL超时…

03.路由选择协议

- 路由选择协议分为:静态的和动态的。Internet中使用的是动态路由选择协议,在Internet的概念中,将整个互联网划分为许多个小的自治系统(AS)。AS的最主要的特征:一个AS对其他AS表现出的是一个单一 和一致的路由选择策略
- 由于AS的存在,路由选择协议又分为两种:
- 内部网关协议(IGP):即在一个AS内部使用的路由选择协议,而这与互联网中其他AS选用什么路由协议无关。比如:OSPF
- 外部网关协议(EGP):若源主机和目的主机不再同一个AS中,就需要使用一种协议将路由选择信息传递到另一个AS中,这就是EGP。比如:BGP。

04.OSPF(开放式最短路径优先)

- OSPF属于内部网关协议(IGP)的一种,使用Dijkstra提出的最短路径算法
- OSPF提出了“区域(Area)”的概念,一个网络可以由单一区域或者多个区域组成。其中,一个特别的区域被称为骨干区域(Backbone Area),该区域是整个OSPF网络的核心区域,并且所有其他的区域都与之直接连接。所有的内部路由都通过骨干区域传递到其他非骨干区域。所有的区域都必须直接连接到骨干区域,如果不能创建直接连接,那么可以通过虚拟链路(Virtual-link)和骨干区域创建虚拟连接。
- 划分区域的优点:
- 将洪泛法的范围限制在一个区域中。
- 减少每个区域内部路由信息交换的通信量。
- OSPF使用的是分布式链路状态协议,使用 洪泛法向该路由器所有的相邻路由器发送信息。最终整个区域的所有路由器都得到一个这个信息的副本。这个副本就是 链路状态数据库(LSDB)用来保存当前网络拓扑结构,路由器上属于同一区域的链路状态数据库是相同的(属于多个区域的路由器会为每个区域维护一份链路状态数据库)。
- OSPF使用 **“代价(Cost)”**作为路由度量。
- 只有当链路发生变化时才会更新信息。如果同一个目的网络有多条路径,OSPF协议可以进行 负载均衡

05.BGP(边界网关协议)

- 由于BGP是工作在AS之间的协议,并且各个AS的情况复杂,所以 BGP只是力求找到一个可以到达目的网络且比较好的路由,而并不是寻找一条最佳路由。每一个AS都应该有一个**“BGP发言人“,一般来说,两个BGP发言人是通过一个共享网络连接在一起的,BGP发言人往往是BGP边界路由**,但也可以不是。
- 一个BGP发言人与其他AS的BGP发言人要交换路由信息,首先要建立TCP连接,然后在此连接上交换BGP报文以建立BGP会话。当BGP发言人交换了路由信息后,就构造自治系统连通图,最后通过该图来进行路由选择。

06.DHCP(动态主机设置协议)

- DHCP是一个局域网的网络协议,使用UDP协议工作,主要有两个用途:
- 用于内部网络或网络服务供应商自动分配IP地址给用户
- 用于内部网络管理员作为对所有电脑作中央管理的手段
- 动态主机设置协议(DHCP)是一种使网络管理员能够集中管理和自动分配IP网络地址的通信协议。在IP网络中,每个连接Internet的设备都需要分配唯一的IP地址。DHCP使网络管理员能从中心结点监控和分配IP地址。当某台计算机移到网络中的其它位置时,能自动收到新的IP地址。
- DHCP使用了 租约 的概念,或称为计算机IP地址的有效期。租用时间是不定的,主要取决于用户在某地连接Internet需要多久,这对于教育行业和其它用户频繁改变的环境是很实用的。通过较短的租期,DHCP能够在一个计算机比可用IP地址多的环境中动态地重新配置网络。DHCP支持为计算机分配静态地址,如需要永久性IP地址的Web服务器。

07.NAT(地址转换协议)

- NAT是一种 在IP封包通过路由器或防火墙时重写来源IP地址或目的IP地址的技术。这种技术被普遍使用在有多台主机但只通过一个公有IP地址访问因特网的私有网络中。

6.Linux方向代理(nginx)

①反向代理(Reverse Proxy):

方式是指 以代理服务器来接受internet上的连接请求, 然后将请求转发给内部网络上的服务器, 并将从服务器上得到的结果返回给internet上请求连接的客户端, 此时代理服务器对外就表现为一个服务器.

通常的代理服务器, 只用于代理内部网络对Internet的连接请求, 客户机必须指定代理服务器, 并将本来要直接发送到web服务器上的http请求发送到代理服务器中. 当一个代理服务器能够代理外部网络上的主机, 访问内部网络时, 这种代理服务的方式就称为反向代理.

②反向代理服务器工作原理:

反向代理服务器通常有两种模型, 它可以作为内容服务器的替身, 也可以作为内容服务器集群的负载均衡器.

7.redis设置密码

redis没有实现访问控制这个功能,但是它提供了一个轻量级的认证方式,可以编辑redis.conf配置来启用认证。

1、初始化Redis密码:

在配置文件中有个参数: requirepass 这个就是配置redis访问密码的参数;

比如 requirepass test123;

(Ps:需重启Redis才能生效)

redis的查询速度是非常快的,外部用户一秒内可以尝试多大150K个密码;所以密码要尽量长(对于DBA 没有必要必须记住密码);

2、不重启Redis设置密码:

在配置文件中配置requirepass的密码(当redis重启时密码依然有效)。

redis 127.0.0.1:6379> config set requirepass test123

查询密码:

redis 127.0.0.1:6379> config get requirepass
(error) ERR operation not permitted

密码验证:

redis 127.0.0.1:6379> auth test123
OK

再次查询:

redis 127.0.0.1:6379> config get requirepass

  1. “requirepass”
  2. “test123”

PS:如果配置文件中没添加密码 那么redis重启后,密码失效;

3、登陆有密码的Redis:

在登录的时候的时候输入密码:

redis-cli -p 6379 -a test123

先登陆后验证:

redis-cli -p 6379

redis 127.0.0.1:6379> auth test123
OK

AUTH命令跟其他redis命令一样,是没有加密的;阻止不了攻击者在网络上窃取你的密码;

认证层的目标是提供多一层的保护。如果防火墙或者用来保护redis的系统防御外部攻击失败的话,外部用户如果没有通过密码认证还是无法访问redis的。

8.redis之String实现原理

Redis对字符串的处理是通过SDS(Simple Dynamic String)实现的;

SDS:

①常数复杂度获取字符串长度

与C语言不同的是,SDS结构中的属性length记录了SDS本身的长度,所以获取一个SDS长度的复杂度为O(1);Redis获取字符串长度的复杂度由O(N)降为O(1),这确保了字符串长度的获取的工作不会成为Redis的性能瓶颈。

②杜绝缓冲区溢出

与C语言不同的是,SDS空间分配政策完全杜绝了发生缓冲区溢出的可能性:当SDS API需要对字符串进行修改时,首先会检查SDS的空间是否满足修改所需的要求,因为SDS自身有对字符串长度记录的属性length和空闲空间属性free,可以借助这两个参数进行检查。SDS会在执行动作之前判断SDS的空间大小,再去执行操作,如果空间不够的话,SDS API会自动扩展空间。

③减少修改字符串时带来的内存重分配次数

SDS数组中的未使用空间字节数量由SDS的属性free记录,通过free记录,SDS实现了空间预分配和惰性释放两种优化策略。

  1. 空间预分配
      空间预分配用于优化SDS的字符串增长操作:当SDS的API对一个SDS进行修改,并且需要对SDS的空间进行扩展时,程序不仅会为SDS分配修改所需要的空间,而且还会为SDS分配额外的空间。额外的空间分配规则如下:

(1)如果修改SDS之后,SDS的长度小于1MB,那么程序会给SDS分配和length一样大的额外空间,这是SDSlength和free的值相等。举个例子,如果修改后的字符串长度为13k,那么SDS的空间将会占据13+13+1=27k(额外的一个字节用于保存空字符串)。

(2)如果修改SDS之后,SDS的长度大于1MB,那么程序会给SDS分配额外的1MB空间,举个例子,比如修改后的SDS有30MB的大小,那么程序会分配1MB的未使用空间,SDS的buf数组实际大小将是30MB+1MB+1byte。

2.惰性释放

惰性释放用于优化SDS的字符串缩短操作:当SDS的API要缩短SDS保存的字符串时,程序并不需要立即使用内存重分配策略来回收缩短后多出来的字节,而是使用free属性将这些字节记录起来,并等待使用。

④.二进制安全

SDS API都是二进制安全的,所有SDS API都会以处理二进制的方式来处理存放在SDS buf中的数据,数据写什么样,它被读取时就是什么样子。

⑤兼容部分C字符串函数

SDS的API总会以SDS保存的数据的末尾设置为空字符串,并且在分配SDS空间时会多分配一个字节的空间来容纳空字符串,这是为了那些保存的数据可以重用一部分<string.h>库中的函数。

9.redis和hashmap的区别

本质区别我理解是是否可以多个进程间共享。

本地缓存,本地缓存没有成熟的超时机制;其次本地缓存使用的是jvm的内存;各个进程间的缓存不可以共享;这种缓存没有持久化机制,随着服务的重启,缓存所占用的空间会释放掉;

集中式缓存(如redis),他们一般由成熟的expire超时机制;是和业务分离的独立的服务,使用的是redis本进程分配的缓存,不是jvm的缓存;这种缓存也叫分布式缓存,各个进程间可以共享,不需要在各个进程本地都缓存一份,可以保证各个进程间的缓存一致;支持持久化;

另外你可以看下redis的相关技术,比如redis设计与实现。redis支持持久化,有成熟的内存淘汰机制,你可以详细的了解他的高性能、高可用的具体实现。

10.hash的性能优化。hashmap性能优化

hashcode和equals

11.工厂模式里面的普通工厂,和抽象工厂的区别。

创建对象不同
进行创bai建对象时,“工厂模式”不使用new创建对象,而是使用Factory模式;““抽象工厂模式”使用迭代模式来创建对象
定义变量不同
“工厂模式”在使用时可以随时设置变量,不用提前进行设置。“抽象工厂模式则”则需要每次增加产品时,进行修改类方法
接口数量不同
工厂模式”可以使用两个接口以及三个接口,“抽象工厂模式”则可以使用无限个接口。

12.redis安装流程

1.下载tar.gz安装包

2.解压缩tar -zxvf redis-4.0.10.tar.gz

3.安装gcc -yum install -y gcc

4.进入解压缩目录执行:- make MALLOC=libc

5.编译完成执行:- make install PREFIX=/usr/redis

13.hashmap的key有什么要求?可以是什么类型?

从HashMap的语法上来讲,一切对象都可以作为Key值。如:Integer、Long、String、Object等。但是在实际工作中,最常用的使用String作为Key值。

14.token和JWT?JWT为什么要放redis?

①Token

相同: 都是访问资源的令牌, 都可以记录用户信息,都是只有验证成功后

区别:

服务端验证客户端发来的token信息要进行数据的查询操作;JWT验证客户端发来的token信息就不用, 在服务端使用密钥校验就可以,不用数据库的查询。

Token验证流程:

  1. 把用户的用户名和密码发到后端
  2. 后端进行校验,校验成功会生成token, 把token发送给客户端
  3. 客户端自己保存token, 再次请求就要在Http协议的请求头中带着token去访问服务端,和在服务端保存的token信息进行比对校验。

特点:

客户端每次都要携带token, 客户端的内容比较多

②JWT

概念: JSON WEB TOKEN 的简写。可以使用在RESTFUL接口定义, 也可以使用在普通的web

组成:
header、payload、签证

JWT验证流程:

  1. 在头部信息中声明加密算法和常量, 然后把header使用json转化为字符串
  2. 在载荷中声明用户信息,同时还有一些其他的内容;再次使用json 把载荷部分进行转化,转化为字符串
  3. 使用在header中声明的加密算法和每个项目随机生成的secret来进行加密, 把第一步分字符串和第二部分的字符串进行加密, 生成新的字符串。词字符串是独一无二的。
  4. 解密的时候,只要客户端带着JWT来发起请求,服务端就直接使用secret进行解密。

特点:

  1. 三部分组成,每一部分都进行字符串的转化
  2. 解密的时候没有使用数据库,仅仅使用的是secret进行解密。
  3. JWT的secret千万不能泄密!!!
③Token为什么要放在Redis里
首先,引入一个中间件管理token就避免了单点问题,对于分布式系统来说,不管你是哪一台服务处理的用户请求,我都是从redis获取的token。其次,redis的响应速度非常快,如果不出现网络问题,基本上是毫秒级别相应。第三,对于token来说,是有时效性的,redis天然支持设置过期时间以及通过一些二方包提供的API到达自动续时效果。
1、token具有时效性,redis处理有优势。2、在API领域,由于请求数比较多,redis也有优势。3、登录信息一般不需要长效储存,所以可以减少DB的压力,直接用redis.还有其他的看项目情形来定

15.springcloudAlibaba组件

项目搭配SpringCloud Alibaba技术的搭配方案:

描述Spring CloudSpring Cloud Alibaba组合选用
服务发现组件Eureka(停止维护)服务发现组件Nacos 注册中心Spring Cloud Alibaba - Nacos
配置中心组件Spring Cloud Config 配置中心Nacos 配置中心Spring Cloud Alibaba - Nacos
断路保护组件Hystrix 断路保护Sentinel 服务容错Spring Cloud Alibaba - Sentinel
链路追踪组件Sleuth 调用链监控/Spring Cloud - Sleuth
负载均衡组件Ribbon/Spring Cloud - Ribbon
远程调用组件OpenFeign (HTTP+JSON)Dubbo(RPC框架)Spring Cloud - OpenFeign
分布式事务/Seata 分布式事务Spring Cloud Alibaba - Seata
API 网关Gateway/Spring Cloud - Gateway

最后技术选型:

Spring Cloud Alibaba - Nacos 实现注册中心
Spring Cloud Alibaba - Nacos 实现配置中心
Spring Cloud Alibaba - Sentinel  实现服务容错
Spring Cloud Alibaba - Seata 实现分布式事务

Spring Cloud - Ribbon 实现负载均衡
Spring Cloud - Feign 实现远程调用
Spring Cloud - Gateway API网关
Spring Cloud - Sleuth 实现调用链监控

Sentinel

阿里巴巴开源产品,把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

Nacos

阿里巴巴开源产品,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

RocketMQ

Apache RocketMQ™ 基于 Java 的高性能、高吞吐量的分布式消息和流计算平台。

Dubbo

Apache Dubbo™ 是一款高性能 Java RPC 框架。

Seata

阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。

16.OpenFeign实现原理

Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。使用Feign,只需要创建一个接口并注解。它具有可插拔的注解特性(可以使用springmvc的注解),可使用Feign 注解和JAX-RS注解。Feign支持可插拔的编码器和解码器**。Feign默认集成了Ribbon,默认实现了负载均衡的效果**并且springcloud为feign添加了springmvc注解的支持。

17.String源码

18.Hashmap源码

概述

HashMap是基于哈希表(散列表),实现Map接口的双列集合,数据结构是“链表散列”,也就是数组+链表 ,key唯一的value可以重复,允许存储null 键null 值,元素无序。

哈希表

数组:一段连续控件存储数据,指定下标的查找,时间复杂度O(1),通过给定值查找,需要遍历数组,自已对比复杂度为O(n) 二分查找插值查找,复杂度为O(logn)
线性链表:增 删除仅处理结点,时间复杂度O(1)查找需要遍历也就是O(n)
二叉树:对一颗相对平衡的有序二叉树,对其进行插入,查找,删除,平均复杂度O(logn)
哈希表:哈希表中进行添加,删除,查找等操作,性能十分之高,不考虑哈希冲突的情况下,仅需一次定位即可完成,时间复杂度为O(1)哈希表的主干就是数组

hash冲突

如果两个不同的元素,通过哈希函数得出的实际存储地址相同怎么办?也就是说,当我们对某个元素进行哈希运算,得到一个存储地址,然后要进行插入的时候,发现已经被其他元素占用了,其实这就是所谓的哈希冲突,也叫哈希碰撞。前面我们提到过,哈希函数的设计至关重要,好的哈希函数会尽可能地保证 计算简单和散列地址分布均匀,但是,我们需要清楚的是,数组是一块连续的固定长度的内存空间,再好的哈希函数也不能保证得到的存储地址绝对不发生冲突。那么哈希冲突如何解决呢?哈希冲突的解决方案有多种:开放定址法(发生冲突,继续寻找下一块未被占用的存储地址),再散列函数法,链地址法,而HashMap即是采用了链地址法,也就是数组+链表的方式

链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好

底层原理:

HashMap的底层就是一个数组,数组中每一项有事一个链表,当新建一个HashMap时候,就会初始化一个数组,查看源码如下,直接看重点,table = new Entry[capacity]; 创建一个Entry数组,也就是上面的table ,这个Entry结构就是static的包含key value 还有一个next的指针,指向下一个元素的引用,也就构成了链表

HashMap存储

调用put 方法时候,如果key存在key不会覆盖,新的value会替代旧的value,返回旧的value;如果key不存在,该方法返回null

看它的源码,调用put时候,根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置 也就是下标,如果数组在该位置上已有其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的在立案表头,先加入的在尾部

HashMap的读取

get()方法也会是首先计算key的 hashCode 找到数组中对应位置的某一元素,通过key的equals方法在对应位置的链表中找到要的元素,
key(hashcode)–>hash–>indexFor–>最终索引位置,找到对应位置table[i],再查看是否有链表,遍历链表,通过key的equals方法比对查找对应的记录。要注意的是,有人觉得上面在定位到数组位置之后然后遍历链表的时候,e.hash == hash这个判断没必要,仅通过equals判断就可以。其实不然,试想一下,如果传入的key对象重写了equals方法却没有重写hashCode,而恰巧此对象定位到这个数组位置,如果仅仅用equals判断可能是相等的,但其hashCode和当前对象不一致,这种情况,根据Object的hashCode的约定,不能返回当前对象,而应该返回null

Hash算法

hash(int h)方法是根据key的hashCode重新计算一次散列。此算法加入了高位计算,防止低位不变,高位变化时,造成的hash冲突

19.hashmap和hashtable 区别

【1】继承与实现
集合实现了继承了
HashMapMapCloneableSerializableAbstractMap
HashTableDictionary

(1)它们都实现了Map接口,但决定到底要用哪一个,还得从性能、线程安全等方面进行考虑

(2)实现了Cloneable接口,代表它们能够被克隆

(3)实现了Serializable接口,代表它们能够被序列化

【2】线程安全
集合是否线程安全
HashMap不安全
HashTable安全

(1)HashMap是非synchronized,HashTable是synchronized的

(2)单线程情况下,不需要进行同步,此时HashMap的性能要高于HashTable

(3)HashMap是不同步的,但是我们可以使用Collections这个集合操作类来使HashMap保持同步,具体方法是

Map map=Collections.synchronizedMap(new HashMap<>());

(4)在JDK1.5中,新增了ConcurrentHashMap类,是线程安全的HashMap,可以用来替代HashTable,而且扩展性也比HashTable好

【3】迭代器机制
集合迭代器机制
HashMapIteratorfail-fast
HashTableEnumerator非fail-fast

(1)fail-fast ,也称快速失败机制。指的是在迭代器遍历的同时,人为添加了新元素或删除元素导致集合结构不一致,会抛出ConcurrentModificationException异常,但迭代器本身的remove()方法不会出现此异常。

【4】新增元素的要求
集合新增元素的要求
HashMapkey,value都可以为null
HashTablekey,value都不可以为null

(1)HashTable中key和value中任意一个为null,主线程都会抛出NullPointerException

20.二叉树为啥比B+树查询效率高

https://www.cnblogs.com/SmallStrange/p/13403840.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值