学习路线图
2019-12-20 13:51:21 5 举报
AI智能生成
java 架构 学习笔记
作者其他创作
大纲/内容
项目实践方案
分布式调用链
日志调用链
日志埋点
电商系统
电商架构核心技术点
淘宝后端架构变迁史
京东后端架构变迁史
电商微服务拆分
库存服务
订单服务
会员服务
支付服务
商品服务
SPU
商品单元
SKU
SPU+属性+价格 + 数量= SKU
营销服务
技术解决方案
分布式解决方案
分布式锁
分布式事务
分布式调度中心
分布式配置中心
分布式序列号
分布式session
分布式存储
SSO服务
同域单点登录
跨域单点登录
高并发秒杀系统
redis与JVM多级缓存
亿级流量详情页多级缓存方案
缓存穿透,缓存击穿,缓存雪崩,热点缓存重建
本地缓存
cache4j
oscache
guava cache
消息中间件消峰异步
限流策略
Nginx限流
计数器
滑动事件窗口
令牌桶 漏桶算法
Hystrix限流
服务降级
风控防刷策略
性能调优
高并发JVM调优
高并发mysql调优
高并发Tomcat调优
高并发Nginx调优
特点
读多写少
资源有限
短时高并发,负载大
搜素推荐系统
大数据架构
linux基础
网络
DNS 使用的协议
将域名解析成ip地址
TCP协议
三次握手
四次挥手
UDP协议
http协议
报文结构
请求体
请求行
请求方法
请求url地址
http协议版本号
请求头
消息体
返回体
返回行
报文协议和版本号
HTTP状态码和状态描述
返回头
返回消息
消息头结构有哪些
accept
application
content type
code type
host
authorities权限
cookie
body消息体数据格式
SOAP
XML
JSON
protobuffer
https协议
对称加密(DES) 计算量小加密解密密钥相同
非对称加密(AES),计算量大 加解密使用不同密钥
握手过程
作用:通过非对称加密方式让服务端拿到客户端随机密码,用于后续的通信用的对称加密密钥
什么叫restful风格
资源统一定位 URI 唯一标识
一切内容都被认为是一种资源
每次请求无状态,类似有限状态机
服务器端不应该保存状态
资源处理方式,由 GET(查询) POST(创建) DELETE(删除) PUT(替换) 请求方式决定
restful最佳实践
域名,专属的域名提供
版本,url中带版本号 或者 在head中维护版本号
路径, 具体到某个方法的url路径
过滤信息,get方式中url的分页,接口分页数据
状态码, http本身的状态码, 服务器端业务状态码
post/get区别
get传输数据有限
get是在url传数据,首先url长度有限制,使用url编码
get方式可以被浏览器缓存
post方式更安全
post方式传输的数据量更大
post方式body传输数据,加密方式更多
内存
虚拟内存与物理内存映射过程
内存碎片导致问题
系统命令
救火必备linux命令
https://blog.csdn.net/weixin_34038652/article/details/86094577
sudo usermod -a -G vsftp snsoadmin
把 snsoadmin 这个用户加入到vsftp 这个组中
系统框架
shell编程
io模型
方式
BIO 同步阻塞
阻塞住业务线程
1:1
NIO 同步非阻塞
多路复用io模型,一般是阻塞在selector上
M:1
单纯底层是不会存在同步非阻塞的,因为业务线程是在不断轮询,很耗CPU
AIO 异步非阻塞
操作系统层面支持,通知机制,操作系统完成了数据内核空间到用户空间的靠背
M:1
引入异步通道,目前使用少
异步阻塞
场景: 数据库读写库同步数据
概念
阻塞
从被调用着看,阻塞只被调用着会挂起调用着线程,让调用着释放CPU使用权
同步
调用者角度看,调用者只做一件事,等待结果,或者一直轮询查结果
异步
调用者角度看,调用者做别的事情,等待被调用者通知结果
reactor模式
使用场景
单reactor单线程
单reactor多线程
主从reactor多线程
概念
多路复用的方式,将监听链接为acceptor模块,处理消息业务handler模块 分开
进程/线程
进程
资源分配最小单位
僵尸进程
父进程没有退出,父进程没有调用 wait / waitpid 回收子进程控制块,导致子进程成为僵尸进程
如果父进程死掉了,子进程会被init守护进程管理,init进程会回收子进程
线程
CPU调度最小单位
c++语言
对象内存模型
虚继承
多态
模板
makefile
编译链接
动态库
静态库
调试
core文件
gdb使用
STL
boost
python语言
java语言
java语言基础
代码块加载顺序
静态代码块只会加载1次,在普通代码块前执行,会在类链接中的准备阶段执行
普通代码块每次new的时候都会加载,在构造方法前执行,其实是编译的时候,代码被放到构造函数前
构造函数每次new都会加载,构造函数默认前面是super() 方法,默认会先调用父类的构造函数
类加载器 双亲委派
类的加载过程
类的加载
class文件加入内存,生成class对象
类的链接
验证
验证class文件是否满足JVM规范
准备
静态类变量默认初始化
解析
常量池的符号引用替换为直接引用
类的初始化
类构造器(构造方法和静态代码块)初始化
类的加载器
bootStrapClassLoader
核心加载器
ExtersionClassLoader
扩展类加载器
SystemClassLoader
系统加载器
ApplicationClassLoader
应用加载器
自定义加载器
双亲委派
保证加载的类是唯一的,只会有一份,所以向上由父类加载
与Tomcat不满足双亲委派
String
String a = "adf"
adf存在于方法区的常量池,栈空间的a直接指向常量池的adf
String b = new String("adf")
adf存在于常量池,堆空间生成对象,对象实际存储指向常量池adf的地址,栈空间的b指向堆空间的地址
String c = "adf" + "df";
String d = "adfdf";
String e = a + "df"
String d = "adfdf";
String e = a + "df"
c和d栈都指向常量池的adfdf,e保存了堆中对象,对象指向的是常量池中的adfdf值
直接常量操作,返回的地址是在常量池
经过new或者不是纯常量操作,会进行一次new在堆中生成对象,对象在指向常量池中数据
final修饰的String也在常量池
final修饰,不可以被继承(不可以被修改)
出于安全考虑,java很多类都用字符串来描述
处于内存考虑,字符串被常用,共享同一块内存,减少内存使用量
一般字符串的内部操作
1. 转成数组,toCharArray()
2. 数组操作变化值
3. String构造函数数组转为字符串
length()方法
返回字符串的实际长度,字符串没有size()方法
Integer
直接赋值或者ValueOf
享元模式,池的技术
-128 ~ 127 是常量,在堆中只会有一个对象
new的话,是在堆中生成新对象
BigInteger是整形,任意大小
BigDecimal是浮点型,任意精度
注解
元注解
修饰注解
@Retention
注解的生命周期,Compile编译,class类对象,RunTimer运行时(此生命周期才可以用被反射拿到)
@Target
接口,类,方法,变量,构造器
@Inherited
注解具有继承性,随着类继承存在
可重复注解,类型注解
java8新特性
集合
存储单值
数组
[] 初始化后长度不可以更改
插入删除效率不高
查找速度快
只有length成员变量表示长度,没有其他的可用API
collection
set
实现
treeset
底层是treemap,数据是红黑树结构
可以按属性进行排序,指定排序规则
需要重写比较函数,被存数据继承comparable接口
数据是否相同按compareto决定
linkedhashSet
按添加的顺序有序
底层也是linkedhashmap,数据+链表
在原有的hashset的基础上增加了添加元素的链接关系,使添加数据有序
对频繁的遍历要比hashset快
hashSet
存储无序的
底层是hashmap,也是数组+链表 存的
无序不可重复
linkedhashset和hashset的数据,一定要重写,并且要求hashcode方法和equals方法一致
hashcode决定了key存储位置
equals决定了key是否相等
list
实现
arrayList 线程不安全
数组
适用增删改少,遍历多
vector 线程安全
数组
stack继承于vector
linkedList
链表
使用增删改多,遍历少
有序,可重复
存储对值
map
hashMap 线程不安全
底层树数组+链表
java8后,数组 + 链表 / 红黑树,链表长度大于8的时候转红黑树
复合的数据 需要重写hashcode和equals方法
多线程下死循环
主要是rehash函数
内部链表重写计算的时候,多线程下会出现环
链表的环造成 get数据的时候会出现死循环
linkedHashMap 线程不安全
底层是数组 + 链表/红黑树
根据添加数据的顺序,有指针关联添加的数据,数据按添加顺序有序
复合的数据 需要重写hashcode和equals方法
concurrentHashMap 分段锁线程安全
复合的数据 需要重写hashcode和equals方法
java1.7 是数据的分段锁
java1.8 是CAS实现的
hashTable 线程安全
方法用Synchronize修饰的
不能有null的key和值
复合的数据 需要重写hashcode和equals方法
子类: Properties 取配置文件的数据
treeMap 有序的
底层是红黑树结构
存储的数据需要实现Comparable接口
key是无序的,不可以重复,使用set存储所有的key;Entry是无序,可重复
扩容
容量的0.75的时候,会扩容,扩为原来的两倍,将数据拷贝到新的空间
Jdk7,Jdk8默认初始数组大小是16
Jdk8 当链表长度超过8,就改用红黑树存储
Jdk8底层是Node[]数组,Jdk是Entry[]数组
最大容量 2的30次方
collections
集合相关的静态方法集
排序
自然排序:实现comparable重写compareTo(Object o)方法
随处可用的比较
定制排序: 实现comparator重写compare(Object o1,Object o2)方法
临时性的比较
size()方法
返回的是元素的个数,集合是没有length方法的
数组和集合的相互转换
toArray() 集合变数组
Arrays.asList() 数组变集合
注意,存的数据要是对象
集合遍历方式
for循环
iterator迭代器
foreach方式
java8新特性,streem流
通配符?
List<?>
可以写入null,不能写入数据
可以读数据
List<? super A>;List<? extends A> 有限制条件的通配符
反射
动态语言的特性,拿到运行时对象的状态类信息,class对象,增加了代码的灵活性
缺点:执行效率低,性能差
功能
拿到运行时对象的类信息
根据运行时对象信息创建对象
根据运行时对象信息使用其方法
根据运行时对象信息修改成员,修改私有成员
动态代理
创建一个实现接口InvocationHandler的类,它必须实现invoke方法
创建需要被代理接口和实现类
通过Proxy的静态方法newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
通过代理调用方法
生成的动态代理类会调用InvocationHandler实现类中的invoke方法
invoke方法中我们可以选择执行被代理实现类的方法,并在其前后进行处理
拿到class对象
类名.class
对象.getClass()
Class类的静态方法forName()
ClassLoader对象的loadClass()方法获取
class对象的作用
Constructor 拿到类的构造函数,实例化对象
Field 拿到类的属性
Method 拿到类的方法
Invoke调用方法
提升反射使用的效率
尽量不要getMethods()后再遍历筛选,而直接用getMethod(methodName)来根据方法名获取方法
forName获取类对象,使用缓存
lambda表达式
实质:作为接口的实例
接口需要是函数式接口
接口中只有一个抽象函数
可以用注解声明接口,@FunctionInterface
util.function包下有大量的函数式接口
==和equals
==
基本数据类型比较 值
引用类型比较地址
equals
比较的是引用类型
重写过的equals比较的是地址,object的原生方法比较的是地址
对象在内存的存储布局
普通对象
mark word
类型指针
实例数据
对齐
数组对象
mark word
类型指针
数组长度 length 4字节
实例数据
对齐
框架=反射+注解+设计模式
mybatis
ORM 半自动化
缓存
二级缓存 -> 一级缓存 -> 数据库
二级缓存是跨SqlSession的
一级缓存是SqlSession级缓存
#和$区别
#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号
#可以防止sql注入
$将传入的数据直接显示生成在sql中
hibernate
ORM自动化程度高
spring / spring-boot
IOC
控制反转
bean不是用的时候new,而是交给IOC容器,用的时候IOC容器提供,IOC容器解决了bean依赖
bean(默认是单例)
bean解释
有状态的对象
配置方式:
xml
注解
综合注解
配置类-包扫描
bean生命周期
生产bean,要调getbean,判断bean是否存在,getbean -> dogetBean -> 别名解析 -> 缓存取bean -> 判断是否循环依赖 原型bean -> 判断bean类是不是抽象 -> 判断依赖 -> 调用构造方法创建对象 -> 绑定依赖和早期引用
宏观: 扫盲class文件, 将beandefinition放入map,然后再实例化
实例化&销毁
实例化
构造器,set注入
销毁
销毁
使用
后置处理器:实现接口beanPostProcesser 钩子处理,处理bean,通过反射调用
beanFactory与factorybean
beanFactory是bean工厂
FactoryBean是类,创建对象的工厂bean
怎么解决循环依赖的?
标记bean正在创建,早期引用,提前暴露
多(三)级缓存(早期对象是半完成品,会存在第三级缓存)
哪种循环依赖不能被解决?
构造器依赖造成的循环依赖
多例(原型) 不能解决循环依赖
多例是每次使用都创建对象
DI
依赖注入
set注入
构造器注入
AOP
切面编程
动态代理
JDK代理
拦截接口
Cglib代理
字节码修改,子类继承
横切,将同一个代码切入多个业务逻辑,减少代码量,代码结构清晰;增强功能
结构
切面
各种切点,连接点的集合,就是AOP的类
切点
可以有多个,具体切入的代码逻辑
连接点
需要切入的业务逻辑位置
spring事务
隔离级别依赖数据库的隔离级别
事务传播行为
支持当前事务
当前事务不存在,就抛出异常
当前事务存在就使用,不存在就不使用
如果当前存在事务,就加入当前事务 (默认)
不支持事务
如果当前事务存在,就挂起当前事务,创建一个新的事务
以非事务运行,挂起当前事务
以非事务运行,挂起当前事务,并抛异常
嵌套事务
如果当前存在事务,则创建事务,嵌套事务
@Transaction底层实现-----AOP
事务失效场景
REQUIRED(默认传播级别), 外部有事务控制,调用的内部方法没有注解事务
只有用在public方法上有效
抛出的异常为checked类型
使用到的数据库不支持事务---myIsam
springMVC
视图解析
@RestCotroller 与 @Controller
@Controller
注明该类属于控制层
将返回的数据Model传给对应的页面模板,拼装数据
@RestController
= @Controller + @ResponseBody
直接返回数据给调用端
spring boot优点
自动配置
内嵌web容器,打包成jar包,不用打包成war包
starter场景启动器,自动版本控制
运行时监控,与云计算的集成
spring boot 配置
@bean注解
给容器添加组件
@Cacheable
缓存
@Configuration
配置注解
@ConditionalOnClass()
条件
@SpringBootApplication
主注解,启动注解
@EnableAutoConfiguration 开启自动配置
@AutoConfigurePackage 自动配置包
将@SpringbootApplication标注的包以及子包下的所有的组件扫描到Spring容器
@Import 导入包
给容器导入组件,导入自动配置类XXXAutoConfiguration
从导进来的自动配置类的路径 META_INFO/spring.factories 获取EnableAutoConfiguration配置的值
获取配置值
@ConfigurationProperties 注释类,类与配置参数一致
@value
配置变量
@PropertiesSource 指定外部配置文件
@ImportResource 导入外部文件
profile
指定多环节的配置
自动配置原理
1. 主配置类,开启了自动配置功能@EnableAutoConfiguration
2. 利用EnabledAutoConfigurationImportSelector 给容器导入了组件,扫描spring.factories文件
3. 将spring.factories的值包装成properties对象,从中获取EnableAutoConfiguration.class对应的值
4. spring boot加载会添加大量自动配置类,启动的时候会优先加载自定义配置类
spring boot 扩展配置
1 自己添加配置的bean到容器,使用@bean注解 @Component
2. 编写配置类,WebMvcConfigureAdapter,扩展MVC
3. Spring boot有很多 XXXConfigurer 帮助进行扩展配置
spring boot默认错误处理机制
1. 浏览器:默认错误页面,客户端:默认错误json
2. 参考 ErrorMvcAutoConfiguration,错误处理默认配置
spring boot 自定义starter
spring boot 更改内嵌servlet容器 (默认时tomcat)
修改容器配置
方法1: 修改类EmbeddedServerletContainerCustomer
方法2:修改properties的配置参数
切换容器:
1. pom排除依赖,引入其他的容器依赖
容器启动原理
1. springBoot启动 执行run
2. refreshContext spring刷新IOC容器
3. refresh()刷新IOC容器
4. onrefresh()使用了createEmbbedServerletContainer()
5. 获取serverlet容器工厂
6.嵌入式容器工厂创建对应的对象
spring boot 2.0
加入了spring5的 webflux 响应式web编程
webflux是 非阻塞IO 多路复用
MVC 本质是同步阻塞IO
netty
主从reactor多线程
前端
vue
js
angularjs
app
controller
freemarker
css与html的结合
行内
嵌入
导入
可以只引进一个总的CSS文件
链接
会在加载页面主体部分之前装载CSS文件
并发编程
多线程
无返回值
实现runnable接口
run方法不会抛异常
需要Thread的start方法启动多线程
继承Thread类
java只能单继承,所以扩展收到限制
有返回值
实现callable接口
future拿到返回值
拿返回值
判断任务是否执行完
中断任务
向线程池summit的多个任务,只有全部执行完,future才可以get到值
call方法会抛异常
需要Thread的start方法启动多线程
解决future的get方法阻塞问题completionService
take方法也是阻塞方法,只是会拿其中一个完成的future
poll方法和take类似,只是poll方法不会阻塞,没有完成的任务直接返回null,可以加等待的时间
ThreadLocal
线程间的数据隔离
解决多线程安全问题
set()往里面放数据
get() 从里面取当前线程的数据
使用完get和set后要用remove去除 内部map的key与value的引用关系,因为 key是弱引用,下次gc的时候被回收,导致value会被线程长期持有,造成内存泄漏
优雅做法:帮ThreadLocal包装到单例中
并发包
BlockingQueue
ConcurrentHashMap
ReentrantLock
LockSupport
CyclicBarrier
CountDownLatch
ReadWriteLock
Semaphore
Condition
相关问题理解
对volatile的理解
虚拟机提供的轻量的同步机制
保证可见性
前后加了内存屏障
不保证原子性
禁止指令重排
当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行
在JMM的理解
可见性 主内存 线程工作内存
原子性
有序性质
指令重排
哪些地方用过volatile
单例模式的double check (禁止了指令重排)
在真正的new操作对象的时候,new命令其实包含了,开辟内存,初始化内存等操作;半初始化状态的对象
多线程情况下,一个线程在new的时候,内存还没有被初始化完全,另一个线程进来后发现对象引用已经不是null了,就会返回一个未初始化完全的对象,从而造成出错
代理模式
CAS的理解
比较交换
工作内存与主存数据比较一样的时候修改,不一样的时候重复读取主存,跟新工作内存数据
CAS底层,unsafe的理解
native方法,unsafe类
CAS缺点
循环时间长,CPU开销大
只能保证一个共享变量的原子性;不能保证代码块的原子性
有ABA问题
原因: 一个线程短时间内把变量由A改成B,再由B改成A
解决:加入时间戳版本,原子引用
AtomicStampedReference
ArrayList是线程不安全的,解决线程不安全的方案
加锁
使用vector线程安全的数组
使用Collections内部方法转为线程安全的List
各种锁的理解
公平锁/非公平锁
是什么:公平锁只等待锁的线程按先来先得顺序得到锁
两者区别: 公平锁按FIFO的等待队列等待锁,锁操作耗时
ReentrantLock默认是非公平锁,synchronize是非公平锁
对象锁
Synchronize ,每个对象的头部markword字段有标志标志,monitorenter 和 monitorexit 指令来实现同步的,monitor管程来控制
锁优化,偏向锁,就是免真正加锁,只是标签
头部mark word字段,有锁状态,是否偏向锁,锁标志
JVM级的不需要业务代码控制
偏向锁
偏向锁的核心思想是,如果一个线程获得了锁,那么锁就进入偏向模式,此时Mark Word 的结构也变为偏向锁结构,当这个线程再次请求锁时,无需再做任何同步操作,即获取锁的过程,这样就省去了大量有关锁申请的操作
可重入锁
是什么:同一个线程外层函数获取锁后,内存递归函数仍然能获得锁
ReentrantLock和Snychronize是典型的可重入锁
底层实现原理,ReentrantLock是AQS同步队列,Snychronize是锁住的对象头部字段记录的标志,在monitor中会做计数
自旋锁
SpinLock,短时间的自旋,不会释放CPU
独占锁(写) / 共享锁 (读)
ReentrantReadWriteLock
读写锁
写的时候排他,读的时候共享排他写锁
锁优化
偏向锁-> 轻量级锁 -> 自旋锁 -> 重量级锁
CountDownLatch/CyclicBarrier/Semaphore
CountDownLatch
让一些线程阻塞,知道一些线程完成操作
一些线程执行await()阻塞,一些线程完成操作后执行CountDown()减数
案例:等待人到齐,才开会
CyclicBarrier
一些线程阻塞在一个点,然后同时进行
await()方法阻塞
案例: 跑步比赛到齐开始
Semaphore
用于并大资源数量的控制,同一时间只能有固定数的线程进入临界区
案例:抢车位
阻塞队列
是什么
阻塞队列空的时候,从队列获取数据的线程会被阻塞
阻塞队列满的时候,往队列放数据的线程会被阻塞
好处
不需要关心什么时候阻塞线程,什么时候唤醒,阻塞队列帮处理了
Blockqueue核心方法处理出错
抛异常
返回特殊值
一直阻塞
超时退出
架构种类
ArrayBlockingQueue基于数组的有界
LinkedBlockingDeque基于链表的有界,默认界值很大
SynchronousQueue同步队列,不存数据,生产一个消费一个
PriorityBlockingQueue 有优先级的无界阻塞队列
delayQueue 延迟无界阻塞队列
LinkedTransferQueue 链表结构的无界阻塞队列
LinkedBlockingDeque链表结构阻塞双端队列
用在哪里
生产者消费者模式
线程池
消息中间件
java线程池,ThreadPoolExecutor的理解
线程池优势
充分利用CPU
减少频繁创建线程的性能消耗
线程池的使用
自定义线程池,继承ThreadPoolExecutor
线程池函数
Executors.newCachedThreadPool
Executors.newSingleThreadPool
Executors.newFixedThreadPool
Executors.newScheduleThreadPool
线程池的重要参数
corePoolSize 线程池的常驻核心线程数
maximumpoolSize线程池能够容纳的最多线程数
keepAliveTime 多余核心线程数的空闲线程的最多存活时间
unit keepAliveTime的单位
workqueue 任务队列,提交到线程池还未处理的任务
threadFactory 线程池中线程的工厂,用于创建线程
handler 拒绝策略,任务丢列满,线程数达到最大时,做的处理
线程池的工作原理
创建线程池后等待提交任务
调用execute添加任务,线程池做的判断:
如果线程数量小于核心线程数,就马上创建线程处理任务
如果正在运行的线程数大于核心线程数,就将任务放入任务队列
如果任务队列满了,且正在运行的线程数小于最大线程数,就创建非核心线程处理任务
如果队列满了,且线程数达到最大线程数,线程池使用饱和拒绝策略处理任务
当一个线程任务处理完,会从任务队列中取下一个任务执行
当一个线程空闲时间超过keepAliveTime时候,线程池处理
如果当前线程数量大于核心线程数,那么这个线程就会被销毁
线程池参数的合理配置
线程池拒绝策略
AbortPolicy 直接抛出异常RejectedException,阻止系统运行
CallerRunPolicy 由提交任务的业务线程处理
DiscardOldestPolicy 抛弃队列中等待最久的任务,然后把最新的任务加入任务队列
DiscardPolicy 直接丢弃任务,不予处理,也不抛出异常,允许任务丢弃
创建线程池的方法
使用自定义线程池
executors线程池问题: 1. 默认使用链表有界阻塞队列,界很大,导致内存溢出
2. 缓存调度线程池会创建大量线程导致资源占用大
2. 缓存调度线程池会创建大量线程导致资源占用大
如何合理配置线程池数量
CPU密集型操作: cpu核心数+1
IO密集型操作:2xcpu核心数
死锁定位分析
产生原因:
系统资源不足
资源分配不当
线程执行顺序不合适
线程互斥,资源持有等待,不可剥夺
解决: jps定位到进程id,jstack定位到栈代码
性能调优
JVM
JMM对象内存模型
主内存
多线程共享
工作内存
多线程私有,拷贝的主内存
happen-before原则
Java内存模型中定义的两项操作之间的偏序关系,如果操作A先行发生于操作B,其意思就是说,在发生操作B之前,操作A产生的影响都能被操作B观察到
Java内存模型中定义的两项操作之间的偏序关系,如果操作A先行发生于操作B,其意思就是说,在发生操作B之前,操作A产生的影响都能被操作B观察到
具体规则:
在一个单独的线程中,按照程序代码的执行流顺序,(时间上)先执行的操作happen—before(时间上)后执行的操作
一个unlock操作happen—before后面(时间上的先后顺序,下同)对同一个锁的lock操作
volatile变量规则:对一个volatile变量的写操作happen—before后面对该变量的读操作
线程启动规则:Thread对象的start()方法happen—before此线程的每一个动作。
线程终止规则:线程的所有操作都happen—before对此线程的终止检测,可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。
对线程interrupt()方法的调用happen—before发生于被中断线程的代码检测到中断时事件的发生。
对象终结规则:一个对象的初始化完成(构造函数执行结束)happen—before它的finalize()方法的开始
传递性:如果操作A happen—before操作B,操作B happen—before操作C,那么可以得出A happen—before操作C
JVM内存布局
虚拟机栈
本地方法栈
堆内存
1/3 新生代
8/10的Eden区
1/10的Surviver0区
1/10的Surviver1区
2/3的老年代
老年代和元数据空间
方法区
程序计数器
内存溢出
堆内存溢出
静态集合添加很多数据
类内部方法,有new大对象,长期持有
元空间内存溢出
大对象
代码太多
引用第三方库太多
栈空间
深度递归
对线数太多
-Xss参数太大
直接内存
netty使用
GC解析
引入类型
强引用
一般栈变量引用的对象,不会被回收对象
软引用
SoftReference修饰使用的,一般不会回收,在内存不够用的时候会被回收
弱引用
WeakReference修饰使用的,一般两次垃圾回收会被回收内存
虚引用
PhantomReference修饰使用的,内次垃圾回收都会被回收对象
GC算法
引用计数
复制
标记清理
标记整理
GC收集器
串行收集器serial (慢+STW)
并行收集器parel/parelNew/ parelOld (快+STW)
并发收集器CMS (快+短暂STW)
执行流程:初始标记 STW,并发标记,重新标记STW,并发清理
使用算法:标记清理
新生代
串行 serial copy (复制)
并行 ParNew (复制)
并行回收Parallel / parallel Scavenge (复制)
老年代
串行 serial Old (标整)
并行 Parallel Old (标整)
并发 标记清理 CMS (和Serial Old联合使用) (标清)
缺点1 CPU负载高
缺点2 内存碎片
G1 (不区分新生老年)(标整) (java9后默认垃圾收集器)
场景:服务端垃圾收集,应用于多处理器和大容量内存环境,高吞吐的同时尽可能的满足垃圾收集暂停时间的要求
特点:
CMS一样的并发执行
整理空闲空间快
需要更多的时间预测GC停顿的时间
不希望牺牲大量的吞吐性能
不需要更大的Java Heap
停顿上增加了预测机制,用户可以制定期望的停顿时间
不区分新生代和老年代,划分内存为块region 1~32M 避免了全内存扫描 收集快
内存区域划分
Eden
Survivor
Old
Humongous 超大内存区 放大对象
收集过程 小区域收集+产生连续的内存块
Eden区满,移动数据到survivor,survivor空间不够,数据会移动到old区
survivor区数据移动到新Survivor区,部分数据移动到old区
Eden区收拾干净,GC结束
执行过程
初始标记
并发标记
最终标记
筛选回收
常配置参数
-XX:MaxGCPauseMillis:设置最大垃圾收集停顿时间
-XX:G1HeapRegionSize=n 内存区块大小
-XX:InitiatingHeapOccupancyPercent=n 堆占用多少触发GC
-XX:ConcGCThreads=n 并发线程数
-XX:G1ReserverPercent=n 空闲区域百分比 默认是10%,防止内存溢出风险
与CMS比较
G1没有内存碎片
可以指定精确控制业务停顿时间
ZGC
Full GC
原因
序执行了System.gc() //建议jvm执行fullgc,并不一定会执行
jmap -histo:live pid命令 //这个会立即触发fullgc
minor gc的时候进行的一系列检查
用了大对象 //大对象会直接进入老年代
程序中长期持有了对象的引用 //对象年龄达到指定阈值也会进入老年代
排查步骤
查找报警对应的进程 ps -ef|grep XX
查看Gc情况
jstat -gcutil pid
Dump文件分析
jmap -dump:live,format=b,file=xxx [pid]
查看内存文件
Jprofile
jvisualvm
jstack Dump 日志文件中的线程状态
linux版MAT分析
准备
下载地址 http://www.eclipse.org/mat/downloads.php
解压,修改MemoryAnalyzer.ini到最大内存
执行分析: ./ParseHeapDump.sh m.hprof org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components
mat目录下会生成3份.zip结尾的报告和一些m.相关的文件,将生成的m.hprof相关的文件都下载到windows本地磁盘
浏览器打开index.html文件内容,查看分析报告
查看Class Histogram一项
性能调优
结合微服务SpringBoot调参
参数分类
辅助信息
-XX:+PrintGC 打印GC信息
-XX:+PrintGCTimeStamps 打印GC时间
-XX:+PrintGCDetails 打印GC详细信息
-XX:+PrintGCApplicationStoppedTime 打印GC时程序暂停时间
-XX:+PrintGCApplicationConcurrentTime 打印GC中程序未暂停时间
-XX:+PrintHeapAtGC GC前后堆栈信息
-Xloggc:filename GC日志入文件
XX:+PrintTenuringDistribution miniGC存活阀值
收集器选择
-XX:+UseParallelGC 年轻代并行,老年代串行
-XX:+UseParNewGC 设置年轻代未并行
-XX:ParallelGCThreads 并行收集器的线程数
-XX:+UseParallelOldGC 设置老年代为并行收集
XX:MaxGCPauseMillis 年轻代垃圾收集的最长停顿时间
-XX:+UseConcMarkSweepGC 使用CMS收集器
-XX:CMSFullGCsBeforeCompaction CMS多少次后进行内存压缩
-XX:+UseG1GC 使用G1收集器
堆大小设置
-Xms 初始堆大小
-Xmx 最大堆大小
-Xmn 年轻代大小
-XX:NewSize 年轻代大小
-XX:MaxNewSize 年轻代最大值
-XX:PermSize 持久代初始值
-XX:MaxPermSize 持久代最大值
-Xss 线程栈大小
-XX:NewRatio 年轻代与老年代的比值
-XX:SurvivorRatio Eden区与Survivor的比值
-XX:LargePageSizeInBytes 内存页的大小
-XX:MaxTenuringThreshold 垃圾最大年龄
-XX:SoftRefLRUPolicyMSPerMB 软引用存活时间
-XX:PretenureSizeThreshold 大对象再老年代生产
-XX:+CollectGen0First FullGC时是否先Young区收集
常用命令
jps -l | grep 查看进程的进程id
jinfo -flags 进程id 进程的jvm参数
jstack 进程id 栈数据
top 整机查看 各个进程的CPU和内存 CPU平均负载
%CPU
%MEM
按数据键盘1
查看每个cpu核的负载信息
查看id = idle
cpu的空闲率,数字越大越好
PID
进程id
COMMAND
进程的执行命令名
load average
系统的平均负载
有三个数据,分别是1分支,5分钟,15分钟的负载值
上面三个数相加 / 3 * 100% 超过了60%,表示系统负载
uptime 是top的简化版本
可以直接查看到 load average 三个数据
vmstate -n 2 3
每2秒刷一次,共3条数据
procs: 进程数
r
运行的进程数
b
阻塞的线程数
cpu
us
用户使用率
sy
系统使用率
memory
查看内存
free
free -m 查看内存,单位是MB
free -g 单位是GB
df 查看磁盘剩余空间数
df -h
-h可以让参数有单位
iostat 查看磁盘io
iostat -xdk 2 3
每2秒刷一次,共3条数据
%util :表示io情况,越大说明越差
r/s
每秒读
w/s
每秒写
ifstat 查看网络io
pidstat -p 查看单个进程内存
ls -l
10位文件信息
1(文件类型) + 3(用户的rwx)+ 3(用户组用户的rwx) 3(任何用户rwx)
ifconfig
查看网卡信息,网络的ip地址
netstat
netstat -nupl (UDP类型的端口)
netstat -ntpl (TCP类型的端口)
0.0.0.0:80 表示端口可以被外部访问
127.0.0.1:80 表示端口只可以被本地访问
netstat -anp | grep ssh
CPU占用过高分析步骤
TOP命令找到占用CPU最高的进程ID
ps -ef 或者 jps定位是后台的哪个具体进程
定位到具体的线程代码
ps -mp 进程id -o THREAD ,tid,time
参数说明
-m 显示所有线程
-p 进程的cpu时间
-o 按格式输出
将需要的线程id转为16进制
printf “%x\n” 线程id
jstack 进程id | grep 16进制线程id -A60
分布式
理论
CAP
C 一致性
A 可用性
P 分区可用性
CA 系统一般不是分布式的,单机可用强一致
CP 分布式系统,强一致
AP 分布式系统,高可用
CP 分布式系统,强一致
AP 分布式系统,高可用
BASE 基本可用,最终一致性,CAP无法同时满足的折中
分布式与集群
分布式系统
一个系统拆分成多个子系统 (并行,每次都被用到)
集群
一个系统部署多份 (串行,每次只用一个)
应用分布式
多台机器部署应用,集群冗余
为了解决单个物理服务器容量和性能瓶颈问题而采用的优化手段
数据分布式存储
数据被hash存储到多台机器
为了解决单个物理服务器容量和性能瓶颈问题而采用的优化手段
高可用
消峰限流保证可用
应用冗余,集器保证可用
异地多活保证可用
高并发
并发
多个线程线程数大于CPU核心数
并行
多个线程数等于CPU核心数
措施
Nginx反向代理
LVS/F5 负载均衡多个Nginx
DNS负载均衡
正反向代理
正向代理
后台系统朝外部请求,经过的代理
内部服务只看到一个地址,正向代理将请求路由到目标地址
反向代理
外部请求到反向代理,外部请求只看到一个代理
反向代理将外部请求分发到后台多个服务机器上
四层反向代理
ip+port的路由
dns路由
七层反向代理
根据http协议中的某些属性来做路由
nginx反向代理
存储中间件
缓存
本地缓存
ehcache
guava cache
集合
申明式缓存
在消费者端做的缓存
redis
部署架构
单机
哨兵
多哨兵
主从模式,主写,从同步数据,可读
哨兵监控集群状态
做不到真正的分布式存储,要做到的化,业务要做hash处理
集群
集成了哨兵的所有功能
做到了分布式存储,通过分槽来实现
持久化
RDB
内容是纯数据
内存镜像,时间窗口大,用于恢复数据会丢失数据
多用于数据冷备
AOP
追加日志,没操作一次记录一次,用于恢复丢失数据少
内容日志是操作命令
常见问题
缓存穿透
黑客攻击,一个不存在的数据,导致大量请求落入数据库
将key放入缓存,并设置空值
布隆过滤器限制有效缓存的key
数据库和redis都不存在的数据
缓存击穿
一个时刻大量缓存数据失效,请求落到数据库
设置随机的过期时间
数据库有数据,缓存没有数据
缓存雪崩
缓存机器挂了重启缓存数据都没了,或者是缓存失效时间同时达到,缓存全部失效清除
缓存失效时间设置随机值
修改失效数据回收策略
持久化缓存数据
缓存挂了,或者数据集中失效
大量请求压垮数据库,数据库挂了导致应用系统挂了,这种级联式的服务故障
热点key(缓存击穿)
促销活动,导致某一个缓存key成为热点数据,大量请求到某几台redis机器,导致redis机器带宽打满,机器崩溃
缓存预热
应用本地缓存缓解
热点数据永远不过期
数据库存在,redis不存在的数据(过期时间redis被去除)
fastdfs
对比HDFS
es
index/type/document
索引
索引相当于mysql的库
分片
每个索引可以设定分片数,默认是5个 primary shard
每个primary shard 可以设置制定指定个replicate shard副本分片(根据机器数决定,至少一个副本分片)
副本分片的作用是实现冗余数据实现高可用,在primary主分片挂了后,副本分片会被升级为主分片;还有一个作用是支持查询不支持写,提升的并发能力
分片的目的是将document文档分块的存在不同的集器上,实现存储分布式
副本shard 可以提供数据读不可以写,从而提升集群的性能
数据存储过程
documentid 可以手动生成也可以自动生成,routing_id来做分片,没有设置默认用documentid主要用来分片
元数据库中数据以及由唯一的id,导入es的时候可以作为es的documentid
主primary shard 先写 buffer缓存 -> 1秒 refresh 进os cache + 同步追加写trancelog日志 -> 30分钟或者trancelog日志太大进行commit操作,flush内存数据进磁盘 segment file新文件 -> 当segment file文件多到一定程度,进行merge操作,将多个segment file文件合并为一个,并删除.del文件 (删除的数据标记在.del文件)
倒排原理
将被搜文档的分词提取出来,将包含关键分词的文档路径归属到当前分词关键字
节点类型
主节点 (存储了集群的元数据,管理集群,可以配置存数据也可以不存数据)
数据节点
存实际document数据的节点
协调节点
客户端连接到的任何节点都会先做协调节点使用
协调节点路由写操纵到主shard分片写数据
路由读读操作到对应数据分片,不分主shard还是副本shard
集群部署架构
9300端口上,自动加入集群,配置统一的集群名称
常用DSL
查询birth字段不存在数据
curl -XGET http://10.10.10.10:9600/epay_cunstomer_infos/epay_customer_infos/_search?pretty
-d '{"query":{"bool":{"must_not":{"exists":{"field":"birth"}}}}}'
-d '{"query":{"bool":{"must_not":{"exists":{"field":"birth"}}}}}'
mongo
非关系型数据库
表无结构限制
索引
主键
唯一
地理位置
全文
副本集
高可用
数据非分布式存储 ,数据量受限于单台机器容量
分片部署
数据分布式存储
hbase
是什么
分布式,可扩展,海量数据的,非关系型数据库,做大表;数据量越大使用性价比越好
基于HDFS的,支持随机写
hdfs是分布式文件系统
单个的小文件的内容怎么写,就有了Hbase
逻辑上类似mysql的表结构,实际数据存储是key-value的
结构:
列族
列
可以动态增减
row key
行键
唯一的
有顺序的
自减顺序
region
表横向切分的切点
按region存储
每一条记录
元数据
时间戳
数组增删不是立马操作的,实际是比较时间戳的
操作类型
行key
列组
列
数据模型
命名空间
类似于mysql的库
自带命名空间 hbase,default
Region
类似mysql的表
Row
行数据是由row key和列决定的
按字典顺序存储的
Column
列由列族+列限定符决定
Time Stamp
时间戳用于标志版本
cell
确定唯一版本的数据,最小单元
数据没有类型,底层全是byte数组
架构
依赖zookeeper
管理hbase集群,选主
Master
master挂了后,还可以做数据增删改,不能做表的增删改
管理表的增删改
Region Server
Hlog(wal)
预写入日志,追加日志,保证数据不丢失
多个Region
增删改数据
split切分region合并region
不配置默认128M 超过的时候会做切分
建表的时候做好预分区
内部有:
多个Store列组,内存 Store
Block cache 读缓存
flush出多个StoreFile文件,删除内存废弃数据
StoreFile文件数量达到一定程度会做合并,删除其他的小文件,compact操作
Region Server与主master 系统时间差要在30s内,才能启动
底层依赖HDFS
Hbase用Hdfs客户端最终数据会写入HDFS
Hlog日志(Wal)也会写入HDfs
写流程
读比写慢
1.先取meta元数据的缓存,取不到先去zk里找meta表元数据所在的RegionServer
2.请求meta所在的RegionServer
3.根据meta信息,看是操作哪个RegionServer数据
4. 写内存完成
5. 多次刷新flush进磁盘,每次都会产生一个Store file文件
默认不配,是RegionServer的40%的时候会flush操作
90%的Jvm内存的时候会阻塞客户端写操作
或者默认是最后一次写数据1小时后,数据会flush进磁盘
WAL日志超过一定大小,会进行flush,默认是32M
读流程
1.先取meta元数据的缓存,取不到先去zk里找meta表元数据所在的RegionServer
2.请求meta所在的RegionServer
3.根据meta信息,看是操作哪个RegionServer数据
先读缓存,读不到读磁盘
缓存失效 LRU算法
hbase的API
DDL
改表alter
改表的状态 alter_status
使能表 enable
下线表 disable
先下线表,才能删除
删除表 drop
列出用户表 list
命名空间 list_namespace
DML
改数据 put
参数:表名,rowkey,列族,值
查数据 get
参数:表名,列名
查数据 scan
参数:表名
删数据 delete
参数: 表名,rowkey,列名
增数据 append
hbase优化
本身是分布式高可用的
建表预分区
rowkey设计原则
散列性:尽量均匀的散列到不同的分区里
长度一般是 70~100
唯一性
内存优化
70%的内存分配给Hbase的JVM堆
打开最大文件描述符
允许HDFS追加文件
开启压缩
客户端RPC监听数量
Hstore文件大小优化
优化hbase客户端缓存
flush,compact,split的机制
hbase分析引擎
MR
Hive
数据仓库
数据分析清理
基于Hdfs和MapReduce
mysql
存储引擎
Innodb
行级锁
支持事务
MyISAM
表级锁
不支持事务
索引
联合索引
多个字段组成的索引
最左前缀匹配,因为联合索引的索引key是索引第一个字段,索引树的叶子节点会包含索引的每个字段并且排序
不满足最左匹配命中不了索引,因为索引key筛选出的是一个范围数据
不满足最左匹配命中不了索引,因为索引key筛选出的是一个范围数据
使用操作函数导致命中不了索引;
大于小于比较导致后面字段不能命中索引;
不从联合索引的第一个字段开始命中不了索引
like ‘%asdf%’ 命中不了索引;like ‘asdf%’ 命中索引
大于小于比较导致后面字段不能命中索引;
不从联合索引的第一个字段开始命中不了索引
like ‘%asdf%’ 命中不了索引;like ‘asdf%’ 命中索引
索引数据结构 B+数
所有索引key都会存在叶子节点
叶子节点双向链接
非叶子节点只有索引key,没有数据
减少磁盘IO次数
聚集索引/非聚集索引
概念:聚集索引,索引关键字和索引数据在一起,不需要回表;非聚集索引,索引关键字和索引数据的地址在一起,获取数据需要回表
Innodb的主键索引是聚集索引
InnodB的非主键索引是非聚集索引
myIsam的索引都是非聚集索引
覆盖索引
索引包含了查询字段
命中索引后不需要二次回表读数据
事务
四大特性
隔离性
原子性
数据库断电奔溃,undo日志保证了原子性
持久性
数据库断电奔溃,redo日志保证了持久性
一致性
undo和redo日志保证了一致性,一致性只操作失败后,要回滚,保证数据一致
隔离级别
读未提交
读到了别的事务回滚数据,脏读 (不加锁)
读已经提交
不可重复读,读到别的事务跟新的数据 (不加读锁)
可重复读
读锁,行级锁不能控制插入数据,幻读 (gap间隙锁解决幻读) MVCC提高了可重复读的并发性,不能解决幻读
MVCC实际是再行记录加隐形字段,记录创建事务id,记录删除事务id
可串行化
读写锁
锁
锁分类
操作类型
读锁(共享读锁) 写锁(排他锁,互斥读写锁)
正常select 走乐观锁
select * from for update
加上for update会走悲观锁
操作粒度
表锁
锁整表,开销小,MyISam引擎 偏读
show open table 可以查看哪些表被锁
show status like "table%" (table_locks_immediate 表级锁次数 table_locks_waited 表级锁等待次数)
行锁
行锁,开销大,加锁慢 支持的事务 Innodb引擎 偏写
事务/事务隔离级别
并发事务问题:更新丢失,脏读,不可重复读,幻读
事务默认自动提交,set autocommit=0 关闭默认提交事务
无索引, 行锁会升级为表锁 varchar类型查询条件没有带引号
gap间隙锁的问题
进行查询的时候,间隙锁会锁定范围内的所有的索引键值,即使键值不存在,从而导致插入的性能降低,特殊场景下会有性能问题
select * from table where a=a for update 手动加锁 for update可以锁定一行
show status like "innodb_row_lock%" 查看行锁 (innodb_row_lock_average_time 等待的平均时长,innodb_row_lock_waites 等待的次数 innodb_row_lock_time 等待的时长)
页锁
BDB 存储引擎支持
锁粒度间于表锁行锁之间,会死锁
单表容量
最大可以达到 2000w条
500w~1000w之间 300w会有性能问题
数据量到2G
分表分库
mysql-sharding
mycat
垂直分
按业务分
水平分
时间或者地域维度分
大表拆分成小表
读写分离库一致性
binlog日志同步数据
binlog日志格式
statement
基于sql语句
row
基于行
mixed
statement和row的混合
数据库优化
方案步骤:sql优化 -> 索引优化 -> 分区 -> 读写分离 -> 缓存 -> 集群 -> 向上扩展 -> 分库分表 -> nosql 大数据
explain分析
id 表执行顺序
select type 查询类型
table 表名
type 查询性能类型 system>range>req_ref>ref>index>all
possibile keys 可能命中的索引
key 命中的索引名
key_len 索引长度,标志用到了索引几个字段
rows 扫描的行数
extra :(use where:用了查询条件,use index 用了覆盖索引 use temporary用了临时表 use filesort 用了数据库外排序)
开启慢查询日志 (最好不要在生产开启)
profile分析
show profiles (query_id 查询sql的id ,Duration 耗时 Query查询语句)
show profile cpu, block io for query query_id (1. status: 状态或者执行步骤,2. Duration 执行耗时 3. CPU_Use: cpu计算耗时 4. cpu_system: cpu系统耗时,5. block_ops_in: 输入io耗时6. block_ops_out: 输出io耗时)
注意的status状态优化点:1. converting HEAP to myIsam 读取的数据太多,内存装不下 2. create tmp table 创建临时表拷贝数据 3. coping tmp table on disk 拷贝内存临时表数据到磁盘4. lock 锁缓存
数据模型优化
DBA运维 数据库实例配置参数优化
io瓶颈
带宽瓶颈
连接数限制
neo4j
是什么
图数据库
数据以节点和关系来存储的
基于jvm的 非关系数据库
解决的问题
关系数据库多对多的查询性能的下降,空间的浪费
数据的复杂关系 (人脉网络,交通网络)
特性
有管理界面
支持事务 ACID
有图查询语言 cypher语句
高性能
高可用集群
社区版不支持集群
复杂的数据模型
基本概念
节点
相当于关系数据库的记录
可以存标签 属性
关系
节点和节点之间的联系
关系必须有方向
关系也具有属性
关系可以头尾都指向自己
路径
关系连接组成的路径
单个节点 自己的路径长度是0
基本操作 Cypher语句
CREATE
创建节点 关系 属性
CREATE (dept:Dept { deptno:10,dname:"Accounting",location:"Hyderabad" })
CREATE (p1:Profile1)-[r1:LIKES]->(p2:Profile2)
创建节点关系,LIKES为关系标签名
MATCH
数据库获取有关节点,关系和属性的数据
MATCH (dept: Dept)
RETURN dept.deptno,dept.dname
RETURN dept.deptno,dept.dname
RETURN
返回值
RETURN <node-name>.<propertyn-name>
WHERE
查询条件
MATCH (cust:Customer),(cc:CreditCard)
WHERE cust.id = "1001" AND cc.id= "5001"
CREATE (cust)-[r:DO_SHOPPING_WITH{shopdate:"12/12/2014",price:55000}]->(cc)
RETURN r
WHERE cust.id = "1001" AND cc.id= "5001"
CREATE (cust)-[r:DO_SHOPPING_WITH{shopdate:"12/12/2014",price:55000}]->(cc)
RETURN r
DELETE
输出节点,关系
MATCH (e: Employee) DELETE e
MATCH (cc: CreditCard)-[rel]-(c:Customer)
DELETE cc,c,rel
DELETE cc,c,rel
REMOVE
删除节点关系的属性
MATCH (m:Movie)
REMOVE m:Picture
REMOVE m:Picture
SET
节点或者关系添加新属性
MATCH (dc:DebitCard)
SET dc.atm_pin = 3456
RETURN dc
SET dc.atm_pin = 3456
RETURN dc
ORDER BY
排序
MATCH (emp:Employee)
RETURN emp.empid,emp.name,emp.salary,emp.deptno
ORDER BY emp.name DESC
RETURN emp.empid,emp.name,emp.salary,emp.deptno
ORDER BY emp.name DESC
UNION
将结果合并为一组
MATCH (cc:CreditCard) RETURN cc.id,cc.number
UNION
MATCH (dc:DebitCard) RETURN dc.id,dc.number
UNION
MATCH (dc:DebitCard) RETURN dc.id,dc.number
LIMIT 和 SKIP
分页操作
MATCH (emp:Employee)
RETURN emp
LIMIT 2
RETURN emp
LIMIT 2
MATCH (emp:Employee)
RETURN emp
SKIP 2
RETURN emp
SKIP 2
MERGE
命令是CREATE命令和MATCH命令的组合
MERGE (gp2:GoogleProfile2{ Id: 201402,Name:"Nokia"})
IN
IN操作
MATCH (e:Employee)
WHERE e.id IN [123,124]
RETURN e.id,e.name,e.sal,e.deptno
WHERE e.id IN [123,124]
RETURN e.id,e.name,e.sal,e.deptno
Exists
Match (n) where exists(n.name) return n
分布式框架
注册中心
注册类型
仅订阅
只能发现调用其他服务,自身不可以被其他服务发现
仅注册
只可以被其他服务发现,不可以去发现和调别的服务
zk
基于观察者模式的服务管理框架, == 文件系统+通知机制
特点
半数以上节点存活,集群就可以正常工作
任何一个节点的数据都一样
任何一个客户端的请求,执行都是顺序的
数据跟新是原子的
数据结构
每个节点都可以通过路径找到
每个节点最多存1M数据
应用场景
注册中心
协调服务
分布式锁
命名服务
路径名都是唯一的
配置参数
每个节点数据一样
修改参数可以通知到所有客户端
集群管理
集群节点信息写入znode
znode信息有变化可以通知到监听的节点
服务动态上下线
服务下线,立即通知客户端
软负载均衡
客户端可以拿到访问最少的服务端地址
配置参数
心跳时间 ticktime
开始通信最大延迟时间 inittime = 10 个心跳
系统启动后的延迟 synctime = 5 个心跳
数据存放路径
client port 客户端连接的端口号
选举算法过程
算法: Paxos修改的ZAB算法
半数以上可用 (5个节点至少有3个节点存活)
超过半数的目的: 防止脑裂问题
只需要半数同意即可: 也可以加快选举速度,不需要全部都走一遍选举
自动选举一个leader
先选自己,选不了自己,选myid最大的为主
监听器原理
客户端创建两个线程
监听请求
监听到调用内部的process处理
数据通信
zk的注册监听器将注册的事件添加到监听列表中
zk会将数据变化通知到客户端的listen线程
监听:数据变化 + 节点的变化
部署架构
有主的镜像集群
每个节点的数据是一样的
一个主多个从
客户端可以从任何一个节点读数据
CP模式
节点类型
leader 提供读写,选主
follow 提供读,不能写,选主
observer 提供读,不能写,不能选主
数据节点类型
持久节点
节点需要手动删除才会被删,默认创建的是持久节点
临时节点
session断开,节点被删除
持久顺序节点
临时顺序节点
数据操作
set 修改设置值
get 查询值,需要带上路径
watch 监听节点,监听只会通知一次,下次通知需要在此监听
create 创建节点
delete删除节点
rmr 删除节点及其子节点
state结构体
czxid 创建节点事务id
ctime 创建时间
mzxid 修改节点的事务id
mtime 修改时间
pzxid 修改子节点事务id
cversion 子节点版本
dataversion数据版本
aclversion 权限版本
ephemeraOwner 临时节点的sessionid,如果不是临时节点是0
dataLength 数据长度
numchilden 子节点个数
写数据过程
1. client向zk集群的server1集器写数据
2. 如果server1不是leader就将写请求转发到leader,leader将写请求广播到其他server
3. 当leader 收到过半数的server写成功了,就会认为写成功了,然后会通知server1节点写成功了
4. server1 会通知client端写成功了
consul
选举算法
Raft算法
状态同步算法
部署架构
etcd
Eureka
AP方式
部署架构
配置中心
apollo
消息中间件
作用
解耦
减少系统的耦合
异步
加快系统响应
消峰
系统高峰期,请求留存在消息队列
使用会存在的问题
系统可用性降低
系统复杂性变高
系统数据一致性问题
常用mq的优缺点
activeMq
高可用
存在丢消息
功能完善
ms级,万级吞吐
社区不活跃
RabbitMq
万级吞吐,Elang语言开发,性能好,延迟低
社区活跃
功能强大的管理界面
RocketMq
十万级吞吐,功能完备
阿里出品,java语言开发
topic可以达到很多个
kafka
十万级吞吐
mq功能简单
容量易扩展
消息不丢
生产者不丢
消费者不丢
中间件本身不丢
做持久化
kafka
broker 部署的实例
集群每个节点都一样,没有主从之分,存储是分布式的
topic
用于消息的分类,逻辑上的概念
消息格式
一个固定长度的head 和 变长度的消息体 body 组成
partition 实现分布式存储 一个topic的消息会被分到多个partition
leader partition 主
提供读写
生产者写数据的时候,会判断ISR中副本写成功后返回ACK
ISR 存放活跃副本,会从中选新leader (根据副本响应时间在配置时间内有返回的副本放入ISR)
follow partition 副本数据
不提供读写,只作备份,leader挂了后 升级为主
副本数量可以配置成多个
leader partition 和 follow partition 不存在同一台集器
同一个组的消费者只能消费topic中的一个partition
一个组的消费者个数超过partition个数没有意义
同一个组的消费者的个数应该等于 一个topic下的partition的个数
partition下文件
多个.log文件存储数据
分多个segment文件
多个log文件,追加的消息数据
HW 高水位---是副本partition中最短的消息长度 只有水位之前的消费者才能消费
保证了数据一致性问题,消费和存储的一致性
保证了数据一致性问题,消费和存储的一致性
LEO 副本partition最大的offset
多个index文件,记录消息的偏移量
partition提高了系统的负载能力和可用性
读写都只能在主partition进行,follow partition不可以读写,只作备份
同一个topic 只能被同一个组的消费者消费
kafka依赖zk管理数据,管理offset数据
按消费者组+ topic+ partition维度维护的offest
默认端口9092
https://zhuanlan.zhihu.com/p/82998949
生产者
保证消息不丢失,不能保证不重发
ACKS = 0 kafka收到消息直接返回生产者 数据会丢失
ACKS = 1 等leader partition落库数据后 kafka返回生产者, 极限情况会丢消息
ACKS = -1 leader partition 和 ISR中的follow partition 都落库成功后 kafka返回生产者,可能会存在数据重复(写副本成功后,还没来得及返回ACK的时候leader partition挂掉了)
设置重发次数为无穷
kafka 内部保证幂等性,存数据的时候做去重 (0.1版本解决的,0.11版本支持事务)
配置参数 enable.idompotence = true
配置参数 enable.idompotence = true
消费者
pull
问题 kafka没有数据的时候,消费者可能空转在拉取空数据 (加超时时间timeout)
push
问题 难适应不同消费者消费速率不一致问题
一个消费者组中的消费者只能消费一个partition
如果消费者小于partition的时候,会做轮询消费------限制条件当前消费者组只能消费一个主题
如果消费者小于partition的时候,会做轮询消费------限制条件当前消费者组只能消费一个主题
自动回写offset 大概1秒,程序自己回写offset,自己回写offset保证消息不丢
没有被消费的消息,kafka默认存7天
保证消息的消费幂等性,不重复消费
数据库层唯一索引
存储唯一id保证幂等
pulsar
特点
发布订阅的设计模式
http://pulsar.apache.org/docs/zh-CN/next/concepts-architecture-overview/
多副本
高可用
强一致
多租户
做到跨集群
topic
持久形和非持久形
非分区topic(默认)
只被一个broker处理
分区topic
被多个broker处理
更高的吞吐量
生产者
生产者是关联到topic的程序,它发布消息到Pulsar的broker上。
同步发送
异步发送
消费者类型
MessageListener接口。在这个接口中,一旦接受到新的消息,received方法将被调用
exclusive
消费者独占 (流式消息)
Shared
多个消费者可以绑定到同一个订阅上 (队列消息)
轮询消费
不可以顺序消费
Failover
灾备 (流式消息)
多个消费者监听消息
只有一个master消费者可以消费
当master挂的时候,队列中下一个消费者消费
rabbitmq
部署架构
单机
不是高可用
伪集群
主节点存数据,从节点不存数据,会做路由提供读
主节点挂了,不可用
镜像集群
高可用,每个节点都存数据,提供读功能,主节点提供写
缺点:不是分布式的
生产者
事务
confirm模式
可能有重复消息,只能保证不丢,不能保证重发
消费者
自动响应ack
程序响应ack
保证消息不丢,消费者突然挂了会丢消息
mq收到消费者回写的ack后会删除消息
分布式锁
单JVM下锁
synchronize和ReentrantLock
多环境,多机器,多JVM下保证只用一个线程处理资源
实现方式
mysql数据库的乐观锁
redis
用起来考虑的点多,容易死锁或者锁不住 。集群中出现问题时使用 redLock 模式。
zookeeper 注意一个名词 "惊群效应"
简单,session断可能导致锁不住
分布式事务
多环境,多机器,多JVM,多模块下保证事务
XA规范
2pc
TM 事务控制
RM 资源控制
AP 应用
2pc是强一致的,数据库层的事务
过程
准备
提交
回滚
数据库资源层的锁占用事务控制
3pc
在2pc基础上引入超时,防止阻塞
TCC
柔性事务
补偿的两阶段提交
业务层的事务,最终一致
人肉回滚
对业务渗入
不在意RM模块是否支持本地事务
引入中间状态
https://www.cnblogs.com/jajian/p/10014145.html
过程
try准备
confirm确认
cancel回滚
此阶段出问题,由框架解决,不需要人肉补偿
具体落地方式
尽最大努力通知
通知方提供查询核对接口
通知方要定时发送结果通知消息
TCC两阶段补偿
业务层的事务控制
可靠消息最终一致
事务消息中间件
本地消息表,内嵌到应用
独立消息服务,单独部署的服务
mq控制分布式事务
半消息的机制
微服务
非微服务的系统问题
项目臃肿,代码工程庞大
资源无法做到隔离,例如 网关 订单对CPU和IO资源的需求不一样
无法灵活扩展
SOA与微服务
SOA是粗粒度的异构系统的通信
微服务是按业务边界细粒度的拆分和部署
DDD领域划分
基本概念
实体Entity
具有不同标志
值对象
当一个对象用于对事物进行描述而没有唯一标识时
领域服务
负责来协调这些领域对象完成操作而已,那么我们可以归类它们为领域服务
聚合及聚合根
定义领域对象之间清晰的所属关系以及边界来实现领域模型的内聚,以此来避免形成错综复杂的、难以维护的对象关系网
工厂(Factory)
创建对象
仓库 Repository
把对象的存储和访问都委托给资源库来完成
落地
确认需求
根据产品功能划分边界
根据功能点划分边界
领域上下文
ddd工程
interface 接入
application 应用逻辑
domain 领域模型
instructment 组件层
常用方法
持久层 orm 映射,持久对应实体
理论服务容错
处理高并发三大方式
缓存
限流
降级
熔断
不进行熔断: 会导致链路连锁崩溃,从而系统雪崩
指依赖的系统出现故障,而不再请求依赖系统的处理
牺牲局部,保住全局:当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用
熔断状态:
熔断关闭
熔断开启
半熔断状态
限流
接口限流
接口层的限流,令牌桶,漏桶,信号量
限制接口的线程数,通过队列缓冲
系统限流
消息队列,令牌,漏桶,滑窗
限流类型
并发数限流
QPS限流
范围: 单机限流、集群限流
限流落地
RateLimiter (令牌桶)
sential (滑窗)
资源隔离
一个接口阻塞了,导致大量线程阻塞,从而导致整个机器线程资源被占用,导致系统挂掉
措施: 对每一个接口限制线程数,进行系统资源的隔离
降级
降低系统服务能力,停掉非核心功能,保证核心功能可用
前后端配合降级
一般是自身的系统故障而降级
方式
部分不可用
全部不可用
12306夜间不可用
延迟可用
中间件
随机拒绝访问
rpc 过程调用
服务注册发现 + socket + NIO框架 + 序列化/反序列化
服务RPC方式
grpc
thrift
dubbo
RMI
序列化方式
文本序列化
xml
json
二进制序列化
dubbo
hanssion
protobuf
thrift
通信框架webservice
跨语言,跨平台
服务端提供服务接口给客户端
WSDL web服务定义语言,基于xml文本
SOAP = http + xml 简单对象访问协议
Spring-cloud
是一个生态环境: 注册中心,服务间调用,统一网关,监控,调用链
hystrisx 资源隔离熔断限流
配置参数:访问数窗口
配置参数:失败比例
固定时间内,接口超时或者失败次数,达到一定比例,进行熔断措施
配置参数: 恢复时间窗
到恢复时间,会先开放一半流量恢复请求,无问题后,全开
feign
服务调用
ribbon
负载均衡 (随机 权重 根据响应时长)
zuul
api网关(避免前端调多个后端,做接口整合,统一鉴权)
dubbo
服务框架,RPC
角色说明
Provider: 暴露服务的服务提供方(service 服务层)
Consumer: 调用远程服务的服务消费方(web 表现层)。
Registry: 服务注册与发现的注册中心(zookeeper)。
Monitor: 统计服务的调用次调和调用时间的监控中心。
Container: 服务运行容器(tomcat 容器,spring 容器)
负载均衡策略
随机模式。按权重设置随机概率。在一个截面上碰撞的概率较高,但调用越大分布越均匀
轮询模式。按公约后的权重设置轮询比例。但存在响应慢的服务提供者会累积请求
最少活跃调用数。响应快的提供者接受越多请求,响应慢的接受越少请求
一致hash。根据服务提供者ip设置hash环
容错方案
快速失败,只发起一次调用,失败立即报错
失败安全,出现异常时,直接忽略。
失败自动恢复,后台记录失败请求,定时重发。
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。
广播调用所有提供者,逐个调用,任意一台报错则报错 [2]。通常用于通知所有提供者更新缓存或日志等本地资源信息。
配置
Provider 上可以配置的 Consumer 端的属性有哪些
timeout:方法调用超时
retries:失败重试次数,默认重试 2 次
loadbalance:负载均衡算法,默认随机
actives 消费者端,最大并发调用限制
Dubbo启动时如果依赖的服务不可用会怎样?
缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,默认 check="true",可以通过 check="false" 关闭检查。
Dubbo推荐使用什么序列化框架,你知道的还有哪些?
推荐使用Hessian序列化,还有Duddo、FastJson、Java自带序列化。
Dubbo默认使用的是什么通信框架,还有别的选择吗?
Dubbo 默认使用 Netty 框架,也是推荐的选择,另外内容还集成有Mina、Grizzly。
注册了多个同一样的服务,如果测试指定的某一个服务呢?
配置环境点对点直连,绕过注册中心,将以服务接口为单位,忽略注册中心的提供者列表
当一个服务接口有多种实现时怎么做?
一个接口有多种实现时,可以用 group 属性来分组,服务提供方和消费方都指定同一个 group 即可。
服务上线怎么兼容旧版本?
可以用版本号(version)过渡,多个不同版本的服务注册到注册中心,版本号不同的服务相互间不引用
Dubbo服务之间的调用是阻塞的吗?
默认是同步等待结果阻塞的,支持异步调用
如何解决服务调用链过长的问题?
使用 Pinpoint 和 Apache Skywalking(Incubator) 实现分布式服务追踪,当然还有其他很多方案。
Dubbo的管理控制台能做什么?
控制台主要包含:路由规则,动态配置,服务降级,访问控制,权重调整,负载均衡,等管理功能。
web容器
TomCat
Jetty
适合于长链接---聊天系统
不支持JSP
Jboss
undertow
异步IO 高性能
虚拟容器
docker
k8s
部署方式
蓝绿部署
同一时刻对外提供只用一个版本
运维较复杂
滚动部署
可能会存在一时刻存在两个代码版本
运维简单
可能会产生数据错乱
灰度/金丝雀部署
一部分用户用A版本,一部分用户用B版本
ABTest发布
互联网工具
浏览器
快捷键
关闭标签: Ctrl+W
新建窗口: Ctrl+N
重新载入: F5 或 Ctrl+R
新建标签页: Ctrl+T
关闭标签:ctrl+shift+w alt+f4
前一个标签页: Ctrl+Tab
前一个标签页: Ctrl+Shift+Tab
打开上次关闭的历史页面:Ctrl + shift + t
git
是什么
代码工程管理
快捷键
git br | grep f | xargs git br -D // 删除本地多余分支
git remote prune origin // 同步远端分支
Ctrl + e // 跳到行尾
Ctrl + a //跳到行首
git branch 查看本地所有分支
-a 全部分支
-r 远端分支
-D 删除本地分支
git push origin :branch_remote_name 删除远端分支
git checkout -b 建立分支
git add . 添加全部修改文件
--all 添加全部目录
git status 查看当前状态
git pull origin --rebase 拉取分支最新
git commit -m"" 提交本地
git push origin 推到远端
-u 是建立关联
-f 是强制推到分支,覆盖之前的提交
git log 查看提交日志
git diff 对比修改
git fetch origin 同步远端新工程
新工程
git init
增加.gitignore
git add README 添加文件
git commit -m 'first commit'
git remote add origin git@github.com:linuxhex/dgraph-test.git
push
小乌龟客户端
idea
快捷键
ctrl+alt+ 右方括号或者左方括号 : 项目之间的跳转
ctrl+e: 最近浏览的文件 ***
ctrl+shift+e: 最近修改的文件 *****
ctrl+shift+a: 动作查找 ****
ctrl+shift+backspace: 上次修改位置 ******
ctrl+b : 方法调用处 ******
ctrl+alt+b : 接口方法的实现类方法 ****
ctrl+u : 父类方法或者接口方法 ****
crtl+alt+左箭头,右箭头 : 浏览过的位置跳转 *****
alt+home 定位文件夹 ***
alt + F + R 打开工程 ***
alt + f7 查找函数在哪使用 *****
alt + ~ 内置git的快捷键 ****
f12 收起右边框 ****
shift+shift: 全局搜索
ctrl+n: 迅速找到类 再按下n:可以搜索到jar包里的类
ctrl+shift+alt+n: 找到符号,函数名 多按次n找到非当前文件夹
alt+enter 智能提示+数据补齐,包提示
alt+insert : 插入文件或者目录, 补充getter setter, construct方法 ******
ctrl+alt+m: 抽取函数:当一个函数复杂很长的时候, 选中代码端, ******
Ctrl+Alt+t: 生成try catch *******
ctrl+shift +U : 大小写转换 ***
ctrl + shift + i 放大代码块用在代码review *****
shift+f9 运行调试
f8单步
f9 跳到下个断点
ctrl+shift+c mvn清理clean
ctrl+shift+b mvn编译compile
复制当前文件 f5
查看pom文件依赖, ctrl+shift+alt+u -》 ctrl+n搜索 -》 shift+del 删除依赖
ctrl+h 查看类继承关系
ctrl+f12 类成员结构 ****
ctrl+alt+L 格式化代码 *****
切换工作区域 ctrl+tab *****
esc 回到代码编写区域
alt+数字 快速切换到对应区域
ctrl + k 内置git快速提交
ctrl + shift + k 内置git快速push远端
shift + esc 隐藏边栏
ctrl + shift + ` 切换代码分支
ctrl+r 当前文件查找可以替换
ctrl + shift + r 全工程文件查找 可以替换
ctrl + t 是内置git 拉取远端更新
配置/插件
source insight
快捷键
maven
是什么
私服
快捷键
mvn dependency:purge-local-repository 强刷本地依赖包
mvn clean 清理编译文件
mvn compile 编译
生命周期
package
编译打包,不部署本地仓库和远端私服
install
编译打包,部署到本地仓库,不部署到私服
deploy
编译打包,部署到远端仓库和私服
常见报错解决
was cached in the local repository
说明依赖的包,没有下载成功
私服没有
网络问题导致没下载到
jenkins
部署
gradle
SonarQube
静态检查
wiki
jmeter
压测工具
navicat
mysql客户端
everything
metrics 监控
prometheus
charles 抓包工具
mobaXterm
Ctrl + l // 清屏幕
Ctrl + pageup // 下翻页
Ctrl + pagedown // 上翻页
Ctrl + table //移动页签
ctrl+shift+table 移动表情
bash - 退出zsh到bash
Polysh
excel
alt + enter 框内换行
Harbor
镜像仓库
Kubernetes
容器集群管理系统
禅道
提bug单
JIRA
任务跟踪
拓展技术
面试
技术广度深度
广度: 敏捷,deops,分布式,缓存,数据库,java知识
深度: 阅读源码,项目深度,开源社区
项目经验
2C, 2B,政企,金融,电信,CRUD
架构设计
负责的架构有多大,能设计多复杂的架构
基础知识
数据结构算法,计算机组成原理,操作系统,网络协议
综合
管理能力,学历,履历,软素质(表达,沟通,团队协作,价值观,性格),薪资要求
重点
数据结构与算法
设计模式
DDD领域驱动
读spring源码
设计一个秒杀系统
编程方法
编程方法学视频
设计模式
目的:软件的规范性,可复用性,可读性,扩展性,可维护性,高类聚低耦合
语言 -> 功能模块 -> 框架
设计模式应用在功能模块和框架
UML类图
类内部成员表示
+ 表示public
- 表示private
# 表示protected 和 friendly
成员表示方式 可见性 名称 :类型 [ = 缺省值]
类方法表示方式 可见性 名称(参数列表) [ : 返回类型]
类之间关系
——> 单向关联关系,直线+箭头,表示箭头指向的类是某一个类的成员
—— 双向关联, 直线,表示双方各自持有对方类型的成员变量
——> 自关联 , 直线 + 箭头 然后指向自己,表示自己包含自身的成员变量
<>—— 聚合关系,空心菱形+直线,菱形指向的类是某个类的一部分,线指向的类可以单独存在
<>—— 组合关系,实心菱形+直线,菱形指向的类是某个类的一部分,线指向的类不可以单独存在,成员与组合类同时存在同时消亡
--------> 依赖关系(方法参数,方法返回值),虚线线+箭头,箭头指向的类是某个类的方法的形参,这个类的方法功能依赖于箭头指向的类
/\
| 继承关系,上是空心三角型+直线, 三角形指向的是父类,直线连接的是子类 (泛化关系)
| 继承关系,上是空心三角型+直线, 三角形指向的是父类,直线连接的是子类 (泛化关系)
/\
| 接口实现关系,上是三角型+虚线,三角形指向的是抽象接口,虚线关联的是具体实现类 (泛化关系)
|
| 接口实现关系,上是三角型+虚线,三角形指向的是抽象接口,虚线关联的是具体实现类 (泛化关系)
|
设计模式7大原则
单一原则
一个类只做一件事,降低类的复杂度,不是指一个类就一个方法
降低更改引起的风险
开闭原则
对扩展开放,对修改关闭
用抽象构建框架,用实现扩展细节
里氏替换
继承时要遵循里氏替换
子类尽量不要重写父类方法
使用子类的地方可以透明替代父类
接口隔离
一个类对另一个类的依赖,应该建立在最小的接口上
最小接口
迪米特法则
最少知道原则
一个对象对另有一个对象保持最少了解
直接朋友
成员变量
成员方法参数
方法返回值
陌生类不要以局部变量出现在类中,只应该有直接朋友
类之间减少了不必要的依赖,降低了类之间的耦合度
依赖倒转
高层模块不应该依赖于低层模块,都应该依赖其抽象
抽象不应该依赖细节,面向接口编程
接口抽象类的价值在于设计,模块依赖应该依赖抽象不是具体实现类
成员变量尽量使用抽象类或者接口
依赖传替的方式
接口
构造器
setter方法
合成复用
使用合成聚合而不是继承
设计模式分类
创建型
原型
类比->克隆羊, 不用获取属性,直接拷贝内存,bean动态变化后可以直接克隆获取
根据已经存在的对象创建新对象,每次都需要获取原对象的属性,可以使用object的clone()方法解决
实现接口cloneable,重写clone方法,注意深拷贝问题
应用: spring中bean可以配置为原型模式或者单例
深拷贝:通过重写clone()方法实现,通过对象序列化实现
单例
减少内存使用,共享配置数据
饿汉式
启动时创建,无线程安全
静态代码块
懒汉式
使用时才创建,有线程安全问题
静态内部类
doublecheck方式
枚举方式
工厂
将实例化对象的操作抽取出来,放到一个类维护,达到与业务流程的解耦
简单工厂
静态方法实例化,工厂内部判断类型实例化对象
JDK 的calendar就是简单工厂实现
工厂方法
实例化方式抽象成统一方法,在子类具体实现,对象的实例化推迟到子类
抽象工厂
用一个工厂接口,抽象子类工厂族;具体对象类聚合抽象工厂
选择: 产品多用抽象工厂,产品少用工厂方法或者简单工厂
建造者
build,解决对象创建过程复杂,类似于盖房子,有一个流程(打地基,盖,装修),将产品和产品过程解耦
角色
产品 product
抽象建造者 builder
具体建造者 createBuilder
指挥者 director
应用: JDK中的StringBuilder类充当了建造者和指挥者的角色
结构型
代理
为目标对象提供一个替身,一般是远程对象,大对象或者需要安全控制的代理
不修改原对象,实现对对象的增强修改,代理对象要实现和原对象同样的接口,增加了对象,一旦修改目标和代理都要修改,维护麻烦
静态代理(通过继承共同对象或者实现相同的接口),JDK代理(动态在内存实现动态代理,代理对象不需要实现接口,目标代理需要实现接口),Cglib代理(修改了字节码,拦截方法)
适配器
接口适配,接口转换; 目标调用适配器接口,适配器调实际被适配者
分类
类适配器
适配器接口被客户端依赖,被具体转换类实现,具体转换类还要继承被转换类
继承方式暴露了接口,继承关系增加了耦合度
对象适配器
不是通过继承被适配类,而是通过组合的方式,通过成员变量持有被适配类
接口适配器
接口内部多方法
应用: JDK的dispatcher的handleAdapter,通过适配器来调各种controller
桥接
将行为实现与抽象分开,抽象聚合了具体实现类的接口,系统更灵活,有助于分层设计; 导致类很多,维护成本
应用: 数据库桥接,不同的数据库,JDBC的实现; 消息管理;银行转账分类
装饰
功能增强,动态的将新功能附加到对象上
就像打包一个快递,快递本身是被装饰者,快递用包装盒包装后就是装饰者
应用: 输入输出流
外观
一个高层接口,屏蔽了内部多个接口,简化调用端的使用
应用: mybatis的configuration
系统分层,对于老大型系统的维护可以使用外观模式
享元
共享技术解决大量细粒度对象,重复对象的内存浪费;内部状态:是不可更改的,外部状态: 是可以改变的
应用: string,Integer的valueof ()和 池底层都是使用的享元模式; 实现原理,经常用hashmap或者hashtable实现
组合
整体与部分的关系,类通过成员持有另一个类,公关继承父类公关函数,简化客户端的使用
应用:JDK中的hashMap
行为型
策略
应用:if else 太多
一系列算法进行了封装,可以相互替换,不会影响调用端
应用:JDK arrays的comparator接口
模板方法
通过抽取算法骨架,而将具体算法实现细节延迟到子类
应用:IOC容器初始化的时候使用了模板方法,refresh()
命令
将动作的请求者和动作的执行者分开
命令模式必须支持可以撤销,具体命令被封装成消息
invoker 调用者角色,command 命令 ,receiver 接受者,concreteRecommand 将接收者与动作绑定
应用:jdbc的templatement类
责任链
接受者对象连成一条链,并在该链上传递请求,直到有一个接受者对象处理它。通过让更多对象有机会处理请求,避免了请求发送者和接收者之间的耦合。
应用: spring MVC
状态
应用:
订单状态扭转
- 状态模式将各个状态所对应的操作分离开来,即对于不同的状态,由不同的子类实现具体操作,不同状态的切换由子类实现
解释器
一个文法或者表达式,使用解释器将其翻译
观察者
订阅模式,被观察者变化会通知所有订阅的观察者
应用: JDK中的observerable类
中介者
通过一个中介对象来协调一系列对象之间的调用
解决问题:多个类交互形成网站结构,中介者将网状变成星型
迭代器
用一致的方式遍历集合的元素,而不暴露集合内部元素细节;解决了不同集合的统一遍历
应用: JDK的arrayList
访问者
测评系统的使用
数据结构与数据操作分离,对外提供一个接待访问者的接口
备忘录
将一个对象的状态保存到另一个对象,在某些情况下可用于状态恢复
数据结构与算法
线性结构
队列
先进先出
栈
先进后出
数组实现栈
栈总大小是固定的
top表示栈顶
入栈操作: top++;stack[top] = data;
出栈操作:value = stack[top]; top--; return value;
数组
顺序存储
稀疏数组
很多数据都是一样
压缩的作用
数组实现环形队列
front 头 rear 尾
取余方式,实现环形
链表
链式存储
每个节点包含数据和next域
存在:带头节点和不带头节点的链表
单链表: 查找方向只有一个
双向链表:可以实现节点自我删除
跳跃表:
解决存储和查询的速度问题
有序链表
再链表中抽出个别节点链接成新链表
树
二叉排序树
左孩子节点小于根节点,根节点小于右孩子节点
会退化成数组
最大堆
根节点比左右孩子节点都大
最小堆
根节点比左右孩子节点都小
平衡二叉树
是二叉排序树
左右子树的高度差为1
红黑树
多用于内存存储,需要排序的结构
加入红黑节点,减少了平衡二叉树的平衡操作次数,提升性能
赫夫曼树
n个权值作为n个叶子节点
WPL带权路径长度最短
权值越大离根越近
用于数据压缩
B/B+树
区别:
b+树只有叶子节点存数据
b+树的叶子节点通过双向指针连在一起
多用于磁盘存储
多路查询树
b+比b的优势,排序范围查找
图
hash
布隆过滤器
多hash算法的筛选
一致性hash
hash环映射,一个点坏了,最坏只有一个区数据需要调整
排序算法
内部排序 (内存)
冒泡
时间 O(n2)
空间 O(1)
快排
时间 O(nlogn)
空间 O(nlogn)
插入
空间 O(n)
时间 O(n2)
选择
时间 O(n2)
空间 O(1)
希尔
时间 O(nlogn)
空间 O(1)
堆排
时间 O(nlogn)
空间 O(1)
桶排序
时间 O(n)
空间 O(n)
计数
时间 O(n)
空间 O(n)
基数排序
时间 O(n)
空间 O(n)
只能是整数,按每一位数,分到对应桶
循环次数由最大数的位数决定
外部排序 (硬盘)
查找算法
线性查找
有序无序
二分查找
有序
插值查找
加密算法
share-256 摘要算法
MD5摘要算法
AES 对称加密 加解密钥一样
DES 非对称 加解密钥不一样
BASE64 64个字符展示,8bit用6bit表示
应用+面试题目
KMP
需要记录部分匹配表
合并两个有序的链表,合并后仍然有序
字符串1和字符串2 字符串匹配
时间复杂度O(n+m)
空间复杂度O(1)
迪特斯特拉
最短路径 A*算法
以起点为出发点,进行广度优先
动态规划
解决子问题的过程中得到主问题的解, 有可能前面两步的结果可以算出本次结果
时间复杂度O(n)
空间复杂度O(1)
单链表
节点个数
是否有环
一个指针走两步,一个指针走一步,同时走,会相遇
约瑟夫
单向环形链表
先first节点首尾变环
新节点加入环
遍历结束标志 cur.next == cur
倒数第k个节点
先求出总节点数m
再遍历m-k个
单链表反转
遍历原来的链接,将遍历到的取出来放到新的链表的前面
从尾到头打印单链表
方式一:先反转,再遍历
方式二:遍历链表放入栈中,再从栈中取出来打印
分治算法
汉诺塔
递归
迷宫
最短路劲
回溯算法
八皇后
8X8的棋盘上放置8个皇后,使得任意两个皇后都不在同一条横线、竖线、斜线方向上?
棋盘的第一行开始尝试摆放第一个皇后,摆放成功后,递归一层,再遵循规则在棋盘第二行来摆放第二个皇后。如果当前位置无法摆放,则向右移动一格再次尝试,如果摆放成功,则继续递归一层,摆放第三个皇后.....
深度遍历/贪心算法
马踏棋盘
栈
深度遍历
计算 5+ 6 * 3
地理位置索引原理 GeoHash
经纬度划分网格:按照桶排序的思想,经度范围划分多个桶,维度范围划分多个桶;根据经纬度所在的桶缩小范围
bitmap
多变量占用空间,用一位表示一个
最小堆
无序数组,第k大的数
大数据
基本理论
数据量大,计算量大
Hadoop
是什么
基于HDFS和MR
基于HDFS计算数据
spark
是什么
迭代式计算
基于内存的计算,可以扩展
和hadoop联合使用,只用hadoop的存储模块
结构
内核
YRAN调度器
Spark SQL
Spark Stream
Spark 机器学习
Spark 图像处理
角色
driver 计算调度
Excutor 计算执行
工作模式
local
本地模式,利用本地多核
hive
底层: HDFS + MapReduce
依赖hadoop
flume
海量日志 采集,抽取,聚合,传输系统,读取磁盘文件传输
结构
source
对应日志数据源
channel
缓存
sink
日志流输出
功能块
Flow消息流
Event 消息处理的最小单位
每个event都有head的字节头
Agent 一个独立的Flume进程
source 以event为单位接受消息
Channel 缓存信息,确保消息被sink消费的前不会丢失
Sink 从channel中拉去数据并处理
Interceptor 是event的拦截,可以修改或者丢弃event
对比
filebeat
go语言写的,比跑在JVM的logstash占用资源少
没有logstash过滤分析数据的能力
更加轻量,部署简单,只为收集日志
logstash
配置简单
具有预处理数据功能
天生为收集日志,紧密ELK
flume
配置简单
具有数据持久化,防止丢数据
为大数据传输数据而生
DGraph
图数据库选型
neo4j
致命弊端:不支持分布式存储
DGraph
分布式存储
部分开源
go开发,潜力最好
支持PB级别的数据量查询
优点: 有类似neo4j的管理界面
风险:小公司在推,文档上,存在风险
Titan
分片存储
完全开源
本身不是数据库,依赖于其他组件,橡一个框架
缺点:依赖组件多,增加运维成本,排查问题的成本
优点:相对来说国内商用的比较多,网上资料多
JanusGraph
分布式存储
单点计算
完全开源技术门槛高
依赖的东西多,像一个框架
衍生自Titan的一个分支
解决了Titan的缺点
AI
机器学习
分类
逻辑回归
SVM
降维
流形
PCA
决策树
回归
聚类
深度学习
强化学习
区块链
0 条评论
下一页