41.redis和memcheched 什么区别 为什么单线程的redis比多线程的memched效率要高啊?
网络IO模型
memcache:是多线程非阻塞IO复用网络模型,分为Master线程和worker子线程,Master线程负责监听网络连接,接受请求后,传递给worker线程, 在worker线程中进行命令接受处理和返回,memcache启动时可以通过 memcached -t num 设置worker线程的数目,网络层使用libevent封装的事件库,多线程模型可以发挥多核作用,但是也引入了缓存一致性和锁的问题。
Redis:使用单线程IO复用模型,自己封装了一个aeEvent事件处理框架,主要实现了epoll 、kqueue、select,对于单纯只有IO操作来说,单线程可以将速度发挥到最大,但是redis也提供了一些简单的计算功能,排序和聚合,对于这些操作,单线程模型实际会严重影响整体吞吐量,CPU计算过程中,整个IO调度室被阻塞的。
内存管理
Memcache:使用了Slab Allocation的方式,memcache将内存割分成固定大小的slab,每个slab又可以分为大小相同的许多个page,每个Page中分为大小相同的chunk,chunk是保存数据的单位,每个slab中chunk大小是不相同的,使用slab和大小不同的chunk来管理内存,item根据大小不同选择合适的chunk存储,内存池可以省去申请、释放内存的开销,并且可以较少内存外部碎片的产生,但是依然会产生内部碎片。 并且在内存仍然有很大使用空间的时候,新的数据也有可能恢复剔除,因为根据大小分配到不同的slab class,如果这个slab class已经满了,就会剔除数据,即使其他的slab class还是有空余的。只是因为memcache使用的替换算法LRU算法是针对slab的不是针对全局的。
Redis:使用现场申请内存的方式来存储数据,会在一定程度上存在内存外部碎片。 并且redis会把带过期时间的数据单独存放在一起,并把它们叫做临时数据,非临时数据永远不会剔除的,即使物理内存不够,导致swap也不会剔除任何非临时数据,这点上redis更适合作为存储而不是cache。而且redis是一种惰性的过期键删除策略,当key过期后仍然会存在在reids中,知道有客户端调用get命令,才会检查key的过期时间,那时再把过期键删除。
数据一致性问题
memcache是多线程的,所以当并发操作时会存在数据不一致问题,memcache提供了一个cas机制
redis提供了事务功能,可以保证一连串命令的事务性
存储方式
memcache只支持简单的key-value存储,不支持持久化和复制,不支持枚举所有key。
redis除了key-value还支持list set sorted hset hash等众多数据结构,提供了keys进行枚举,redis同时提供了持久化(RDB持久化和AOF持久化)和复制
redis提供了事务功能,可以保证一连串命令的事务性
分布式存储
redis支持master-slave复制模式
memcache可以使用一致性hash做分布式
储存大小
redis最大可以达到1GB,而memcache只有1MB
42.redis有什么数据类型都在哪些场景下使用啊?
String(字符串):二进制安全,可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512M。
Hash(字典):适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值。键值对集合,即编程语言中的Map,类型适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去)。
场景:存储、读取、修改用户属性。
List(列表):链表(双向链表)。增删快,提供了操作某一段元素的API
场景:1,最新消息排行等功能(比如朋友圈的时间线) 2,消息队列
Set(集合):哈希表实现,元素不重复。1,添加、删除,查找的复杂度都是O(1) 2,为集合提供了求交集、并集、差集等操作
场景:1,共同好友 2,利用唯一性,统计访问网站的所有独立ip 3,好用推荐时,根据tag求交集,大于某个阈值就可以推荐
Sorted Set(有序集合):将Set中的元素增加一个权重参数score,元素按score有序排列。数据插入集合时,已经进行天然排序
场景:1,排行榜 2,带权重的消息队列
线程不是影响吞吐量的重要因素。Redis是一个内存数据库,所有数据都在内存中,我们知道内存的读写速度是非常快的,而网络I/O速度则要慢得多,因此数据的读写在整个请求的耗时占比是较小的,使用多线程反而会在线程上下文切换上浪费时间,同时还会带来并发问题,需要对操作的对象加锁,并不能提高性能。
在网络I/O上,Redis采用了I/O多路复用(Epoll)模型,由于每个请求的处理都非常快,因此单线程即可处理大量的请求,实现了高性能高并发。单纯的网络IO来说,量大到一定程度之后,多线程的确有优势, 但并不是单纯的多线程,而是每个线程自己有自己的epoll模型,也就是多线程和multiplexing混合。但是,考虑Redis操作的是内存中的数据结构,如果在多线程中操作,那就需要为这些对象加锁,所以使用多线程可以提高并发度,但是每个线程的效率严重下降了,而且程序的逻辑严重复杂化。Redis的数据结构并不全是简单的Key-Value,还有list,hash等复杂的结构,这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加一个元素,在hash当中添加或者删除一个对象,这些操作还可以合成MULTI/EXEC的组。这样一个操作中可能就需要加非常多的锁,导致的结果是同步开销大大增加。Redis在权衡之后的选择是用单线程,突出自己功能的灵活性。在单线程基础上任何原子操作都可以几乎无代价地实现,多么复杂的数据结构都可以轻松运用,甚至可以使用Lua脚本这样的功能。
Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
43.reids的主从复制是怎么实现的 redis的集群模式是如何实现的呢 redis的key是如何寻址的啊?
主从同步流程
1、保存主节点信息;从节点只保存主节点的地址信息变直接返回(复制流程还没有开始)
2、主从建立socket连接:无限重试到链接成功或者执行slaveofnoone取消复制;
3、发送ping命令(1、检测主从指尖socke是否可用;2、检测主节点当前是否接受处理命令)
4、权限验证
5、同步数据集(全量同步和部分同步)
6、命令持续复制:主节点持续把写命令发送给从节点;
从节点执行psync,发送psync给主,主根据psync参数和自身数据情况决定响应结果,决定全量复制还是部分复制。全量复制发送RDB文件。部分复制是主从节点间网络出现中断时,如果超过repl-timeout时间,主会认为从故障并中断复制。中断期间,主的命令写入复制缓冲区;然后在从节点连上主之后如果复制缓冲区中存在偏移量的数据,那么表示可以复制,进行复制步骤。
redis集群是如何实现的
主从模式:
只有1个Master,可以有N个slaver,而且Slaver也可以有自己的Slaver,由于这种主从的关系决定他们是在配置阶段就要指定他们的上下级关系
读写分离:
Master只负责写和同步数据给Slaver,Slaver承担了被读的任务,所以Slaver的扩容只能提高读效率不能提高写效率。
Slaver先将Master那边获取到的信息压入磁盘,再load进内存,client端是从内存中读取信息的,所以Redis是内存数据库。
哈希Slot:
其实是redis层面上的分库分表
对象保存到Redis之前先经过CRC16哈希到一个指定的Node上,例如Object4最终Hash到了Node1上。
每个Node被平均分配了一个Slot段,对应着0-16384,Slot不能重复也不能缺失,否则会导致对象重复存储或无法存储。
ode之间也互相监听,一旦有Node退出或者加入,会按照Slot为单位做数据的迁移。例如Node1如果掉线了,0-5640这些Slot将会平均分摊到Node2和Node3上,由于Node2和Node3本身维护的Slot还会在自己身上不会被重新分配,所以迁移过程中不会影响到5641-16384Slot段的使用。
主从模式和哈希Slot一起使用:
想扩展并发读就添加Slaver,想扩展并发写就添加Master,想扩容也就是添加Master,任何一个Slaver或者几个Master挂了都不会是灾难性的故障。
redis的key是如何寻址的
如上 根据哈希slot进行寻址。
44.使用redis如何设计分布式锁?使用zk可以吗?如何实现啊这两种哪个效率更高啊??
使用redis中的setnx命令进行设计分布式锁
关于redis的操作命令,我们一般会使用set,get等一系列操作,数据结构也有很多,这里我们使用最简单的string来存储锁。
redis下提供一个setnx命令用来将key值设为value,类似于set功能,但是它和set是有区别的,在于后面的nx,setnx是SET if Not eXists。就是:当且仅当key值不存在的时候,将该key值设置为value。
也就是说使用setnx加入元素的时候,当key值存在的时候,是没有办法加入内容的。
使用zk大同小异
是通过创建zk的znode节点进行控制。检查zookeeper集群下的这个节点是否存在存在证明已经有锁了,不存在就没有。
优劣
Redis分布式锁,必须使用者自己间隔时间轮询去尝试加锁,当锁被释放后,存在多线程去争抢锁,并且可能每次间隔时间去尝试锁的时候,都不成功,对性能浪费很大。
Zookeeper分布锁,首先创建加锁标志文件,如果需要等待其他锁,则添加监听后等待通知或者超时,当有锁释放,无须争抢,按照节点顺序,依次通知使用者。
45.知道redis的持久化吗都有什么缺点优点啊? ?具体底层实现呢?
RDB的优缺点:
优点:RDB是一个紧凑的二进制文件,代表redis在某个时间点上的数据快照。非常适用于备份,全量复制等场景用于灾难恢复。加载Rdb恢复数据远快于AOF方式。
缺点:1、无法做到实时持久化/秒级持久化(因为每次都要fork,属于重量级操作)
2、redis演进过程中有多个格式rdb版本,存在老版本redis无法兼容新版rdb格式的问题
AOF的优缺点
优点:
1. 该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。
2. 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。
如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
3. AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。
缺点:
1. 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
2. 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。
46.redis过期策略都有哪些LRU 写一下java版本的代码吧??
redis过期策略
redis使用的回收策略是惰性删除和定期删除
1. 惰性删除
在进行get或setnx等操作时,先检查key是否过期,
若过期,删除key,然后执行相应操作;
若没过期,直接执行相应操作
2. 定期删除
遍历每个数据库(就是redis.conf中配置的”database”数量,默认为16)
检查当前库中的指定个数个key(默认是每个库检查20个key,注意相当于该循环执行20次,循环体时下边的描述)
如果当前库中没有一个key设置了过期时间,直接执行下一个库的遍历
随机获取一个设置了过期时间的key,检查该key是否过期,如果过期,删除key。
判断定期删除操作是否已经达到指定时长,若已经达到,直接退出定期删除。
redis内存回收策略
引用计数算法以及LRU算法
1. 引用计数算法
引用计数算法作为垃圾收集器最早的算法,现在的JVM都不再采用引用计数算法进行垃圾回收。
对于创建的每一个对象都有一个与之关联的计数器,这个计数器记录着该对象被使用的次数,垃圾收集器在进行垃圾回收时,对扫描到的每一个对象判断一下计数器是否等于0,若等于0,就会释放该对象占用的内存空间,同时将该对象引用的其他对象的计数器进行减一操作。
2. LRU算法
又称为 最近最久未使用算法
算法演示
虽然可以使用队列实现,但是LRU算法的最经典的实现是HashMap+Double LinkedList(哈希表+双向链表)
时间复杂度为O(1)
个人实现
/**思路
1.维护一个hashMap和一个双向链表(可以使用LinkList,此处自己实现)
2.get时通过hashMap查询,更新得到的key到链表头部
3.set时存入hashMap,更新set的key到链表头部,检查链表大小若超过则把链表尾部去除
分布式服务框架
47.说一下dubbo的实现过程注册中心挂了可以继续通信吗??
服务容器负责启动,加载,运行服务提供者。
服务提供者在启动时,向注册中心注册自己提供的服务。
服务消费者在启动时,向注册中心订阅自己所需的服务。
注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外
注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者
注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
48.dubbo支持哪些序列化协议?hessian 说一下hessian的数据结构PB知道吗为啥PB效率是最高的啊??
dubbo序列化:阿里尚未开发成熟的高效java序列化实现,阿里不建议在生产环境使用它
hessian2序列化:hessian是一种跨语言的高效二进制序列化方式。但这里实际不是原生的hessian2序列化,而是阿里修改过的hessian lite,它是dubbo RPC默认启用的序列化方式
json序列化:目前有两种实现,一种是采用的阿里的fastjson库,另一种是采用dubbo中自己实现的简单json库,但其实现都不是特别成熟,而且json这种文本序列化性能一般不如上面两种二进制序列化。
java序列化:主要是采用JDK自带的Java序列化实现,性能很不理想。
Kryo:Kryo序列化机制比默认的Java序列化机制速度要快,序列化后的数据要更小,大概是Java序列化机制的1/10。所以Kryo序列化优化以后,可以让网络传输的数据变少,在集群中耗费的内存资源大大减少。需要注意的是其基于类的field。性能上优于古老的hessian,虽然类第一次序列化时优于Kryo要去加载该类导致速度上不及hessian,但是无论在大小速度上都和特性支持上都强于hessian
FST:fst是完全兼容JDK序列化协议的系列化框架,序列化速度大概是JDK的4-10倍,大小是JDK大小的1/3左右。
ProtoBuf:google开发的开源的序列化方案,独立于语言,独立于平台,效率相当高,用protobuf序列化后的大小是json的10分之一,xml格式的20分之一,是二进制序列化的10分之一。
ProtoStuff:ProtoBuf的一个优化版本,不需要我们去写.proto文件了。
hession的数据结构
pb效率为何这么高
一、使用三元组储存方式:TLV(Tag - Length - Value)以标识 - 长度 - 字段值表示单个数据,最终将所有数据拼接成一个字节流,从而实现数据存储的功能。
不需要分隔符 就能 分隔开字段,减少了 分隔符 的使用
各字段 存储得非常紧凑,存储空间利用率非常高
若 字段没有被设置字段值,那么该字段在序列化时的数据中是完全不存在的,即不需要编码
二、Protocol Buffer对于不同数据类型 采用不同的 序列化方式
三、使用Varint & Zigzag编码方式对不同大小的值以不同的大小进行表示,对数据进行进一步的压缩
四、通过.proto定义文件使用嵌套消息类型节约定义成本(类似于json字符串一样的嵌套)
49.知道netty吗?netty可以干嘛呀NIO,BIO,AIO 都是什么啊有什么区别啊?
50.dubbo复制均衡策略和高可用策略都有哪些啊动态代理策略呢?
dubbo提供几种预置负载均衡可选策略
1. Random:随机,按权重设置随机概率。在一个截面上碰撞的概率很高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
2. RoundRobin:轮循,按公约后的权重设置轮循比率。注意:轮询策略存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
3. LeastActive:最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差(调用前的时刻减去响应后的时刻的值 也就是请求耗时),使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
4. ConsistentHash:一致性 Hash。相同参数的请求总是发到同一提供者。当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
高可用性:见第一问dubbo的实现过程
动态代理策略:基于Spring Bean生成的rpc服务代理。所有的Dubbo消费者Bean都是ReferenceBean类型的对象,interface属性中配置的接口只是让ReferenceBean对象知道Dubbo的服务提供方提供的方法签名而已
51.为什么要进行系统拆分啊拆分不用dubbo可以吗'dubbo和thrift什么区别啊?
系统拆分可能是由于技术团队扩大,组织结构变化从最初的一个团队逐渐成长并拆分为几个团队,团队按照业务线不同进行划分,为了减少各个业务系统和代码间的关联和耦合,几个团队不再可能共同向一个代码库中提交代码,必须对原有系统进行拆分。
其不仅是为了适应团队规模扩张,系统拆分也是soa架构实现的一环,并且具有代码成果的安全性、方便服务替换、解耦各个功能模块以增加交付速度等优势。
dubbo只是一种通用的系统拆分服务治理解决方案,不用当然可以。自己引入rpc框架,监控体系,消息系统也能实现。
thrift是rpc通讯框架,通过.thrift文件实现rpc通讯。dubbo是服务治理框架,不仅包含rpc,更多的是服务治理。比如注册中心,mq,监控等等。
分布式消息队列
52.为什么使用消息队列啊消息队列有什么优点和缺点啊?
出现原因:
主要原因是由于在高并发环境下,由于来不及同步处理,请求往往会发生堵塞,比如说,大量的insert,update之类的请求同时到达MySQL,直接导致无数的行锁表锁,甚至最后请求会堆积过多,从而触发too many connections错误。通过使用消息队列,我们可以异步处理请求,从而缓解系统的压力。
解决问题:
系统中出现“生产“和“消费“的速度或稳定性等因素不一致的时候,就需要消息队列,作为抽象层,弥合双方的差异。
优点:
1. 解耦:将消息写入消息队列,需要消息的系统自己从消息队列中订阅,从而系统不需要做任何修改。
2. 异步:将消息写入消息队列,非必要的业务逻辑以异步的方式运行,加快响应速度
3. 削峰:系统慢慢的按照数据库能处理的并发量,从消息队列中慢慢拉取消息。在生产中,这个短暂的高峰期积压是允许的。
缺点:
通讯依赖中间件:与其他系统交互依赖了第三方实现。可用性降低(中间件挂掉会出现问题)
系统复杂性增加:需要额外考虑一致性问题,重复消费问题等诸多由于中间件带来的问题。
非及时:无法确保消息被消费的时间。不能作为单次请求链条的依赖。
53.如何保证消息队列的高可用啊如何保证消息不被重复消费啊
如何保证消息队列的高可用:当然是集群和broker储存消息机制。
不被重复消费:通过幂等回调方式来确保。
54.kafka ,activemq,rabbitmq ,rocketmq都有什么优点,缺点啊?
55.如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路
个人认为mq底层需要有一套主题-生产者—消费组-消费者模型进行支持。需要一个注册模块,注册消费机器到消费组。每一个topic需要维护自己的消费组。然后储存模块,储存生产者发送消息及生产-消费轨迹,消费模块,通知到一个消费组某台机器进行消费。需要基于zk发现服务(生产者及消费者机器)。
通信协议
56.说一下TCP / IP四层?
链路层(数据链路层/网络接口层):包括操作系统中的设备驱动程序、计算机中对应的网络接口卡
网络层(互联网层):处理分组在网络中的活动,比如分组的选路。
运输层:主要为两台主机上的应用提供端到端的通信。
应用层:负责处理特定的应用程序细节。
57.HTTP 的工作流程??http1.0 http1.1http2.0 具体哪些区别啊?
工作流程
1. 地址解析:把url地址解析成解出协议名、主机名、端口、对象路径等部分
2. 封装http请求数据包
3. 封装成tcp包,建立tcp连接(三次握手)
4. 客户端发送请求
5. 服务器响应
6. 服务器关闭tcp连接
http1.0,1.1,2.0的区别
1. 长连接:HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP1.1默认支持长连接。
2. 节约带宽:HTTP 1.1支持只发送header信息(不带任何body信息),如果服务器认为客户端有权限请求服务器,则返回100,否则返回401。客户端如果接受到100,才开始把请求body发送到服务器。
这样当服务器返回401的时候,客户端就可以不用发送请求body了,节约了带宽。
3. HOST 域:现在可以web server例如tomat,设置虚拟站点是非常常见的,也即是说,webserver上的多个虚拟站点可以共享同一个ip和端口。
HTTP1.0是没有host域的,HTTP1.1才支持这个参数。
HTTP2.0使用了多路复用的技术,:做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。
数据压缩:HTTP1.1不支持header数据的压缩,HTTP2.0使用HPACK算法对header的数据进行压缩,这样数据体积小了,在网络上传输就会更快。
服务器推送:意思是说,当我们对支持HTTP2.0的web server请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器端获取。这种方式非常合适加载静态资源。
58.TCP三次握手,四层分手的工作流程画一下流程图为什么不是四次五次或者二次啊?
三次握手的原因:
如果两次握手如果客户端请求在某个节点停留较长时间 到了服务端就相当于服务端直接与客户端建立连接,但是这是一个已经失效了的报文。这种连接不可靠。
四次挥手的原因:
当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,”你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
59.画一下https的工作流程?具体如何实现啊?如何防止被抓包啊??
1.[Server]生成一对密钥:公钥和私钥,我们称之为“KeyPub”,“KeyPri”
2.[Server]服务端将公钥(KeyPub)发送到客户端
3.[Client]生成一个对称密钥(姑且称之为key2),然后用key2加密数据。
4.[Client]使用公钥(KeyPub)加密key2.这时,key2是安全的,因为只有服务度有私钥KeyPri
5.[Client]发送用key2加密后的信息及用KeyPub加密过的key2到服务端
6.[Server]服务端使用KeyPri解密得到加密过的key2,得到真正的key2
7.[Server]使用key2解密消息正文。这样,数据就被安全的传输到了服务端。
具体实现可以参照rsa加密流程
RSA加密使用方式及签名验证 - CSDN博客
如何防止被抓包:https 所谓的防止被抓包并不是能够杜绝抓包的行为,而是让抓包变得无意义,例如用https进行抓包之后,抓包方无法得知里面的数据内容,也无法进行伪造。
除了https防止抓包外,数据传输更内层也对数据进行了保护,也就是SSL(Secure Socket Layer,安全套接字层)。
60.源码中所用到的经典设计思想及常用设计模式
61.系统架构如何选择合适日志技术(log4j、log4j2、slf4j、jcl…….)
62.springAOP的原理,springAOP和Aspectj的关系,springAOP的源码问题
63.dubbo框架的底层通信原理
64.RPC通信原理,分布式通信原理
65.如何利用springCloud来架构微服务项目
66.如何正确使用docker技术
67.springMVC的底层原理、如何从源码来分析其原理
68.mybaits的底层实现原理,如何从源码来分析mybaits
69.mysql的索引原理,索引是怎么实现的
70.索引的底层算法、如何正确使用、优化索引
71.springboot如何快速构建系统
72.zk原理知道吗zk都可以干什么Paxos算法知道吗?说一下原理和实现?
算法
有一个文件,有45亿个阿拉伯数字,如何去重?如何找到最大的那个?
使用bitMap,映射int到byte的关系上进行去重操作 一个byte能表示8个数,这样可以把申请的内存变为原来的1/8
BitMap