Java服务端开发知识总结

# Java

## 中间件

### redis

- redis的数据结构和应用场景

    - redis的数据结构

        - dict

            -   dictht ht[2];

                -  dictEntry **table;

                    - dictEntry *next

            - 渐进式rehash

                - 为ht[1]分配空间,同时持有ht[0]和ht[1],将rehashidx设为0

 rehash期间,每次对字典执行任意操作时,除了执行对应操作之外,还将ht[0]在rehashidx索引上的键值对rehash到ht[1],随后rehashidx+1

直到rehashidx增加到ht[0].size,此时ht[0]的所有键值都迁移到ht[1],rehashidx重置为-1,rehash完成

rehash的过程中,ht[0]和ht[1]可能同时存在键值对,因此在执行查询操作的时候两个哈希表都得查,而如果是执行插入键值对操作,则直接在ht[1]上操作就行。

                - ht[0]只会减少不会增加
                - https://blog.csdn.net/llllllkkkkkooooo/article/details/115141263

            - https://blog.csdn.net/cxc576502021/article/details/82974940
            - https://tech.meituan.com/2018/07/27/redis-rehash-practice-optimization.html
            - https://www.cnblogs.com/jeemzz/p/11440923.html

        - String
        - list

            - 双端链表

                - ziplist

        - set
        - hash
        - zset

            -  skiplist 

        - https://blog.csdn.net/yangbodong22011/article/details/78467583

    - 数据结构存储

        - https://blog.csdn.net/weixin_34942265/article/details/113581423

    - redis 锁

        - 简单的锁,基于setnx 带ex
        - 有多个命令,如何保证原子性(事务、pipeline、lua脚本)
        - redisson可重入、自旋、

            - 公平锁

                - redisson_lock_queue
                - redisson_lock_timeout

            - https://blog.csdn.net/Howinfun/article/details/121366238

        - redlock

            - 利用多个 Redis 集群,用多数的集群加锁成功,减少 Redis 某个集群出故障

    - 缓存

        - 缓存穿透

            - 增加空缓存

        - 雪崩

            - 加锁建立缓存

        - 击穿

            - ttl随机化

    - 用redis实现

        - 排行榜
        - 延迟队列
        - 任务分发队列

    - set和string存json,用起来有什么区别?

        - hmset和直接set string 性能区别
        - 判断一个值在不在集合里面 性能区别

- redis事务

    - watch MULTI exec

        - 乐观锁

- redis的内存用完时会怎么样

    - 有哪些淘汰机制

        - allkeys-lru
        - volatile-lru

            - 从已设置过期时间的挑选

    - redis是如何清理的?

        - 懒删除
        - 扫描

    - 如何提高内存使用效率

- redis可靠性

    - rdb快照
    - AOF日志
    - 双云

- redis的部署模式有哪些?你们项目使用哪种?规模有多大?

    - 集群模式

        - 20主20从
        - 双az通过kafka同步
        - gossip协议

            - meet、ping、pong、fail
            - redis集群过大,会导致内部通讯的开销越来越多
            - 16379端口

        - 一致性hash

            - 哈希环
            - 虚拟节点

        - slot分区

            - crc16(key)%16384
            - slot分配给节点

                - reshard 

        - 如何扩容

            - 如何数据同步
            - 数据恢复

    - 哨兵

- redis单节点的qps有多少

    - redis为什么快?

        - 数据存放在内存中,cpu内存寻址读取很快
        - 使用dictht数据结构,指数级时间复杂度
        - reactive模式,io多路复用

    - 热点key问题

        - 热key会导致redis集群汇总一个节点的延迟升高,进而导致调用方的连接池大量阻塞在这个缓慢节点的调用上,导致连接池耗尽。
        - 副本key
        - 内存缓存

            - caffeine本地缓存

                - 如何保证一致性

    - redis集群模式,每个客户端都和每个redis节点建立连接吗

        -  连接池配置了1000个连接,在Java程序启动的时候并不会创建1000个,在使用的时候根据需要来创建,最多只能创建1000个。
   
        -  如果Redis集群如果很大,比如存在1000个master节点,那么连接池最大只能设置60个左右,因为操作系统最多只能维护65535个tcp端口,而java程序最大情况下需要向每个master节点都创建60个连接,在这种情况下创建的连接个数为60*1000=60000个连接,基本耗尽了可用的tcp端口。

- redis大key是什么

    - 为什么不建议大key

        - 内存不均衡,出现节点内存耗尽
        - 网络io
        - 单线程影响其他命令响应

- redis的key的存储

    - 一个实例最多能放多少个key?(2^32个)

        - https://zhuanlan.zhihu.com/p/43462366

    - rehash的过程是什么样的

        - https://blog.csdn.net/belalds/article/details/93713491

    - redis最新版本使用了多线程

        - https://www.cnblogs.com/mumage/p/12832766.html

### mysql

- 索引

    - 物理结构:b+tree,page

        - 索引的长度太长会有什么影响

    - 索引的最左原则

        - idx(a,b,c) : where a=xx and c = xx是否走索引?

    - 索引覆盖
    - 聚簇索引,回表
    - 什么情况下建索引

        - 数据离散,且离散程度好的放在前
        - 字段变化次数相对于查询次数较少

    - 索引失效

- mysql的单表大小、为什么要控制大小?

    - 分表、分库的实现方法
    - b+tree的存储计算

        - 系统的块是4k,innodb的页是16k
        - innodb指针6byte、主键bigInteger 8byte
        - 假如行数据1kb

            - 非叶子单page:16k/(8+6)=1170

                - 如果树高3:1170*1170*16约等于2200万 

            - 叶子单page:16k/1k

        - https://www.cnblogs.com/leefreeman/p/8315844.html

- 主键

    - 自增Id

        - 好处是生成快、省索引空间,坏处是只能单表、对外场景会暴露业务量。

    - UUID

        - uuid、guid,好处是全局唯一,坏处是占空间影响性能、无序、当然也无法范围查询。

    - 雪花算法

        - 好处是按时间有序、可以自己搞生成规则,在id里面嵌入分表号。缺点是时间如果往前拨,会引起主键冲突。

- 时区问题如何解决

    - java服务器时间、msyq服务器时间、连接串时区如何匹配
    - 夏令时

- acid

    - atomic

        - undo log 回滚

    - consistent

        - binlog

            - 存储引擎的上层产生的,不管是什么存储引擎,对数据库进行了修改都会产生二进制日志
            - Statement
            - Row
            - Mixedlevel

    - isolation

        - 三个问题

            - 脏读

                - A事务读到其他事务修改但未提交的数据

            - 不可重复读

                - A事务过程中对同一条数据两次相同查询结果不一样

            - 幻读

                - A事务过程中,两次范围查询的结果条数不一样

        - 事务的四个隔离级别

            - 读未提交
            - 读已提交
            - 可重复读

                - 可能幻读

                    - 使用范围锁

            - 串行化

        - 写操作对另一个事务写操作:锁
        - 写操作对另一个事务读操作:MVCC

    - durable

        - buffer pool中保存了page的缓存,优先读写缓存,异步刷新到磁盘中。
        - 为了crash recovery,引入了redo log,先写log再写缓存。

            - https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html
            - innodb层产生
            - 以块为单位进行存储,记录page的变化

        - redo log恢复

            - lsn:log sequence number
            - check point: 触发脏页刷盘
            - 数据页lsn小于redo log lsn

                - 子主题 1

        - https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html

- 事务

    - 事务如何能保证RR

        - mvcc

            - 数据行隐藏列:中包含了事务Id, Undo Log指针, undo Log中有一条版本链
            - 事务第一次读取前生成readView,获取事务系统trx_sys快照。读行数据的时候,先对比行数据事务id和快照
            - trx_sys

                - low_limit_id:下一个新事务Id

                    - 如果行数据事务Id比low更大,说明快照时,事务未开始,找undo log

                - up_limit_id:活跃中的事务最小的id

                    - 如果行数据事务Id比up_limit_id更小,说明事务已经提交,对ReadView可见

                - rw_trx_ids: 活跃中的事务Id列表

                    - 如果行数据事务Id不在列,说明已经提交,可见
                    - 如果存在,说明不可见,找undo log

            - undolog

                - 逻辑日志:记录反向操作
                - 是采用段(segment)存储

                    - 每个undo操作在记录的时候占用一个undo log segment
                    - rollback segment称为回滚段,每个有1024个undo log segment。
                    - 存放在共享表空间

        - 行锁、行间锁、间隙锁

    - https://www.cnblogs.com/kismetv/p/10331633.html
    - 分布式事务

- alter table加字段会锁表吗

    - 5,6之后 更改字段类型会锁表

        - https://www.shiqidu.com/d/940

### kafka

- 基本结构

    - producer
    - consumer
    - broker

        - 实际的kafka物理节点

    - topic
    - partition

        - 一个topic可以有多个partition
        - 一个broker可以放多个partition
        - topic的每个partition在一个group中的消费者是唯一的,group+topic+partition保持一个offset

            - 如果消费者比partition多,多的消费者会闲置
            - 一个partiton就是一个独立的log文件,数据写入是顺序的,磁盘利用高,partition太多打开的文件就多,顺序性就可能变成随机写,影响磁盘吞吐

        - 一个消费者可能消费多个partition
        - partition副本(AR)

            - Leader Follower
            - 同步副本ISR

                - LSO log start offset
                - 高水位HW

                    - 已经同步的

                - LEO:Log End Offset 

            - OSR

                - out of sync replica

        - partition key

            - 相同的partition key会落到同一个partition,在同一个partition消费有序

    - 什么情况会消息丢失、如何避免

        - 避免发送失败

            - 重试

                - ack=0 不重试
                - ack=1 只等待leader成功
                - ack >1 等待leader和若干个isr写入成功
                - ack=-1、all 等待全部ISR写入成功

                    - min.insync.replicas >1 

                        - 至少要有x个isr,否则抛异常

            - unclean.leader.election.enable=true

                - 不允许OSR成为leader,防止丢HW到LEO之间的消息

            - 异常处理,持久化发送失败消息,重试

        - 避免消费失败

            - 先消费再commit

                - 可能导致重复消费

            - 死信队列

    - 什么情况会重复消费、如何避免

        - 拉多条消息,消费时异常,导致未commit

            - 在使用auto commit时尤其有可能

        - 消费超时,超过max.poll.interval.ms、触发rebalance,另一个节点又拉消息重复消费
        - 加快消费速度、减少消息拉取数量、增大超时时间、消费幂等去重机制

- zk在kafka中起什么作用(答案为老版本)

    - /broker/ids 维护broker信息
    - /broker/topics/ 维护所有topic消息,以及每个topic下的partitions信息。每个partition有个state节点,维持leader分区、ISR的brokerId等。
    - /consumers/{group_id}/owners/{topic}/{broker-id.partition_id}消费者和partition的注册关系
    - /consumers/{group_id}/offsets/{topic}/{broker-id.partition_id} 消费offset(老版本是这么做的,新版本存放在 Kafka 集群中的一个叫 __consumer_offsets 的topic中

- kafka的存储结构
- kafka性能好的原因

    - 顺序append写入,按segment存储
    - 零拷贝,不走用户态,直接在内核态传输

- 消息堆积如何处理
- 如何提升写入性能、消费性能
- rebalance

    - when

        - 消费者数量变化
        - 消费者消费超时
        - 分区数变化
        - group订阅的topic变化

    - how

        - coordinator

            - partition的leader所在的broker一般就是协调者
            - 负责监控group中的consumer的心跳

        - 超时:coordinater从组里面选举产生新的leader,leader发送syncGroup给coordinater,coordinator通过心跳下发syncgroup
        - 数量变化:由leader consumer通知coordinator

    - rebalance会标记一个generation给consumer,提交offset时,会比较。从而防止rebalance前提后重复提交的问题。

### zk

- 应用

    - 锁

        - zk作分布式锁和redis 做分布式锁的区别

            - zk如何实现公平锁(临时顺序节点)

                - https://www.nowcoder.com/discuss/205156?type=1

    - 注册中心

        - zk和eureka作为注册中心的区别

            - Zk强调CP

                - 当zk的节点失效时,会进行崩溃回复,进行leader选举,期间zk服务不可用

            - eureka强调AP

                - eureka的集群是平等的,某个节点的故障不会影响其他节点提供注册和查询服务。eureka如果发现85%的服务心跳丢失,就会进入保护模式。

    - 消息通知
    - 配置管理

        - 配置信息保存在znode中,znode变化时通过watch通知各个客户端,从而更改配置

    - 集群管理

        - 监控集群机器状态,加入和剔除(断连的机器临时目录被删除,其他所有机器都收到通知

- kafka为什么依赖zk

    - https://www.cnblogs.com/TM0831/p/13386184.html

- zk集群是什么结构:https://www.cnblogs.com/TM0831/p/13386184.html

    - znode

        - 既是数据文件也是目录,每个节点最大存1MB
        - 原子性,读会读全部、写会替换节点

    - 持久节点
    - 临时节点

        - 客户端断开就会删掉

- zab协议

    - 消息广播

        - 写操作都会路由到leader节点,转换为proposal,广播给follower。当超过半数follower反馈后,广播commit

    - 崩溃恢复

        - 初始化、leader节点故障、leader与超过半数节点断连时,会进行leader选举

    - 节点的三种状态

        - leading
        - following
        - election

    - zxid

        - 高32位叫做epoch,周期Id,每次有新的leader选举的时候,都会+1
        - 低32位是自增计数器,每次事务请求都加1

- watch机制

    - 客户端可以watch某个znode的变化,当znode变化时,会通知客户端这个事件(不会告知内容,只通知事件

        - 父节点的创建修改删除会触发watch
        - 子节点的创建删除会触发

    - 1、客户端像zk注册watcher,并把监听

### es

- 如何保证和主数据仓比如mysql的一致性

## java特性

### jdk 8 stream、future等

### 数据结构

- arraylist

    - 数组,随机访问性能好,插入删除较差,尤其是需要移动数据的时候
    - new ArrayList(20) 不放数据的话,实际上此时内部数组还是空的,get会报越界。

- linkedList

    - 双向链表,随机访问性能差,O(1)插入删除

- HashMap

    - 初始数组长度16,负载因子0.75,大于16*0.75时会扩容,容量扩展一倍

        - 如果能预估出大小,就在建立hashmap的时候指定大小,可以提高效率

    - 存储结构

        - 初始:数组+链表
        - 链表较长时put:数组+红黑树

            - resize和remove时,如果小于6,会退化为链表

        - 对象的hashcode(定位数组)和equals(判重)方法

            - 重写equals必须重写hashCode方法

    - put过程

        - hash: key.hashCode 高16位于低16位异或

            - 原因是初始数组大小为16,只有低4位参与运算
            - 通过高低位异或,扩大参与的位数,增强散列度

        - treefy:链表binCount 大于TREEFY_THRESHOLD(8)时

            - 如果数组长度小于64,只resize
            - 否则treefy这个链表,转为红黑树

        - resize: map.size 大于数组长度*负载因子

            - 数组的每个槽位会拆分为low、hi

    - 并发问题

        - hashmap在1.7的时候,并发put,扩容rehash中会对链表倒序,可能出现环形链表,导致死循环,1.8不会有这个问题
        - 1.8 put ++size非原子,可能导致丢失数据

            - 抛出ConcurrentModificationException

        - concurrentHashMap

            - 1.7使用分段锁:划分16个segment,嵌套了一层,所以极限是16个并发
            - 1.8使用synchronized,按槽位的粒度控制

                - 如果槽位为空,使用cas

- priorityQueue
- TreeSet
- 布隆过滤器
- bitmap

### 常量

- String、StringBuilder、StringBuffer

    - String是不可变类型,每次都会创建新的String对象,并且会在常量池缓存
    - StringBuffer是线程安全的

- String ==,equas,new String("123"),"123"

    - hashcode重载

- integer -128到127
- 对象放int和integer的区别

### jvm

- jvm参数

    - flume
    - tomcat

        - -XX:MaxMetaspaceSize=512m -XX:MetaspaceSize=256M -XX:+UseG1GC -XX:+PrintGCDateStamps -XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -Xms3967M -Xmx3967M -XX:OnOutOfMemoryError=xxx

- JVM内存模型

    - jvm stacks
    - native method stacks
    - metaspace

        - 常量池

            - 1.8的String在这里

        - 方法元信息

    - heap

        - young

            - eden

                - minor gc

                    - eden+from -> to
                    - 经过若干次回收依然存活的,会进入老年代
                    - 假如垃圾产生的速度过快或者大对象,会直接进入老年代

            - survivor

                - from
                - to

                    - young区的三个区域的内存一般是8:1:1

            - young区一般占堆区的三分之一

        - old

            - tenured

                - full gc

        - 一个请求中对象的产生到消亡的过程,在各个jvm内存区域的流动过程
        - qps高时,对象的生命周期会有什么变化?为什么会出现fgc?

- java内存模型jmm

    - 主内存和工作内存,线程对变量的操作在工作内存进行,工作内存存放该线程读写变量的副本
    - 可见性
    - 重排序

        - happens-before

    - volatile:保证可见性,禁止重排序

- jvm运维命令

    - jstat gcutil pid

        - 查看gc统计、内存使用

    - jps

        - 查看java进程

    - jmap

        - 定位oom、major gc等问题

    - jstack

        - 定位死锁、线程池占用等问题

    - OOM问题如何定位

        - jmap -dump:format=b,file=/usr/local/base/02.hprof 12942
        - 自动oom dump:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/base
        - 使用mat分析dump文件
        - 一般业务造成的oom,看huawei开头的类,哪个实例比较多
        - 找到path to gc roots

- gc roots

    - 方法区的静态属性引用、常量引用
    - 栈中引用对象
    - 本地方法栈中JNI引用对象

- 常用的gc算法

    - g1

        - https://www.cnblogs.com/lsgxeva/p/10231201.html
        - region

            - 基于region:将堆内存分为比如2048个相同大小的区,大小可以在1M到32M,分区时不区分young和old

                - 大对象

                    - TLAB(Thread Local Allocation Buffer)线程本地分配缓冲区
                    - 子Eden区中分配 
                    - Humongous 区:如果一个h区存不下,就要找连续的h区,为了找到连续的h区,就可能触发full gc

            - 跟踪各个Region 的垃圾堆积价值,即垃圾对象占比越多的Region回收的收益越大,优先回收价值最大的region
            - 清理时,将对象从一个区域复制到另一个区域,同时完成了压缩,不会有碎片内存

        - 停顿时间模型

            - 设定目标停顿时间

                - -XX:+UseG1GC -Xmx32g -XX:MaxGCPauseMillis=200

            - 根据前几次回收Region所用时间来估算要回收哪些Region,用最小的时间获取最大收益

        - rememberSet

            - 使用cardTable作为RS
            - 每个Region都有自己的cardTable,记录来自其他Region的引用

        - gc过程

            - youngc

                - 过程

                    - 根扫描

                        - 静态和本地对象被扫描

                    - 更新remembered set

                        - RS

                            - 作用是跟踪指向某个heap区内的对象引用

                    - 处理RS
                    - 对象拷贝

                        - eden+survivor -> survivor
                        - survivor->survivor
                        - survivor->old

                    - 处理弱引用、虚引用

            - mix gc

                - 过程

                    - 全局并发标记

                        - 初始标记(stw

                            - 对gc根标记

                        - 根区域扫描

                            - 初始标记的存活区扫描对老年代的引用,并标记被引用的对象

                        - 并发标记:三色标记算法

                            - 黑色:根对象,或者该对象与它的子对象都被扫描
                            - 灰色:对象本身被扫描,但还没扫描完该对象中的子对象
                            - 白色:未被扫描对象,扫描完成所有对象之后,最终为白色的为不可达对象,即垃圾对象

                        - 最终标记
                        - 清除垃圾

                    - 拷贝存活对象

    - cms

        - 单线程,且会产生内存碎片
        - 适用于老年代:标记清除法

    - 如果取舍

        - g1的内存占用和cpu比cms高
        - g1如果目标时间过小,可能导致垃圾堆积
        - g1适合内存大的场景,至少4g
        - g1内存没有碎片,停顿时间可控

### 对象

- 对象头

    - mark word
    - 类指针
    - 数组对象长度

- 实例数据
- 对齐填充字节

    - 补齐到8bit的倍数

### class类文件

- magic

    - 文件类型

- version

    - jdk版本

- constant pool
- ..Fields
- Methods
- https://www.jianshu.com/p/4d89f803396a

### juc

- 线程池

    - 线程的创建和销毁开销很大

        - 线程栈是需要分配空间的
        - -Xss128K
        - 内存-堆区)\栈大小,再多会OOM
        - https://blog.csdn.net/z69183787/article/details/100098725

    - 操作系统限制 

        -      /proc/sys/kernel/pid_max

        /proc/sys/kernel/thread-max

        max_user_process(ulimit -u)

    - restTemplate底层是httpclient

        - io时阻塞,让出cpu、不让出线程

    - io多路复用+aio/nio

        - 把io密集型转化成cpu密集型
        - 这就是为何select、poll 、epoll、nginx可以用很少的线程可以获得极大吞吐量的原因

    - 参数

        - PoolSize 

            - core
            - max

        - keepAliveTime 
        - workQueue
        - threadFactory
        - handler

    - 核心线程 corePoolSize 、任务队列 workQueue (满了才会扩大)、最大线程 maximumPoolSize ,如果三者都满了,使用 handler处理被拒绝的任务。

当线程池中的线程数量大于 corePoolSize 时,如果某线程空闲时间超过 keepAliveTime ,线程将被终止。
    - 计算密集型,最好不超过N*CPU IO密集型可以到2N*CPU

        - 实际上tomcat的线程池默认都是200了

    - 异常处理

        - 在runnable逻辑中使用try catch
        - 设置uncaughtExceptionHandler

            - 只适用于excute,submit不能捕获

- io

    - aio bio nio

- wait、sleep

    - wait只能在synchronized中使用,

- sleep、join、interrupt

    - https://blog.csdn.net/weixin_43190941/article/details/82914348
    - interrupt只会改变标记,需要被中断线程调用isInterrupted()进行检查
    - 如果处于阻塞(sleep),会抛出InterruptedException

- synchronized

    - 加锁对象

        - 修饰静态方式时,加锁的是类
        - 修饰非静态方法时,加锁的是this对象
        - 修饰对象时,加锁的是对象

    - 可重入,不可中断、非公平
    - 对象头Mark Word,

        - 锁标记位:最后两个bit
        - 偏向锁:

            - 当一个线程竞争时
            - 记录获得偏向的线程Id

        - 轻量锁

            - 当两个线程竞争时,其他线程会通过自旋方式获取锁,轻量锁是不阻塞的,通过自旋+Cas获取锁
            - 线程栈帧中建立lock record:存储锁对象的Mark Word的拷贝
            - CAS尝试将mark word的指针指向lock record,成功即获取锁。或者mark word的指向就是当前线程的锁记录,说明是重入。

        - 重量锁

            - 当等待轻量锁的线程自旋超过一定次数,或者有第三线程竞争时,会升级为重量锁
            - 指向Monitor对象

                - owner

                    - 获得monitor对象的线程或者锁

                - WaitSet

                    - 调用wait方法后处于wait状态的线程,被加入到这个linkedList

                - EntryList 

                    - 等待锁block状态的线程的队列

                - recursions

                    - 重入次数

                - monitor基于操作系统的mutex lock实现,需要从用户态切换到和形态,因此效率不高

            - 上锁

                - owner字段CAS操作,如果owner为空,赋值指向自己,获取锁后recursions++

            - 释放锁

                -  monitorexit,recursions--,如果计数为 0,则 monitor owner置空

    - wait只能在synchronized中使用,调用加锁对象的notify方法可以唤醒
    - synchronized的锁升级

        - https://my.oschina.net/u/4591203/blog/4410947
        - 无锁->偏向->轻量锁->自旋->重量锁
        - 子主题 3

- aqs

    - reentrantLock

        - 可重入、可中断、公平
        - condition

            -       lock = new ReentrantLock();
        condition1 = lock.newCondition();
            - condition.await()
            - condition.signal()

    - Semaphore

        - new Semaphore(10)
        - acquire
        - release
        - 非公平

    - countDownLatch

- 异步请求

    - completableFuture

### spring

- aop

    - Spring AOP

        - PointCut

            - 注解

                - 定义

                    - @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Inherited
public @interface Cache 

                - @Aspect
@Pointcut("@annotation(xx.Cache)")
    public void cachePointCut() {
    }

            - 类方法

                - @Pointcut("execution(* com.abc.service.*.many*(..))"

        - Advice

            - @Aspect
@Around("cachePointCut()")
    public Object handleCache(ProceedingJoinPoint joinPoint) {

        - Spring Aop都是使用动态代理实现的,使用了aspectJ的注解
        - 同时配置多个切面 @Order(1) 越小优先级越高 
        - Spring AOP的介绍https://zhuanlan.zhihu.com/p/29483023

    - 动态代理

        - 类

            - JDK动态代理

                - 如果实现了接口,默认使用
                - 切面实现 InvocationHandler
                - Proxy.newProxyInstance(loader, interfaces, this)创建代理对象

            - cglib

                - 切面实现MethodInterceptor
                - enhancer.create创建代理对象
                - 底层通过asm实现,具备缓存,效率较好

        -  JDK动态代理和CGLIB动态代理的示例www.freesion.com/article/7543522446/

    - 静态代理

        - aspectJ:基于预编译

            - 编写XXAspect.aj
            - 使用ajc编译织入

                - ajc -d . xxx.java xxx.aj

        - 优势:性能更好
        - 使用AspectJ的示例https://www.jianshu.com/p/aa293edba2e4

- ioc

    - 通过反射,维护一个bean容器上下文

- 事务注解

### 动态代理

- 接口:动态代理
- 类:cglib,运行时生成子类

### threadlocal

- 使用场景

    - 隐藏传递一些header内容
    - 传递traceId、事务Id

- 语法

    - ThreadLocal<Context> threadLocal = new ThreadLocal<>();
    - threadLocal.set(context)

        - threadlocal.get()

    - new 两个threadLocal对象,即使在同一个线程,作为key也是不同的

- 问题

    - 内存泄漏

        - threadlocal继承weakReference,当Threadlocal对象作为Entry的key被gc,对象会内存泄漏
        - 引用链:Thread -> ThreaLocalMap -> Entry[]
        - Entry extends WeakReference<ThreadLocal<?>>
        -  Entry(ThreadLocal<?> k, Object v)

            - key:ThreadLocal<?> k为弱引用,会被gc回收,但是value还被强引用。
            - 如果线程一直存在,比如线程池,那么value的强引用一直存在,内存泄漏

        - 解决方法

            - 主动调用ThreadLocal.remove
            - 将ThreadLocal变量定义成static,一直存在ThreadLocal的强引用

    - 强引用 gc roots
    - 父子线程

        - 子线程

### applicationContext

### springMVC 请求路由过程

### 自定义类加载器

- 热部署:继承ClassLoader,实现loadClass方法,比如获取文件流,调用defineClass创建类。

    - 如果自定义的找不到,会尝试父类

- nuwa 依赖隔离

    - 每个中间件的classloader各自加载自己的版本的同一个类路径的类

- 代码保护:加密

## shell定位问题常用命令

### 如何在日志中找关键字、以及其上下行内容

### 如何用命令统计请求日志中某个接口的qps?如何对接口请求量排序

### 查看cpu信息

-  lscpu

    - 8C16t 3.0ghz

- cat /proc/meminfo 

    - 16GB

## 计算机、网络常识

### 线程池的概念、主要参数

### 网络模型(http和tcp和ip分别在那一层

## 微服务

### 限流、熔断、降级区别

- 熔断:快速失败,避免故障扩散。比如抢购时返回系统繁忙请重试,一般用超时请求计数判断。
- 降级:在系统过载时提供有损服务,从而降低负载。比如评论的es查询降级到mysql,可以手动配置,也可以根据tps\响应时间和失败率降级
- 限流:在系统过载时主动丢弃部分业务请求。被调方判断,比如appinfo单服务调用qps有限制

    - 限流的表现形式可以是拒绝服务、或者降级

- 隔离

### hystrix

- HystrixCommand

    - setter

        - GroupKey
        - CommandKey
        - ThreadPoolKey
        - 超时、错误

            - ExecutionTimeoutInMilliseconds
            - CircuitBreakerErrorThresholdPercentage
            - CircuitBreakerRequestVolumeThreshold

        - 线程池配置

- HystrixObservableCommand
- 隔离

    - 线程池
    - 信号量

### rpc比http好在哪里

## 设计

### 秒杀系统

- 缓存:页面静态化预热到cdn、数据预热到缓存缓存、最好用本地缓存、排查redis单key问题
- 库存:写入redis,通过原子操作对库存进行减少。库存在每台服务器本地做计数,如果超过总量的一定比例直接失败。
- 客户端:校验系统时间、校验登录、点击频率限制
- 服务端:秒杀开始前的请求直接失败,量大的ip、账号可计入黑名单。

    - 秒杀时间到,请求涌入,负载均衡到各个服务器;写入消息队列削峰,接口快速返回提示:正在抢购中,客户端保持在这个界面,等一会儿再查结果
    - 接口端幂等设计;url动态化,加入随机数让人无法提前猜到;加入token,一次消耗,防刷

- 服务器连接数放开

### 海量数据排序

- 评论墙、热帖榜

    - 定时任务:切片,各自排一小部分,取前面的写入redis zset汇聚,做二次排序

### 推荐

- 召回:根据特征向量取数据
- 用户模型
- 粗排、精排、调整

## 算法

### 二分查找

- 递归
- 循环

### DFS、BFS

### 动态规划

- 0-1背包问题

### tsp问题

### 最短路径

- 弗洛伊德算法

    - 三层循环(点、邻接矩阵)
    - 多源点

- 地杰斯特拉

    - 单原点
    - 每次找距离最近的没访问过点,松弛各条边

### 字典树

### 字符串转double(soul

### leetcode

- 回文(PDD
- 42.trapping train water
- 31.next permutation
- 最长上升子序列
- 最大连续和

## rx java

### https://juejin.cn/post/6844903447280484360

### https://blog.csdn.net/qq_26787115/article/details/65629072

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值