中间件
redis是什么
redis是一个非关系型数据库,以KV结构存储数据,提供了多种数据类型和各自的本地方法,单线程处理数据本地方法,基于内存存储,吞吐量大,集群部署高可用,基于redis这些特性我们很简单的可以实现一些功能,比如订阅发布、排行榜、计数器等。
redis和memcache区别
redis单线程,多种数据类型,丰富的本地方法,有持久化;支持cluster分布式;
memecache多线程,只有String,只有getset,无持久化;客户端分布式;memcache使用固定大小的内存块存储数据,内存利用率低
redis的性能(有品1)
redis单机性能能达到10w吞吐,单机开启6.0提供的IO线程峰值可以达到15w
redis为什么是单线程的还可以这么快(有品1)
IO多路复用监听多个socket事件,等数据读取完毕进入核心线程执行;基于内存,没有磁盘寻址耗时;核心线程只做计算,充分利用CPU;单线程没有线程切换消耗;单线程天生线程安全,不需要加锁;加上本地数据结构的优化
redis数据类型和使用场景
string 字符串、整数、浮点数;二进制安全;最大值512m;缓存、计数器
list 列表;队列、
set 无序不重复列表;点赞列表
sortset 有序不重复列表;排行榜
hash 包含键值对的散列表;最大长度为2^32 -1 ;适合存储对象,对某一属性单独操作
bit 位图;布隆过滤器
hyperloglogs 基数统计;
redis底层数据结构
sds 字符串存储;扩容最大1m,小于1m时double;c语法string以空座位结束;len、free、buf[];惰性释放,使用free记录
dict 字典;包含两个hash表,方便rehash,扩容时,将其中一个hash表rehash到另一个表中,交换两表身份;渐进式rehash
ziplist 压缩列表;节省内存;
quicklist 每个quicklist节点就是一个ziplist,具备压缩列表的特性;list的实现,双端操作o(1)
skiplist 跳跃表,每个节点有指向更远节点的指针,从空间上看好像跳跃一下,
intset 整数set
ziplist
包含的元素较少、并且每个元素要么是小整数要么是长度较小的字符串时,redis将会用ziplist作为hash、zset键的底层实现
ziplist是由一系列特殊编码的连续内存块组成的顺序存储结构,双向链表,类似于数组,ziplist在内存中是连续存储的,为了节省内存 每个元素所占的内存大小可以不同,每个节点可以用来存储一个整数或者一个字符串
prevlength(可变长)、encoding(数字8位,字符串8、20、40)、data;
特殊编码,int不再是固定32位,大数就用更长的位数存,小数就用短的位数存
插入数据,需要计算插入地址,ziplist扩容后长度,插入位置之后的数据要整体向后移,可能会产生数据拷贝
超过512个节点 有大于64字节的节点,hash回有ziplist切换为hashtable
redis哨兵模式(有品1)
redis哨兵不处理消息,监控master的健康状态,主观下线、客观下线,选举新master;本身也可以集群部署,高可用
redis cluster(有品1)
redis服务端提供的分布式功能;hash槽,16384槽位;每个服务负责一部分槽位,互为主从;客户端连接一个服务就可以;可以使用哨兵;增删节点需要运维参与,移动槽位;
redis的RDB
save和bgsave命令,创建实时内存快照,save是同步阻塞创建,bgsave是fork一个子进程进行快照,快照过程中主进程使用copyOnWrite方式继续工作;
IO占用CUP;无法记录实时数据;服务宕机,数据存在丢失部分风险;save(m,n) ,每m条或ns执行一次RDB
redis的AOF
向日志文件里拼接执行命令,每执行同步,自动同步;数据全;rewrite压缩文件;文件太大
redis主从同步
增量复制
主库维护缓存列表,主从维护offset,当从库的offset在主库范围内,执行增量复制,直接读取缓存列表中的执行记录
全量复制
刚上线、失联之后offset不再主库buff范围的从库需要执行全量复制
redis生成一个RDB文件发送给从服务,从服务使用RDB恢复数据;IO问题
redis分布式锁实现(有品1)
利用setNx+setEx或者set(k,v,nx,px)方法的原子性,想某key写入一个线程ID,删除时先判断线程ID,lua脚本原子操作,防止错误删除;本地使用cnt记录重入次数;key设置过期时间防止死锁;redisson看门狗解决续期;集群问题,redLock解决
redisson看门狗定时器,10s续期一次
redlock 按顺序向集群每个节点请求一个锁,根据一定超时时间判断是否跳过,超过一半的节点加锁成功就返回
redis6.0做了什么(有品1)
增加IO线程,IO线程处理多路复用之后接收到文件准备好的消息(网卡->内核socket缓冲),读取数据的操作(内核socket缓存->用户内存)
redis事务
一个事务包含了多个命令,原子操作
事务中的多个命令被一次性发送给服务器,这种方式被称为流水线,减少网络通信次数,提升性能
只校验语法,如果失败是不会回滚的,
MULTI 和 EXEC 命令将事务操作包围起来
redisKey淘汰策略
先进先出
LRU 最长时间未使用
LFU 单位时间内最少使用
随机
redisKey的过期
定时过期(时间事件,设置了过期时间的key的列表中拿一部分,过期一部分)+取时过期(拿到数据,发现过期了,执行过期操作)
什么是zookeeper
分布式协同框架,为分布式项目提供一致性服务。内存读写,强一致性,事件通知,高可用,leader和follower;
zab协议
1.消息同步 先发消息,等待大多数follower反馈之后,再发一条commit
2.选举 集群启动时、leader宕机时
zk的数据结构
zk是一个树状的存储结构,以文件路径的方式访问对应节点,
每一个节点既是一个文件也是一个文件夹,节点路径是唯一的,可以用做命名服务
节点的数据结构是Znode,
维护数据、权限(ACL)、名称、stat(dataVersion每次修改节点数都会++,cversion子节点发生变化++,aclVersion发生变化++)、cZxid创建事物ID、mZxid修改事物ID、时间戳
zk的节点类型
永久节点 需要主动删除
临时节点 创建的节点的session失效就会删除
无序节点
有序节点 在同一个父节点下有序,在name后面拼上顺序ID
zk的事件通知机制
zk提供节点的增删改和子节点的增删改事件通知;
客户端和服务端都维护一个事件监听列表,客户端添加监听之后进入本地列表,并同步到服务端,服务端事件触发后通知到客户端,客户端根据消息内的path去拉取数据,
这个监听是一次性的,如果持续监听,需要在此添加
zk实例的三种状态
Looking 刚加入集群
Leading leader状态
Flowing flowing状态
zk实例的三种身份
Observer 只同步数据,不参与选举,扩展集群读操作的性能而不影响写
leader 负责数据读写,同步
flower 负责读请求,写请求转发给leader
zk的Zxid
Zxid是zk提供的事务ID,是一个64位的数字,高32位代表leader周期,低32位为自增序列;事务ID每次同步都会发送给follower
zk的MyId
zk每台实例应当配置一个唯一的ID
zk选举过程
网状投票,投票原则,投给zxid更大的,如果zxid一样投给myid更大的;当一台服务获取到半数以上的节点投票,自动成为leader
启动阶段:假设3台实例的集群
1.实例1加入集群,发现只有自己,投票给自己,没有达到半数
2.实例2加入集群,投票给自己,实例1接到2的选票,发现2的myid大一些,更改选票发给2,2接收选票发现达到半数以上,成为leader
3.实例3加入集群,发现已经有leader,自动成为follower
崩溃恢复阶段:假设3台
1.所有人投票给自己并发送给其他所有实例
2.接到别人选表之后对比zxid和myid,根据规则更改选票发出去
3.有一台达到半数成为leader
zk脑裂问题
脑裂问题发生在leader宕机重新选举之后,宕机的旧leader又加入集群,这样集群就存在了两个leader;
新leader会头部消息给旧leader,旧l拿到zxid发现高32位的l周期已经增加,自己就成就followe
zk的session机制
客户端启动之后会与zk维护一条长链接,zk会为这个客户端创建一个session并分配一个sessionId,session有过期时间,每次主动通讯,或者心跳都会给session续期;
心跳中断后,zk会尝试重新发起连接,如果成功,保持session,如果失败,session失效
zk的分布式锁实现
先创建一个永久锁节点,尝试在这个锁节点下创建有序临时节点,排在第一位的节点获得锁,
后面的节点分别监听它之前的一个节点,
锁释放之后,删除临时节点,第二顺位的会接到通知,获取锁
临时节点特性防死锁
可重入可以在线程内部或者临时节点维护重入次数
zk分布式锁可以规避惊群效应
kafka是什么
高性能的分布式消息队列,百万吞吐;不支持延迟队列;多用于日志收集等海量数据场景;磁盘读写,持久化;由Scala和Java编写
kafka的性能(有品1)
百万吞吐;磁盘顺序读写接近内存;pagecache;零拷贝;批量读;IO压缩传输;分区分段+索引
pagecache页存 Pagecache是通过将磁盘中的数据缓存到内存中,从而减少磁盘I/O操作;pagecache中的数据更改时能够被同步到磁盘上,page回写;pagecache刷盘sync fsync 内存少,达到时间
零拷贝 文件->内核->用户内存->内核soket缓冲区->网卡 四次copy,硬件->内核是有CMD完成;CMD提供了文件->网卡操作
kafka架构
逻辑架构
broker 服务器
topic 主题,可以认为是一个队列
partition 分区,每一个topic可以分为多个partition,分区是为了提升性能;每个broker会有多个partition,互为主备;
producter 生产者 生产消息
consumer 消费者 消费消息;一个partition同时只能被同一个消费者组里的一个消费者消费
consumegroup 消费者组,同一个消费者组只能消费1次;实现多次消费,用消费者组
物理架构
segment文件 每一个partition使用多个segment文件存储,通过索引文件定位消息在哪个segement中;分段存储是为了防止文件过大,
.log文件 .index文件
kafka主从
kafka主从是为了容灾和提升服务高可用,每个broker里的有多个partition,多个partition可以互为主备,与主完全同步的备进入ISR列表
kafka的rebalance
rebalance指,partition和consumer的重新匹配,这个过程kafka是不处理任何消息的;
主要发生在,topic数量发生变化,partition数量发生变化,consumer数量发生变化,当前连接的consumer消费超时或者挂了
通过Coordinator(每个broker都会启动一个Coordinator服务,存储group的offset等信息,0.9之前是zk)协调,选出group中一个consumer作为leader,进行partition分配
kafka的瓶颈
当topic数量过多的时候,由于kafka的partition的segment存储方式,会产生更多的文件,顺序读写退化为随机读写
kafka如何保证顺序
每个partition顺序写,每个partition同时只能被被同一个消费者组里的一个消费者消费,保证消费顺序
kafka如何保证消息可靠(qzwl1)
生产消息时可以选择ack模式,默认异步,ack.all 同步所有ISR列表内的备份;
kafka落盘,先写入pagecache 服务器宕机可能丢失,实时刷盘
消费时,可选自动提交和主动提交,在提交offset之后,才认为消息被消费;自动提交有丢消息的风险,主动提交有重复消费风险
kafka事务
kafka从0.11开始支持事务;原子写入多条消息;
kafka的分区同步机制
每个patition有几个关键的offset ,只同步ISR(Inof-Sync Replicas)列表分区,leader负责维护和跟踪ISR
LogEndOffset 下一个分配的偏移量
HighWartermark 消费者最高水位线 新消息提交leader后同步所有follower,之后更新HW,此消息才可以被消费
FirstMessageOffset
rabbitmq
erlang开发消息队列,开源,跨语言跨平台,可靠消息传输
rabbitmq架构
Broker:实例,它提供一种传输服务,它的角色就是维护一条从生产者到消费者的路线,保证数据能按照指定的方式进行传输,
Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
Queue:消息的载体,每个消息都会被投到一个或多个队列。
Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来.
Routing Key:路由关键字,exchange根据这个关键字进行判断消息投递哪些queue
vhost:虚拟主机,一个broker里可以有多个vhost,用作不同用户的权限分离。
Producer:消息生产者,就是投递消息的程序,面向交换机
Consumer:消息消费者,就是接受消息的程序.,面向队列
Channel:消息通道,在客户端的每个连接里,可建立多个channel,通过一个链接可以并发发送消息和接收消息
rabbitmq交换机类型
扇形交换机 路由到所有绑定的queue上
DIRECT交换机 投递到所有routekey相等的queue上
Topic交换机 投递到所有routekey匹配的queue上,这里指的匹配是利用通配符,topic的routekey是一种以.分隔的字符串,每分隔的一段都可以用作匹配,比如..red.*会比配所有第三段为red的消息
HEADERS交换机 消息头订阅,消息发布前,为消息定义一个或多个键值对的消息头,然后消费者接收消息同时需要定义类似的键值对请求头:(如:x-mactch=all或者x_match=any),只有请求头与消息头匹配,才能接收消息,忽略RoutingKey.
rabbitmq怎么生产消息
生产者面向交换机
channel.basicPublish(excange_name,route_key,false,bs,"test".getBytes());
rabbitmq怎么消费消息
消费者面向的是queue,消费相同routekey、queue的会做均衡,消费相同routekey和不同queue的消费做会做复制
channel.basicConsume(QUEUE_AUTODELETE, AutoAck, consumer)
消息确认,ack,
rabbitmq事务
事务的实现主要是对信道(Channel)的设置,
只有在autoAck=false时生效
rabbitmq的AMQP
高级消息队列协议
在 AMQP 模型中,消息的 producer 将 Message 发送给 Exchange,Exchange 负责交换 / 路由,将消息正确地转发给相应的 Queue。消息的 Consumer 从 Queue 中读取消息。
rabbitmq集群高可用
单一模式 一台实例
普通模式 每台实例有相同的元数据、队列结构,数据只存在一个实例上,消费时,去数据存储的实例取出
镜像模式 每台实例可以维护其他队列的镜像,消费时,直接从镜像发送,需要做节点的同步
rabbit死信队列
长时间没有被消费或者消费失败的消息,会进入死信队列,死信队列也是一个队列,死信队列中的消息也可以被消费
直接订阅某个队列的死信队列,设置队列超时时间,来实现延时队列;
先声明一个交换机和一个队列,将这个队列关联一个私信交换机,声明这个私信交换机,声明死信队列,将死信队列绑定私信交换机;
消息超时或消费失败,会由队列进入私信交换机,由私信交换机进入死信队列
rabbitmq的消息持久化
持久化队列需要声明durable=True
rabbitmq消息可靠性
- 开启事物
- 开启confirm 基于回调的消息确认
- 开启持久化 开启镜像模式
- 关闭自动ack
消息重试机制,默认三次
rabbitmq的镜像模式
rabbitmq部署有三种方式,单机部署、普通集群部署、镜像集群部署
每个队列都有对应的镜像队列作为备份,每个broker会启动一个GM服务,GM服务起到协调作用,所有GM组成GMgroup环形链表,由master通知next,直到leader收到通知同步结束
master宕机之后存在时间最长的slave升级成master
activemq rabbtimq rocketmq kafka的区别
activemq jms规范;支持事物、xa协议;社区较少
rabbitmq erlang开发,对java二次开发不友好;跨语言、跨平台;社区文档有优势;需要学习amqp协议
rocketmq java开发;参考kafka设计,优化kafka瓶颈,吞吐量高
kafka java开发;吞吐量高,高可用,技术成熟,单机超过64分区有性能问题,没有延迟队列
zeromq 无持久化,数据协议要自己定义,更像是一个通讯框架;快
rocketmq架构
逻辑架构
nameserver 负责broker注册与发现,存储broker元数据,心跳,路由;集群部署
broker 服务器
topic 主题,可以认为是一个队列
queue 队列,topic的分片,每一个topic可以分为多个partition,分区是为了提升性能;每个broker会有多个partition,互为主备;
producter 生产者 生产消息
consumer 消费者 消费消息;一个partition同时只能被同一个消费者组里的一个消费者消费
consumegroup 消费者组,同一个消费者组只能消费1次;实现多次消费,用消费者组
物理架构
commitLog message持久化的文件
rocketmq延时消息原理
只支持固定的几种延时时间
原理就是,延时消息先进入固定时间的延时队列,到时间后,放到真实队列下
rocketmq优化了哪些功能
1.通过commitLog解决了kafka顺序读写退化问题
2.优化重试机制,消费失败链接超时自动切换broker
网关是做什么的
网关是一个Api服务器,是系统的唯一入口。网关的最重要的职责就是路由转发。鉴权,日志,静态资源响应等。
与Nginx的区别是,nginx只能做路由转发,处理静态资源,无法扩展一些公共业务功能。
可以用nginx对网关服务做代理,网关服务对业务服务做代理。
gateway 和 netflix zuul
gateway原理
gateway使用netty作为通讯框架,
三大组件:
路由 一个ID、一个uri、一组断言、一组过滤器组成
断言 用来匹配http中的请求符合那个uri
过滤器 对请求和响应做处理
什么是eureka
eureka是一个注册中心,是spring cloud中的一个组件,用于服务的注册与发现。
eureka server 注册中心
service provider 服务提供方,将服务注册到注册中心
service consumer 服务消费方,从注册中心获取服务列表
zk是CP,eureka是AP保证eurekaserver的高可用性,允许一定的数据不一致
什么是nacos
nacos是alibaba开源的 配置中心和注册中心
两种模式支持ap或者cp;
eurake nacos zk的区别
eurake ap;http
nacos ap/cp;http
zk cp;tcp
Hystrix原理
限流
1.线程池
2.令牌桶
熔断,基于catch异常
sentinel原理
sentinel通过控制资源并发线程数来进行限流;
资源是sentinel中的抽象概念,一个方法,一个uri都可以被定义为一个资源;
通过对资源配置规则,进行限制
通过响应时间对资源进行降级,当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。
dubbo架构
registry 注册中心 模式zk实现;服务注册与发现;
provider 服务提供者,发布服务到注册中心
consumer 服务消费方,从服务中心获取已经注册的服务列表
container 服务容器 tomcat等
monitor dubbo监控中心,做一些服务监控,统计功能
dubbo支持哪些协议
dubbo 缺省协议 采用单一长连接和NIO异步通讯 适合于小数据量大并发的服务调用 以及服务消费者机器数远大于服务提供者机器数的情况;hessian二进制序列化;mina通讯
rmi 采用JDK标准的 阻塞式短连接和JDK标准序列化
hessian 用于集成 Hessian 的服务,Hessian 底层采用 Http 通讯,采用 Servlet 暴露服务,Dubbo 缺省内嵌 Jetty 作为服务器实现
http 多连接;短链接;json序列化;http传输
webservice 基于 WebService 的远程调用协议;http;多连接;短链接;SOAP文本序列化
thrift
memcached 基于 memcached实现的 RPC 协议
redis 基于 Redis实现的 RPC 协议
rest 基于标准的Java REST API
dubbo协议优缺点
采用单一长连接和NIO异步通讯 适合于小数据量大并发的服务调用 以及服务消费者机器数远大于服务提供者机器数的情况;hessian二进制序列化;mina通讯
不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低
dubbo协议为什么不能传大包
因dubbo协议采用单一长连接,如果每次请求的数据包大小为500KByte,假设网络为千兆网卡(1024Mbit=128MByte),每条连接最大7MByte(不同的环境可能不一样,供参考),单个服务提供者的TPS(每秒处理事务数)最大为:128MByte / 500KByte = 262。单个消费者调用单个服务提供者的TPS(每秒处理事务数)最大为:7MByte / 500KByte = 14
dubbo协议使用单链接好处
减少握手;在高QPS场景下,短链接有可能压垮服务
dubbo中的SPI机制(自如1)
依靠SPI机制实现插件化功能,将所有的功能组件做成基于SPI实现,提供了很多可以直接使用的扩展点,实现了面向功能进行拆分的对扩展开放的架构。
Java中的SPI Classpath下的META-INF/services/创建一个以服务接口命名的文件,文件里面记录的是此jar包提供的具体实现类的全限定名。JVM会在启动的时候扫描这个目录,进行加载
全部加载;没有缓存;数据库的driver
META-INF/services/ 目录:该目录下的 SPI 配置文件是为了用来兼容 Java SPI
META-INF/dubbo/ 目录:该目录存放用户自定义的 SPI 配置文件
META-INF/dubbo/internal/ 目录:该目录存放 Dubbo 内部使用的 SPI 配置文件
ExtensionLoader.getExtensionLoader 根据接口获取其特有的自定义类加载器
ExtensionLoader.getExtension(name) 先读Holder缓存,没有创建一个holder,然后创建实例,先获取类原信息,包含包装等信息,先读实例缓存,这里的实例缓存没有经过包装,如果没有进行反射创建,然后执行包装,然后放入holder返回
@SPI 标记一个接口需要被发现
@Wrapper 标记这是一个包装类 实现AOP
@Adaptive 标记这是一个需要自适应的方法
injectExtension发生在getExtension阶段 IOC,拿出所有需要带有set的method,获取属性名,从ObjectFactory中拿,ObjectFactory也是一个通过SPI发现的组件
ExtensionLoader是核心,静态Map维护了所有class的ExtensionLoader,通过每个class的ExtensionLoader获取对应name的实例
dubbo自适应扩展
自适应扩展指的是不需要自己显示调用ExtensionLoader.getExtension(name),而是通过一个ExtensionLoader.getAdaptiveExtension()获取一个自适应的实现类;
自适应实现类是根据接口类方法上的@Adaptive进行标记,获取自适应实现时通过javaassist动态将ExtensionLoader.getExtension(name)代码写到class文件中,并编译后或实例;
name来自于参数中URL对象,所以adaptive方法参数中必须包含URL参数;
未被Adaptive修饰的方法被调用会抛出notsupport异常
adaptive未设置value 按接口生成名获取 驼峰改成.
adaptive设置一个value 从url获取对应参数
adaptive设置多个value 从后往前 每一个都是上一个的默认值
adaptive实例有点像门面模式
@Adaptive修饰实现类,会直接将这个类当做一个自适应实现
dubbo SPI 的AOP
通过Wrapper实现,在SPI文件内,并且包含传入自身接口的构造放放,将被视为一个包装类;
没有被Wrapper注解修饰,或者通过Wrapper上参数匹配或者违背派出的包装类,在实现类被获取时通过构造方法包装
dubbo与springcloud的区别
dubbo本身是一个RPC框架,基于RPC服务扩展了周边一系列功能,服务注册与发现,路由,负载均衡;
springcloud是一个微服务生态,内容比dubbo多很多,消息总线,配置中心,网关等
dubbo中的服务暴露
coding通过@DubboService标记一个接口实现类需要被暴露
在Spring refresh阶段执行BeanFactoryPostProcessor ServiceClassPostProcessor扫描被DubboService修饰的类 处理成ServiceBeanDefinition注册到BeanFactory
DubboBootstrapApplicationListener 在spring finishRefresh阶段启动执行所有ServiceBean.export对象的暴露
暴露本地服务(提供给本地服务调用),通过代理生成Invoker,经过协议处理包装成Exporter,注册到注册中心
dubbo中的服务发现
coding中通过@DubboReference标记一个接口需要远程服务,可以选择实时注入,或者延时注入
在外部类Bean加载,populateBean事,执行ReferenceAnnotationBeanPostProcessor,创建一个ReferenceBean注入,ReferenceBean是一个FactoryBean
dubbo中服务调用过程
dubbo中的容错
fastover 请求失败,换一个节点重试,默认1次
fastfail 请求失败,返回失败
全发一次成功一个就行
失败了就返回空 记录日志
seata支持哪些模式
支持at、tcc、saga、xa
AT模式 拦截用户sql,解析之后找到对应修改行,进行快照;如果回滚,就使用快照数据,如果提交,就删除快照即可
Feign
Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。
Feign本身是一个RPC框架,依赖注册中心的服务发现与注册,封装了Ribbon和Hystrix也就是客户端负载均衡以及服务容错保护
Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。
Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这两者的强大功能外,还提供了一种声明式的Web服务客户端定义的方式。
Feign原理简述
启动时,程序会进行包扫描,扫描所有包下所有@FeignClient注解的类,并将这些类注入到spring的IOC容器中。当定义的Feign中的接口被调用时,通过JDK的动态代理来生成RequestTemplate。
RequestTemplate中包含请求的所有信息,如请求参数,请求URL等。
RequestTemplate声场Request,然后将Request交给client处理,这个client默认是JDK的HTTPUrlConnection,也可以是OKhttp、Apache的HTTPClient等。
最后client封装成LoadBaLanceClient,结合ribbon负载均衡地发起调用。
什么是netty
netty是一个基于nio的客户、服务器端编程框架,提供异步的,事件驱动的网络应用程序框架和工具,可以快速开发高可用的客户端和服务器。
netty是基于nio的,它封装了jdk的nio,让我们使用起来更加方法灵活。
并发高,传输快,封装好
javaNIO模式 buffer channel selector
netty架构
BootStrap、ServerBootStrap 启动引导类,通过链式调用串联各个组件
Future\ChannelFuture Netty中所有IO操作都是异步的,这里的异步指使用多线程处理事件,需要注册Future获取结果
Channel 通讯组件,用于执行网络操作
Selector 基于Selector对象实现IO多路复用,一个S线程可以监听多个Channel事件,
NioEventLoop 本质上是一个单线程线程池,IO任务有processSelectedKeys触发,非IO任务有runAllTasks触发
NioEventLoopGroup 管理eventloop的生命周期,也是一个线程池,每个线程负责处理一个Channel上的事件
ChannelHandler 处理IO事件,将操作转发到ChannelPipeline中
ChannelHandlerContext 用于传递Channel上下文信息关联一个ChannelHandler对象
ChannelPipeline 保存ChannerlHandler的list,用于处理或拦截Channerl的入站和出站事件,一个Channel包含一个ChannerlPipeline
netty线程模式
基于reactor
单reactor单线程
单reactor多线程
多reactor多线程 BossNioEventGroup(mainReactor)负责处理所有accept事件,注册到acceptor中,建立同道channel注册到WorkerNioEventGroup(sunReactor),sunReactor负责处理他管理的channel的read write事件,和处理pipeline任务
netty5为什么被废弃
主要是使用了ForkJoinPool,增加复杂度,也没提升多少性能;aio技术不大成熟;作者好像没啥时间
Elasticsearch
Elasticsearch 是一个分布式可扩展的实时搜索和分析引擎,一个建立在全文搜索引擎 Apache Lucene(TM) 基础上的搜索引擎.
全文搜索功能,
分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索。
实时分析的分布式搜索引擎。
可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。
倒排索引
正向索引就是我们为记录上打上各种标签,比如记录行1 name age等
倒排索引 我们为每个name记录包含它的记录行,
es使用的是倒排索引
mysql的fullindex
ES的分布式(雪球1)
ES集群中每个节点内部都有很多分片,这些不同节点中的分片互为主备;
保存数据时,根据ID确定数据应当存放的分片,找到主分片对应的节点,转发消息;
执行成功之后,主分片向副分片进行同步
ES的索引(雪球1)
ES使用倒排索引技术
term index -> term dictionary -> Posting List(维护文档ID,权重等信息)
对term dictionary使用二级索引快速定位到对应的term
index 对应databases 索引只是一个 逻辑命名空间,它指向一个或多个分片(shards),内部用Apache Lucene实现索引中数据的读写
type 对应scheme 每个文档在ElasticSearch中都必须设定它的类型。文档类型使得同一个索引中在存储结构不同文档时,只需要依据文档类型就可以找到对应的参数映射(Mapping)信息,方便文档的存取
document 对应rows 是可以被索引的基本单位
field 对应column
ES的中文分词器
hanlp ik
ES中Term index(雪球1)
字典树,专门处理字符串匹配,不包含所有term,包含所有term公共前缀,快速定位 term dictionary 的某个offset;
term index 在内存中是以 FST(finite state transducers)的数据结构保存
ES中term dictionary
在磁盘上面是分 block 保存的,一个 block 内部利用公共前缀压缩,比如都是 Ab 开头的单词就可以把 Ab 省去
什么是Mybatis
半orm框架,aop封装jdbc,connection、preparestatement、resultset映射,只需要关注sql,减少jdbc代码开发量
优点:减少代码开发量,可以与spring集成
缺点:可移植性差,不是面向对象
Mybatis缓存
一级缓存 sqlsession级别,内存缓存,默认开启,一次会话没有update多次查询返回缓存结果,update就刷新
二级缓存 自己命名作用于,可以自定义实现,默认不开启
虚拟地址空间、用户空间、内核空间
内存分页 节约、提高效率,内存拆成一块块4k 的page
虚拟地址空间 多任务OS,进程运行在各自的虚拟内存中,为了隔离;进程通过pagetable映射到物理内存;可以先建立虚拟地址空间并不映射物理内存,用的时候再映射物理内存
虚拟地址空间分为用户空间和内核空间 linux3:1
内核空间 为了系统安全 os强制用户进程不能直接操作内核,内核也需要内存,与用户进程隔离,单独使用内核空间
linux启动时,将内核程序加载到物理内存的内核空间上运行,为了能让用户进程使用内核来完成系统调用,将虚拟地址空间的内核空间映射到物理的内核空间上
用户态 程序运行在用户空间,属于用户态
内核态 程序畸形系统调用,进入内核空间运行,处于内核态
用户切换到内核态:系统调用 异常 外围设备中断
Memcached集群(雪球1)
memcached本身并没有提供集群部署的方案,一般部署多台实例,在客户端采用一致性hash的方案,选择对应的实例进行通讯。必须知道所有实例地址,本地shard规则需要统一维护。
或者原则一些开源的代理方案,
mcrouter facebook的成熟案例;功能强大,支持Memcache实例分组、实例复制功能,实例宕机后可自动踢出;一般用于ubuntu平台,在centos上安装较复杂
Magent代理
Memcached线程模型
一个master多个worker线程
每个woker线程使用一个libevent对象封装,包含线程信息和conn队列,每个请求进来master为其封装一个conn对象,选择对应的worker线程
Memcache内存模型
启动时创建 slabclass_t数组,slabclass_t数组维护一组slab对象,定义slab内部chunk大小,slab数组,slab数量,slab由一组page构成,一个page最大1k~128m,一个page包含相同大小的一组chunk;
每个slab对象按照slabclass_t定义的chunk大小进行分割,chunk是一个固定大小的物理存储单元,有可能造成空间浪费,
item是存储在chunk的逻辑数据,维护双向指针、key、value、time等信息
数据写入时,根据大小(超过1m,直接丢弃)找到对应的slabclass_t,遍历slab对象找到有空闲的chunk,进行数据存储;如果没有空闲就创建一个新的salb,如果内存不够执行LRU策略
Slab Allocator分配内存 每个slabclass_t都会分配一个1M大小的slab,slab又会被切分为N个小的内存块chunk,这个小的内存块的大小取决于slabclass_t结构上的size的大小。
grow factor调优
Memcache中的LRU
当最终没有足够内存分配给Item时,memcache将执行LRU来获取空间。首先从slab的尾部LRU链表tail[]开始搜索,检查该链表中是否有无效item,如果有则清除掉,将该空间用于存储新的Item,此操作最多尝试50次。如果没有无效Item,则看是否有开启强制淘汰,如果开启了,则无条件清除最后一个Item,即使该Item被设置成永久有效。如果没有开启,则抛出Out Of Memory错误。
Memcached总结
1、MemCache中可以保存的item数据量是没有限制的,只要内存足够
2、MemCache单进程在32位机中最大使用内存为2G,这个之前的文章提了多次了,64位机则没有限制
3、Key最大为250个字节,超过该长度无法存储
4、单个item最大数据是1MB,超过1MB的数据不予存储
5、MemCache服务端是不安全的,比如已知某个MemCache节点,可以直接telnet过去,并通过flush_all让已经存在的键值对立即失效
6、不能够遍历MemCache中所有的item,因为这个操作的速度相对缓慢且会阻塞其他的操作
7、MemCache的高性能源自于两阶段哈希结构:第一阶段在客户端,通过Hash算法根据Key值算出一个节点;第二阶段在服务端,通过一个内部的Hash算法,查找真正的item并返回给客户端。从实现的角度看,MemCache是一个非阻塞的、基于事件的服务器程序
8、MemCache设置添加某一个Key值的时候,传入expiry为0表示这个Key值永久有效,这个Key值也会在30天之后失效
MongoDB
MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB文档类似于JSON对象。字段值可以包含其他文档,数组及文档数组。
MongoDB速度快的原因
写:内存映射技术 - 写入数据时候只要在内存里完成就可以返回给应用程序,保存到硬体的操作则在后台异步完成
读:内存缓存常用数据,文档模式数据都在一起,磁盘顺序读写
分布式集群扩展