程序员必备知识点

程序员必备知识点

1、tcp 三次握手,四次挥手

为什么连接的时候是三次握手,关闭的时候却是四次握手?

image-20200928193010926

三次握手是为了确定收发双方都有收发能力:

第一次握手,证明了client有发送能力

第二次握手,证明了server又接收和发送能力

第三次握手,证明了client有接收能力

image-20200928193246073

原文链接:https://blog.csdn.net/whuslei/article/details/6667471

2、tcp 拆包、粘包问题。

应用程序写入的数据大于套接字缓冲区大小,这将会发生拆包。

应用程序写入数据小于套接字缓冲区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘包。

进行MSS(最大报文长度)大小的TCP分段,当TCP报文长度-TCP头部长度>MSS的时候将发生拆包。

接收方法不及时读取套接字缓冲区数据,这将发生粘包。

粘包、拆包解决办法

TCP本身是面向流的,作为网络服务器,如何从这源源不断涌来的数据流中拆分出或者合并出有意义的信息呢?通常会有以下一些常用的方法:

1、发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。

2、发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。

3、可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。

http和https的区别

HTTPS是一种应用层协议,本质上来说它是HTTP协议的一种变种。HTTPS比HTTP协议安全,因为HTTP是明文传输,而HTTPS是加密传输,加密过程中使用了三种加密手段,分别是证书,对称加密和非对称加密。HTTPS相比于HTTP多了一层SSL/TSL

image-20201008104044814

1.客户端向服务端发起HTTPS的请求,连接到服务器的443端口;

2.服务器端将加密公钥以证书的形式返回;

3.服务器接受到该公钥进行验证,就是验证2中证书,如果有问题,则HTTPS请求无法继续;如果没有问题,则上述公钥是合格的。(第一次HTTP请求)客户端这个时候随机生成一个私钥,成为client key,客户端私钥,用于对称加密数据的。使用前面的公钥对client key进行非对称加密;

4.进行二次HTTP请求,将加密之后的client key传递给服务器;

5.服务器使用私钥进行解密,得到client key,使用client key对数据进行对称加密

6.将对称加密的数据传递给客户端,客户端使用非对称解密,得到服务器发送的数据,完成第二次HTTP请求。

区别:

(1)HTTPS是密文传输,HTTP是明文传输;

(2)默认连接的端口号是不同的,HTTPS是443端口,而HTTP是80端口;

(3)HTTPS请求的过程需要CA证书要验证身份以保证客户端请求到服务器端之后,传回的响应是来自于服务器端,而HTTP则不需要CA证书;

(4)HTTPS=HTTP+加密+认证+完整性保护。

3、linux io 类型。

同步模型(synchronous IO)

阻塞IO(bloking IO)

非阻塞IO(non-blocking IO)

多路复用IO(multiplexing IO)

信号驱动式IO(signal-driven IO)

异步IO(asynchronous IO)

4、线程reactor 模型。

单线程模型

多线程模型

主从线程模型

5、redis 分布式锁

setnx

redission 底层是lua脚本

6、sortSet 排序时间复杂度,及常用命令

sortSet 的排序时间复杂度为:O(N+M*Log(M)),跳表?

常用命令:

zadd :添加元素,格式是:zadd zset的key score值 项的值, Score和项可以是多对,score可以是整数,也可以是浮点数,还可以是+inf表示无穷大,-inf表示负无穷大

1
zadd key名称 分数 成员名

zrange :获取索引区间内的元素,格式是:zrange zset的key 起始索引 终止索引 (withscore)

1
zrange key名称 起始索引 终止索引 withscores

zrangebyscore :获取分数区间内的元素,格式是:zrangebyscore zset的key 起始score 终止score (withscore),默认是包含端点值的,如果加上”(“表示不包含,后面还可以加上limit来限制。

1
zrangebyscore key名称 startscore endscore withscores

zrem :删除元素,格式是:zrem zset的key 项的值,项的值可以是多个

1
zrem key名称 member

zcard :获取集合中元素个数,格式是:zcard zset的key

1
zcard key名称

zincrby :增减元素的score,格式是:zincrby zset的key 正负数字 项的值

1
zincrby key名称 score member

zrank : 获取项在zset中的索引,格式是:zrank zset的key 项的值

1
zrank key名称 member

zscore :获取元素的分数,格式是:zscore zset的key 项的值,返回项在zset中的score

1
zscore key名称 member

Java基础

ArrayList源码

HashMap源码

ConcurrentHashMap源码

线程池ThreadPool

synthronized, volatile, Lock的使用和区别

NIO实现

工厂,代理,单例模式(单例模式多线程问题)

1

cglib与proxy的使用和区别

JDK Proxy 动态代理的实现无需引用第三方类,只需要实现 InvocationHandler 接口,重写 invoke() 方法即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 /**
     * JDK Proxy
     */
    static class JDKProxy implements InvocationHandler {
        private Object target; // 代理对象

        // 获取到代理对象
        public Object getInstance(Object target) {
            this.target = target;
            // 取得代理对象
            return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(), this);
        }

        /**
         * 执行代理方法
         * @param proxy  代理对象
         * @param method 代理方法
         * @param args   方法的参数
         * @return
         * @throws InvocationTargetException
         * @throws IllegalAccessException
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws InvocationTargetException, IllegalAccessException {
            System.out.println("动态代理之前的业务处理.");
            Object result = method.invoke(target, args); // 执行调用方法(此方法执行前后,可以进行相关业务处理)
            return result;
        }
    }

实现MethodInterceptor接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 /**
     * CGLib 代理类
     */
    static class CGLibProxy implements MethodInterceptor {
        private Object target; // 代理对象

        public Object getInstance(Object target) {
            this.target = target;
            Enhancer enhancer = new Enhancer();
            // 设置父类为实例类
            enhancer.setSuperclass(this.target.getClass());
            // 回调方法
            enhancer.setCallback(this);
            // 创建代理对象
            return enhancer.create();
        }

        @Override
        public Object intercept(Object o, Method method,
                                Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("方法调用前业务处理.");
            Object result = methodProxy.invokeSuper(o, objects); // 执行方法调用
            return result;
        }
    }

  1. JDK Proxy 是 Java 语言自带的功能,无需通过加载第三方类实现;
  2. Java 对 JDK Proxy 提供了稳定的支持,并且会持续的升级和更新 JDK Proxy,例如 Java 8 版本中的 JDK Proxy 性能相比于之前版本提升了很多;
  3. JDK Proxy 是通过拦截器加反射的方式实现的;
  4. JDK Proxy 只能代理继承接口的类;
  5. JDK Proxy 实现和调用起来比较简单;
  6. CGLib 是第三方提供的工具,基于 ASM 实现的,性能比较高;
  7. CGLib 无需通过接口来实现,它是通过实现子类的方式来完成调用的。

Java可重入锁和读写锁

JVM内存模型

JVM GC机制和相关算法

GCroot ,可达性分析法。

标记清除法、复制算法、标记整理法、分代算法

内存分配的两种方式: 指针碰撞空闲列表

JVM类的加载

加载、验证、准备、解释、初始化、使用、卸载

加载:1)通过一个类的全限定名来获取定义此类的二进制流。

​ 2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据接口

​ 3)在内存中生成一个代表这个类的java.lang.Class的对象,作为方法区这个类的各种数据访问入口。

ClassTraceLoading

加载是文件到内存的过程,通过类的全限定名查找类字节码文件,并利用字节码创建一个class对象;

验证是对类文件内容进行验证。目的在与确保Class文件符合当前虚拟机要求,不会危害虚拟机自身安全。主要包括四种:文件格式验证(魔数,版本号,等等),元数据验证,字节码验证,符号引用验证。

准备是进行内存分配,为类变量也就是类中由static修饰的变量分配内存,并设置初始值。这里要注意,初始值是0或者null,false。代码中具体的值是在初始化工程中完成的,final类型在编译过程中就赋值了

解析主要是解析字段,接口,方法。主要是将常量池中的符号变量替换为直接引用的过程。

初始化,主要完成静态块与静态变量的赋值。这是类加载的最后阶段。

JVM性能调优的大体步骤

CAS算法

CAS是英文单词CompareAndSwap的缩写,中文意思是:比较并替换。CAS需要有3个操作数:内存地址V,旧的预期值A,即将要更新的目标值B。

CAS指令执行时,当且仅当内存地址V的值与预期值A相等时,将内存地址V的值修改为B,否则就什么都不做。整个比较并替换的操作是一个原子操作。

CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。

CAS的缺点:

CAS虽然很高效的解决了原子操作问题,但是CAS仍然存在三大问题。

  1. 循环时间长开销很大。
  2. 只能保证一个共享变量的原子操作。
  3. ABA问题。

循环时间长开销很大:
我们可以看到getAndAddInt方法执行时,如果CAS失败,会一直进行尝试。如果CAS长时间一直不成功,可能会给CPU带来很大的开销。

只能保证一个共享变量的原子操作:
当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁来保证原子性。

什么是ABA问题?ABA问题怎么解决?
如果内存地址V初次读取的值是A,并且在准备赋值的时候检查到它的值仍然为A,那我们就能说它的值没有被其他线程改变过了吗?

一致性Hash

arrayList底层结构,linkedList底层结构,两者的区别(RandomAccess)

1. 是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全; 2. 底层数据结构: Arraylist 底层使用的是 Object 数组; LinkedList 底层使用的是 双 向链表 数据结构(JDK1.6之前为循环链表,JDK1.7取消了循环。注意双向链表和双向循环链表 的区别,下面有介绍到!)

3. 插入和删除是否受元素位置的影响:

1 ArrayList 采用数组存储,所以插入和删除元素的 时间复杂度受元素位置的影响。 比如:执行 add(E e) 方法的时候, ArrayList 会默认在将指 定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入 和删除元素的话( add(int index, E element) )时间复杂度就为 O(n-i)。因为在进行上述操作 的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。

2 LinkedList 采用链表存储,所以对于 add(E e) 方法的插入,删除元素时间复杂度不受元素位 置的影响,近似 O(1),如果是要在指定位置 i 插入和删除元素的话( (add(int index, E element) ) 时间复杂度近似为 o(n)) 因为需要先移动到指定位置再插入。
4. 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而 ArrayList 支持。 快速随机访问就是通过元素的序号快速获取元素对象(对应于 get(int index) 方法)。

5. 内存空间占用: ArrayList的空 间浪费主要体现在在list列表的结尾会预留一定的容量空 间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因 为要存放直接后继和直接前驱以及数据)。

hashmap底层结构(java8版本),concurrentHashMap(java8版本)、hashTable,三兄弟对比下吧?

nio和bio相比有啥不同(aio呢)

jvm内存划分(java8版本呢?),堆的划分(系统遇到瓶颈,确定是JVM引起,怎么调优,说下具体做法)

成员变量、局部变量等等的会分配到jvm的哪块儿区域

mysql的引擎知道哪些,有啥区别

1
show engines;

image-20200930222745773

MyISAM、支持事务的 InnoDB、内存类型的 Memory、归档类型的 Archive、列式存储的 Infobright,以及一些新兴的存储引擎,以 RocksDB 为底层基础的 MyRocks 和 RocksDB。

功能 InnoDB MyiSAM
ACID事务
配置ACID
崩溃恢复
外键支持
行级锁粒度
MVCC
  • InnoDB 支持 ACID 的事务 4 个特性,而 MyISAM 不支持;

  • InnoDB 支持 4 种事务隔离级别,默认是可重复读 Repeatable Read 的,MyISAM 不支持;

  • InnoDB 支持 crash 安全恢复,MyISAM 不支持;

  • InnoDB 支持外键,MyISAM 不支持;

  • InnoDB 支持行级别的锁粒度,MyISAM 不支持,只支持表级别的锁粒度;

  • InnoDB 支持 MVCC,MyISAM 不支持;

乐观锁、悲观锁

悲观锁主要是共享锁排他锁
共享锁又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。
排他锁又称为写锁,简称X锁,顾名思义,排他锁就是不能与其他所并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,但是获取排他锁的事务是可以对数据就行读取和修改。

实现乐观锁一般来说有以下2种方式:

  • 使用版本号
    使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。
  • 使用时间戳
    乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。

索引相关的(btree、失效、组合索引的最左分配原则、explain使用)

线程池相关

参数名 含义
corePoolSize 核心线程数
maxPoolSize 最大线程数
keepAliveTime+单位时间 空闲线程的存活时间
ThreadFactory 线程工厂,用来创建新线程
workQueue 用于存放任务的队列
Handler 处理被拒绝的任务

image-20201001090334020

四种拒绝策略
策略 处理方法
AbortPolicy 抛出一个类型为RejectedExecutionExceptiond的RuntimeException,让开发者知道任务被拒绝了,从而根据具体业务选择重试或者放弃提交等策略
DiscardPolicy 当新任务提交,直接丢弃,不会给开发者任何通知,所以存在风险
DiscardOrdestPolicy 丢弃老任务,同上也有风险
CallerRunsPolicy

volatile关键字

lock的读写、中断、自旋

对threadLocal的理解

ThreadLocal 不是用来解决多线程共享变量的问题,而是用来解决线程数据隔离的问题。

底层实现主要是存有一个map,以线程作为key,泛型作为value,可以理解为线程级别的缓存。每一个线程都会获得一个单独的map。

序列化、反序列化(一个已经实现Serializable的类,新增个属性,怎样让程序直接报错)

1.修改序列化id的值

java关键字Transient

*Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。
transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。*

servlet是否线程安全(为什么你认为是/否)

对dubbo的理解(画下provider、consumer、注册中心、监控的关系)

  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务,并且缓存到本地
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

consumer1次调用provider,在dubbo内部各模块运转的流程

1.首先服务消费者通过代理对象 Proxy 发起远程调用

2.接着通过网络客户端 Client 将编码后的请求发送给服务提供方的网络层上,也就是 Server。

3.Server 在收到请求后,首先要做的事情是对数据包进行解码。然后将解码后的请求发送至分发器 Dispatcher,再由分发器将请求派发到指定的线程池上,最后由线程池调用具体的服务

谈谈你对mq的理解(你用的activemq,那kafka与之对比,有啥优势呢)

maven中install、package命令的区别

用过哪些设计模式,单例的懒汉、饿汉、线程安全的懒汉、最好的线程安全懒汉实现?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singletion{
//构造器私有
private Singleton{
}

//公开+静态的get方法
public static Singletion getSingleton(){
return Holder.instance;
}
//内部类 私有+静态+new
private static final class Holder{
private static Singleton instance = new Singleton();
}
}

int的位数

1.字节:byte:用来计量存储容量的一种计量单位;位:bit

2.一个字节等于8位 1byte = 8bit

char占用的是2个字节 16位,所以一个char类型的可以存储一个汉字。

整型:

byte:1个字节 8位 -128~127

short :2个字节 16位

int :4个字节 32位

long:8个字节 64位

浮点型:

float:4个字节 32 位

double :8个字节 64位

注:默认的是double类型,如3.14是double类型的,加后缀F(3.14F)则为float类型的。

char类型:

char:2个字节。

Boolean 类型

boolean: (true or false)(并未指明是多少字节 1字节 1位 4字节)

补充:BigInteger类实现了任意精度的整数运算,BigDecimal实现了任意精度的浮点数运算。

bitmap

1000W的数据,32的正整数 4个字节,40M,

如果用位图的话,1亿的只需要1亿个二进制位12M就够了

hashMap ConcurrentHashMap 区别,hash冲突如何解决的?

synchronized 和lock的区别,synchronized是悲观锁还是乐观锁,cas算法

https://km.sankuai.com/page/34303789

即compare and swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。CAS算法涉及到三个操作数

需要读写的内存值 V

进行比较的值 A

拟写入的新值 B

当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个自旋操作,即不断的重试。

3、谈谈threadLocal的理解、InheritableThreadLocal 、TransmittableThreadLocal 以及fastThreadLocal

参考答案:https://mlog.club/article/22197

ThreadLocal局限性:无法在父子线程之间传递;

InheritableThreadLocal:线程池不可用;

TransmittableThreadLocal:需要TtlExecutors

3、线程池

https://www.cnblogs.com/shijiaqi1066/p/3412300.html

1.创建一个线程时,查看核心线程数是不是已经满了,如果没有满创建一个核心线程

2.如果核心线程满了,查看队列是否已经满了,没有满就加入队列,等核心线程有空闲在执行

3.如果队列满了,查看,max是否超过了,如果没超过,就创建新的线程

4.如果超过了max,则执行对应的拒绝策略

4、请你说一下自己对于 AQS 原理的理解、

参考答案:https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/Multithread/AQS.md

5、CyclicBarrier 和 CountDownLatch 的区别

对于 CountDownLatch 来说,重点是“一个线程(多个线程)等待”,而其他的 N 个线程在完成“某件事情”之后,可以终止,也可以等待。而对于 CyclicBarrier,重点是多个线程,在任意一个线程没有完成,所有的线程都必须等待。

CountDownLatch 是计数器,线程完成一个记录一个,只不过计数不是递增而是递减,而 CyclicBarrier 更像是一个阀门,需要所有线程都到达,阀门才能打开,然后继续执行。

6、aop实现原理:动态代理、cglib,

两种实现有什么区别:基于接口、基于继承类

  1. JDK Proxy 是 Java 语言自带的功能,无需通过加载第三方类实现;
  2. Java 对 JDK Proxy 提供了稳定的支持,并且会持续的升级和更新 JDK Proxy,例如 Java 8 版本中的 JDK Proxy 性能相比于之前版本提升了很多;
  3. JDK Proxy 是通过拦截器加反射的方式实现的;
  4. JDK Proxy 只能代理继承接口的类;
  5. JDK Proxy 实现和调用起来比较简单;
  6. CGLib 是第三方提供的工具,基于 ASM 实现的,性能比较高;
  7. CGLib 无需通过接口来实现,它是通过实现子类的方式来完成调用的。

MyBatis中#与$的区别

${} 是 Properties 文件中的变量占位符,它可以用于标签属性值和 sql 内部,属于静态文本 替换,比如${driver}会被静态替换为 com.mysql.jdbc.Driver 。

#{} 是 sql 的参数占位符,Mybatis 会将 sql 中的 #{} 替换为?号,在 sql 执行前会使用 PreparedStatement 的参数设置方法,按序给 sql 的?号占位符设置参数值,比如 ps.setInt(0, parameterValue), #{item.name} 的取值方式为使用反射从参数对象中获取 item 对象的 name 属性值,相当于 param.getItem().getName() 。

jvm

1、描述下jvm内存模型

image-20200930173845666

2、JVM参数Xms Xmx是如何设置的, 如果大小是一至,为什么这样设置?

参考答案:

Xmx设置JVM 的最大可用内存,Xms 设置JVM实际使用内存,一般Xmx和Xms相同,这是因为当Xmx内存空间不够用时,将进行扩容导致Full GC。将Xmx和Xms设置成相同的值,避免因Xms偏小导致频繁重新分配内存,影响应用使用。

2、有遇到过OOM么,什么情况,怎么发现的,怎么查原因的?

考察点:jstat mat工具

3、如何定位一个CPU Load过高的java线程?

top -c

top -Hp pid

printf “%x\n” pid (将pid转换16进制表示的)

定位线程堆栈 jstack 29054 | grep ‘0x1a17’ -C30 —color

redis

分布式锁:一般,只是提到加超时时间

持久化:rdb、aof,可以

AOF更安全,可将数据及时同步到文件中,但需要较多的磁盘IO,AOF文件尺寸较大,文件内容恢复相对较慢, 也更完整。

RDB持久化,安全性较差,它是正常时期数据备份及 master-slave数据同步的最佳手段,文件尺寸较小,恢复数度较快。

缓存穿透:缓存穿透是指访问的key在缓存中存在,直接访问的DB,比如有恶意的黑客,故意访问数据库不存在的id,缓存中肯定不存在,压力就会集中在DB上

注意事项:大key

大 key解决方案

1.序列化压缩保存

2.拆分保存(有点分布式的意思)

hotKey解决方法

1.可以将这些热 key 进行分散处理,比如一个热 key 名字叫 hotkey,可以被分散为 hotkey#1、hotkey#2、hotkey#3,……hotkey#n(有点负载均衡的意思)

2.可以 key 的名字不变,对缓存提前进行多副本+多级结合的缓存架构设计。

3.如果热 key 较多,还可以通过监控体系对缓存的 SLA 实时监控,通过快速扩容来减少热 key 的冲击。

4.业务端还可以使用本地缓存,将这些热 key 记录在本地缓存,来减少对远程缓存的冲击。

redis过期时间,token,验证码之类的时间

定期删除和惰性删除

定期删除:redis默认是每隔 100ms 就随机抽取一些设置了过期时间的key,检查其是否过期, 如果过期就删除。注意这里是随机抽取的。为什么要随机呢?你想一想假如 redis 存了几十万 个 key ,每隔100ms就遍历所有的设置过期时间的 key 的话,就会给 CPU 带来很大的负载!

惰性删除 :定期删除可能会导致很多过期 key 到了时间并没有被删除掉。所以就有了惰性删 除。假如你的过期 key,靠定期删除没有被删除掉,还停留在内存里,除非你的系统去查一下那 个 key,才会被redis给删除掉。这就是所谓的惰性删除。

edis 提供 6种数据淘汰策略:

  1. volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

  2. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

  3. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

  4. allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是

    最常用的)

  5. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

  6. no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。

    这个应该没人使用吧!

4.0版本后增加以下两种:

  1. volatile-lfu:从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰
  2. allkeys-lfu:当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的key

设计模式

mysql

事务隔离级别:

读未提交:没提交就可以读取到

读提交:提交就能读取到

可重复读:

慢查询:

explain 查看扫描行行数,查看查询条件是否落在了索引上

mysql 常见存储引擎

myasiam

innodb

momory

聚簇索引和非聚簇索引的区别?

一般情况下主键会默认创建聚簇索引,且一张表只允许存在一个聚簇索引。

在《数据库原理》一书中是这么解释聚簇索引和非聚簇索引的区别的:
聚簇索引的叶子节点就是数据节点,而非聚簇索引的叶子节点仍然是索引节点,只不过有指向对应数据块的指针。

索引最左前缀:

分表:分表维度理解可以

数据迁移:停服务,mq双写

怎么保证迁移后数据正确:记录数,

mvcc :同一份数据临时保留多版本的一种方式,进而实现并发控制

生成全局 id 有下面这几种方式:

UUID:不适合作为主键,因为太⻓了,并且无序不可读,查询效率低。比􏰀适合用于生成唯一的 名字的标示比如文件的名字。
数据库自增 id : 两台数据库分别设置不同步⻓,生成不重复ID的策略来实现高可用。这种方式 生成的 id 有序,但是需要独立部署数据库实例,成本高,还会有性能瓶颈。

利用 redis 生成 id : 性能比􏰀好,灵活方便,不依赖于数据库。但是,引入了新的组件造成 系统更加复杂,可用性降低,编码更加复杂,增加了系统成本。

Twittersnowflake算法 :Github 地址:https://github.com/twitter-archive/snowflake。

美团的Leaf分布式ID生成系统 :Leaf 是美团开源的分布式ID生成器,能保证全局唯一性、趋势 递增、单调递增、信息安全,里面也提到了几种分布式方案的对比,但也需要依赖关系数据库、 Zookeeper等中间件。感觉还不错。美团技术团队的一篇文章:https://tech.meituan.com/2017 /04/21/mt-leaf.html 。

算法:

1、螺旋打印矩阵

https://leetcode-cn.com/problems/spiral-matrix/solution/luo-xuan-ju-zhen-by-leetcode/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> order = new ArrayList<Integer>();
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return order;
}
int rows = matrix.length, columns = matrix[0].length;
boolean[][] visited = new boolean[rows][columns];
int total = rows * columns;
int row = 0, column = 0;
int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
int directionIndex = 0;
for (int i = 0; i < total; i++) {
order.add(matrix[row][column]);
visited[row][column] = true;
int nextRow = row + directions[directionIndex][0], nextColumn = column + directions[directionIndex][1];
if (nextRow < 0 || nextRow >= rows || nextColumn < 0 || nextColumn >= columns || visited[nextRow][nextColumn]) {
directionIndex = (directionIndex + 1) % 4;
}
row += directions[directionIndex][0];
column += directions[directionIndex][1];
}
return order;
}

2、倒叙速出

主动学习:看过什么书,印象深的点是什么?如何自我学习?

Springboot学习,大V的学习问题解决思路;自己做笔记!

文章目录
  1. 1. 程序员必备知识点
    1. 1.1. 1、tcp 三次握手,四次挥手
    2. 1.2. 2、tcp 拆包、粘包问题。
      1. 1.2.1. 粘包、拆包解决办法
    3. 1.3. 3、linux io 类型。
    4. 1.4. 4、线程reactor 模型。
  2. 2. Java基础
    1. 2.1. ArrayList源码
    2. 2.2. HashMap源码
    3. 2.3. ConcurrentHashMap源码
    4. 2.4. 线程池ThreadPool
    5. 2.5. synthronized, volatile, Lock的使用和区别
    6. 2.6. NIO实现
    7. 2.7. 工厂,代理,单例模式(单例模式多线程问题)
    8. 2.8. cglib与proxy的使用和区别
    9. 2.9. Java可重入锁和读写锁
    10. 2.10. JVM内存模型
    11. 2.11. JVM GC机制和相关算法
    12. 2.12. JVM类的加载
    13. 2.13. JVM性能调优的大体步骤
    14. 2.14. CAS算法
      1. 2.14.1. CAS的缺点:
    15. 2.15. 一致性Hash
    16. 2.16. arrayList底层结构,linkedList底层结构,两者的区别(RandomAccess)
    17. 2.17. hashmap底层结构(java8版本),concurrentHashMap(java8版本)、hashTable,三兄弟对比下吧?
    18. 2.18. nio和bio相比有啥不同(aio呢)
    19. 2.19. jvm内存划分(java8版本呢?),堆的划分(系统遇到瓶颈,确定是JVM引起,怎么调优,说下具体做法)
    20. 2.20. 成员变量、局部变量等等的会分配到jvm的哪块儿区域
    21. 2.21. mysql的引擎知道哪些,有啥区别
    22. 2.22. 乐观锁、悲观锁
    23. 2.23. 索引相关的(btree、失效、组合索引的最左分配原则、explain使用)
    24. 2.24. 线程池相关
      1. 2.24.1. 四种拒绝策略
    25. 2.25. volatile关键字
    26. 2.26. lock的读写、中断、自旋
    27. 2.27. 对threadLocal的理解
    28. 2.28. 序列化、反序列化(一个已经实现Serializable的类,新增个属性,怎样让程序直接报错)
    29. 2.29. java关键字Transient
    30. 2.30. servlet是否线程安全(为什么你认为是/否)
    31. 2.31. 对dubbo的理解(画下provider、consumer、注册中心、监控的关系)
    32. 2.32. consumer1次调用provider,在dubbo内部各模块运转的流程
    33. 2.33. 谈谈你对mq的理解(你用的activemq,那kafka与之对比,有啥优势呢)
    34. 2.34. maven中install、package命令的区别
    35. 2.35. 用过哪些设计模式,单例的懒汉、饿汉、线程安全的懒汉、最好的线程安全懒汉实现?
    36. 2.36. int的位数
    37. 2.37. bitmap
    38. 2.38. hashMap ConcurrentHashMap 区别,hash冲突如何解决的?
    39. 2.39. synchronized 和lock的区别,synchronized是悲观锁还是乐观锁,cas算法
    40. 2.40. 3、谈谈threadLocal的理解、InheritableThreadLocal 、TransmittableThreadLocal 以及fastThreadLocal
      1. 2.40.1. ThreadLocal局限性:无法在父子线程之间传递;
      2. 2.40.2. InheritableThreadLocal:线程池不可用;
      3. 2.40.3. TransmittableThreadLocal:需要TtlExecutors
    41. 2.41. 3、线程池
    42. 2.42. 4、请你说一下自己对于 AQS 原理的理解、
    43. 2.43. 5、CyclicBarrier 和 CountDownLatch 的区别
    44. 2.44. 6、aop实现原理:动态代理、cglib,
    45. 2.45. MyBatis中#与$的区别
  3. 3. jvm
    1. 3.1. 1、描述下jvm内存模型
    2. 3.2. 2、JVM参数Xms Xmx是如何设置的, 如果大小是一至,为什么这样设置?
    3. 3.3. 2、有遇到过OOM么,什么情况,怎么发现的,怎么查原因的?
    4. 3.4. 3、如何定位一个CPU Load过高的java线程?
  4. 4. redis
    1. 4.1. 大 key解决方案
    2. 4.2. hotKey解决方法
    3. 4.3. 定期删除和惰性删除
  5. 5. 设计模式
  6. 6. mysql
    1. 6.1. 聚簇索引和非聚簇索引的区别?
    2. 6.2. 生成全局 id 有下面这几种方式:
  7. 7. 算法:
|