中间件

作者: 小丸子的呆地 | 来源:发表于2021-11-02 14:39 被阅读0次

    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速度快的原因

    写:内存映射技术 - 写入数据时候只要在内存里完成就可以返回给应用程序,保存到硬体的操作则在后台异步完成
    读:内存缓存常用数据,文档模式数据都在一起,磁盘顺序读写

    分布式集群扩展

    相关文章

      网友评论

          本文标题:中间件

          本文链接:https://www.haomeiwen.com/subject/vezkgltx.html