架构师技术栈—知识(精编版)
2022-08-05 15:17:21 3 举报
AI智能生成
架构师学习技术栈理论知识精编版
作者其他创作
大纲/内容
JAVA基础
集合
Collection
List
List集合基础
实现了Collection接口
List接口特性:是有序的,元素是可重复的
允许元素为rull
常用的子类
Vector
底层结构为数组,初始容量为0,每次增长2倍
它是线程同步的,已被ArrayList替代
LinkedList
底层结构是双向链接
实现了Deque接口,因此可以像操作栈和队列一样操作即可
线程非同步
ArrayList
底层结构是数据,初始容量为0,每次增长1.5倍
线程非同步
set
set集合基础
实现了Collection接口
set接口特性:无序的,元素不可重复
底层大多数是Map结构的实现
常用的三个子类都是非同步的
常用子类
HashSet
底层数据结构是哈希表(一个元素为链表的数组)+红黑shu
实际是封装了HashMAP
元素无序,可以为null
LinkedHashSet
底层数据结构由哈希表(一个元素为链表的数组)和双向链表组成
父类是HashMAP
实际为LinkedHashMAP
元素可以为null
TreeSet
底层实际上是一个TreeMap实例(红黑树)
可以实现排序的功能
元素不能为null
Map
基础知识
存储的结构是Key-value键值对,不像Collection是单列集合
阅读Map前最好知道什么是散列表和红黑树
子类
HashMAP
底层是散列表+红黑树,初始容量为16,装载因子为0.75,每次扩容2倍
允许为null,存储无序
非同步
散列表容量大约64且链表大于8时,转成红黑树
Key的哈希值会与该值的高16位做异或操作,进一步增加随机性
当散列表的元素大于容量装载因子时,会再散列,每次扩容2倍
如果hashCode相同,key不同则替换元素,否则就是散列冲突
LinkedHashMAP
底层逻辑列表+红黑树+双向链表,父类是HashMAP
允许为null,插入有序
非同步
提供插入顺序和访问顺序两种,访问瞬息是符合LRU算法的,一般用于扩展(默认是插入顺序)
迭代与初始容量无关(迭代的是维护的双向链表)
大多使用HashMAP的API,只不过在内部重写了某些方法,维护了双向链表
TreeMap
底层是红黑树,保证了时间复杂度为log(n)
可以对其进行排序,使用Comparator或者Comparable
只要compare或者CompareTo认定该元素相等,那就相等
非同步
自然排序(动手排序),元素不能为null
ConcurrentHashMap
底层是散列表+红黑树,支持高并发操作
key和Value都不能为null
线程是安全的,利用CAS算法和部分操作上锁实现
get方法是非阻塞,无锁的,重写Node类,通过volatile修饰next来实现每次获取都是最新设置的值
在高并发环境下,统计数据(计算size.....等等)是无意义的,下一时间size值就会变化
jvm
类加载
过程
加载
链接
验证
准备
解析
初始化
类加载条件
创建实例
静态方法
静态字段
反射
初始化子类
main方法
双亲委派
先找父类
父类无,继续向下查找
ClassNotFoundException
ClassLoader主要方法
loadClass
给定一个类名,加载一个雷,返回代表这个类的Class实例,如果找不到,则返回异常
defineClass
如果给定的字节码流b定义一个类,off表示位置,len表示长度,该方法只有子类可以使用
findClass
查找一个累,也是只能子类试用,这是重载classLoader时,最重要的系统扩展点
findLoadedClass
同样,这个方案也只有子类能够只用,他会去寻找已经加载的类,这个方法是final方法,无法被修改
哪些类加载器
Bootstrap
sun.misc.Launcher$ExtClassLoader
sun.misc.LauncherSAPPClassLoader
自定义加载类
自定义加载器用于加载一些特殊途径的类,一断也是用户程序类
类加载器的缺陷和补充
SPI
上下文类加载器
重写类加载器逻辑
光加载死锁
jstack看不到死锁信息
内存布局
堆
虚拟机栈
本地方法栈
方法区(永久代)
常量池
程序技术器
直接内存
GC
算法
标记清除法
复制算法
标记整理算法
分代收集算法
GC任务
哪些内存需回收
引用计数
可达性分析
什么时间回收
finalize方法
如何回收问题
垃圾处理器
Serial串行收集器
ParNew并行收集器
Parallel Scavenge
CMS收集器
GC种类
YGC
只收集eden的GC
old GC
等同于Full GC
Full GC
Mixed GC
并发
并发基础
并发编程的优缺点
优点
充分利用多核CPU的运算能力
方便业务拆分
缺点
频繁的上下文切换
线程安全(常见的避免死锁的方式)
易混淆的概念
同步VS异步
并发VS并行
阻塞VS非阻塞
临界区VS临界资源
线程的状态和基本操作
如何新建线程
集成Thread类
实现Runnable接口
实现Callable或Runnable接口,FutureTask
线程状态的转换
NEW
RUNNABLE
WAITING
TIMED-WAITNG
TERMINATED
BLOCKED
线程的基本操作
interrupt
sleep
join
yield
守护线程Daemon
并发理论
JMM内存模型
重排序
happens-before
内存语义
内存语义的实现
并发关键字
synchronized
volatile
final
三大性质
Lock体系
Lock与synchronized
AQS
设计意图
如何使用AQS实现自定义同步组件
可重写的方法
AQS提供的模板方法
AQS源码解析
同步队列的数据结构
独占式锁
共享式锁
ReentrantLock
ReentrantReadWriteLock
Condition机制
LockSupport
并发容器
线程池
原子操作类
JUC工具
数据设计模式
数据结构
含义
非数值型程序设计中数据的组织方式及其处理的算法
4种基本逻辑结构
集合
线性结构
层次结构
网状结构
4种基本存储结构
顺序存储
链式存储
索引存储
散列存储
数组
类型相同的数据
通过下标访问,顺序存储
内存连续性
缺点
大小固定
写入需要移动元素,效率慢
链表
单链表
双向链表
循环链表
跳表
特性
跳跃表的每一层都是一条有序的链表
跳跃表的查找次数近似于层数,时间复杂度为0,插入删除也为0
最底层的链表包含所有元素
跳跃表是一种随机化的数据结构
跳跃表的空间复杂度为0
查找
由于元素是有序的,可以通过增加一些路径来加快查找速度
插入
删除
树
无序树:树中任意节点的子结点之间没有顺序关系
有序树:树种任意节点的子结点之间有顺序关系,这种树成为二叉树;
二叉树:每个节点最多含有两个子树的树成为二叉树
满二叉树:叶节点除外的所有节点均含有两个子树
完全二叉树:除最后一层外,所有层都是满节点,且最后一层缺右边连续节点的二叉树
哈夫曼树:带权路径最短的二叉树
栈
先进后出
队列
先进先出
堆
通常是一个可以被看做一棵树的数组对象。堆的决堤实现一般不通过指针域,而是通过构建一个一维数组与二叉树的父子结点进行对应,因此对总是一颗完整的二叉树
hash散列表
图
设计模式
六大原则
创造型
结构型
行为型
J2EE模式
分布式架构
分布式应用
分布式锁
redis分布式锁
直接setnx
setnx设置一个过期时间
set nx ex
set nx ex增加一个事务id
set nx +事务id+lua
redlock
zk分布式锁
临时顺序节点
分布式事务
基础知识
数据库事务
ACID(更多指数据库事务层面)
分布式理论
CAP理论
BASE理论
解决方案
两阶段提交(2PC)
三阶段提交(3PC)
补偿事务(TCC)
本地消息表
可靠事件模式(消息队列)
Sagas事务模型(最终一致性)
最大努力通知方案
基础
RPC
定义
一般用来实现部署在不同机器上的系统之间的方法调用,使得程序能够像访问本地系统资源一样,通过网络传输去访问远端系统资源
组成部分
Client Code
Serialization/Deserialization
Stub Proxy
Transport
Server Code
序列化实现
定义
序列化
是将对象的状态信息转换成为可存储或传输的形势过程
反序列化
是序列化的逆过程,将字节数组反序列化为对象,把字节序列恢复为对象的过程
注册中心
服务注册中心
Zookeeper
底层通信
I/O模型
阻塞
非阻塞
同步
异步
java I/O
Streams字节流
Writer/Reader字符流
字节流/字符流对比
NIO
缓冲区(Buffer)
通道(Channel)
Selector选择器
应用
Netty
负载实现
软负载的实现原理
目的
将请求按照某种策略分布到多台机器上,使得系统能够实现横向扩展,是应用实现可伸缩性的关键技术
定义
分布式服务架构中实现负载均衡是通过软件算法来实现的,有别于基于硬件设备实现负载均衡
原理
分布式服务框架中,负载均衡是在服务消费端实现的
负载均衡算法
随机
获取服务列表大小范围内的随机数,将该随机数作为列表索引,从服务提供列表中获取服务提供者
加权随机
在随机算法的基础上针对权重做了处理。首先根据加权数放大服务提供者列表,比如服务提供者A加权数为3,放大之后变为A,A,A,存放在新的服务提供者列表,然后对新的服务提供者列表应用随机算法
轮询
将服务调用请求按顺序轮流分配到服务提供者后端服务器上,均衡对待每一台服务提供者机器
依次按顺序获取服务提供者列表中的数据,并使用计数器记录使用过得数据索引,若数据索引到最后一个数据,则计数器归零,重新开始新的循环
加权轮询
首先根据加权数放大服务提供者列表,再在放大后的服务提供者基础上使用轮询算法获取服务提供者
源地址hash
利用请求来源的IP的hashcode对服务提供者列表大小取模,得到服务提供者列表索引,从而获取服务提供者
使用调用方ip地址的hash值,将服务列表大小取模后的值作为服务列表索引,根据该索引取值
服务治理
服务治理内容
服务注册与发现
软负载
服务质量监控与服务指标数据采集
服务分组路由
服务依赖关系分析
服务降级
服务权重调整
服务调用链路跟踪
记录负责人
实现
服务分组路由实现原理
简单服务依赖关系分析实现
服务调用链路跟踪实现原理
互联网工程
git
GIT打补丁
两个相同的repo:repo1和repo2,有修改合并
一是用git diff生成的UNIX标准补丁.diff文件
.diff文件只是记录文件改变的内容,不带有commit记录信息,多个commit可以合并成一个diff文件。
git diff 的使用方法:
创建:
git diff 【commit sha1 id】 【commit sha1 id】 > 【diff文件名】
打入:
git apply 【diff文件名】
创建:
git diff 【commit sha1 id】 【commit sha1 id】 > 【diff文件名】
打入:
git apply 【diff文件名】
二是git format-patch生成的Git专用.patch 文件。
.patch文件带有记录文件改变的内容,也带有commit记录信息,每个commit对应一个patch文件。
创建:
git format-patch HEAD^ // 最后一次提交补丁
git format-patch HEAD^^ // 最后两次提交补丁
git format-patch -1 // 最后一次提交补丁
git format-patch -2 // 最后两次提交补丁
打入:
git am 【diff文件名】
git format-patch HEAD^ // 最后一次提交补丁
git format-patch HEAD^^ // 最后两次提交补丁
git format-patch -1 // 最后一次提交补丁
git format-patch -2 // 最后两次提交补丁
打入:
git am 【diff文件名】
maven
idea
jekins
sonarQube
Nginx
Nginx是一个 轻量级/高性能的反向代理Web服务器,他实现非常高效的反向代理、负载平衡,他可以处理2-3万并发连接数,官方监测能支持5万并发,现在中国使用nginx网站用户有很多,例如:新浪、网易、 腾讯等。
Nginx性能这么高?
异步非阻塞事件处理机制:运用了epoll模型,提供了一个队列,排队解决
Nginx应用场景?
http服务器。Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。
虚拟主机。可以实现在一台服务器虚拟出多个网站,例如个人网站使用的虚拟机。
反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会应为某台服务器负载高宕机而某台服务器闲置的情况。
nginz 中也可以配置安全管理、比如可以使用Nginx搭建API接口网关,对每个接口服务进行拦截。
Nginx负载均衡的算法怎么实现的?策略有哪些?
1 轮询(默认)
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某个服务器宕机,能自动剔除故障系统。
upstream backserver {
server 192.168.0.12;
server 192.168.0.13;
}
upstream backserver {
server 192.168.0.12;
server 192.168.0.13;
}
2 权重 weight
weight的值越大分配
到的访问概率越高,主要用于后端每台服务器性能不均衡的情况下。其次是为在主从的情况下设置不同的权值,达到合理有效的地利用主机资源。
upstream backserver {
server 192.168.0.12 weight=2;
server 192.168.0.13 weight=8;
}
到的访问概率越高,主要用于后端每台服务器性能不均衡的情况下。其次是为在主从的情况下设置不同的权值,达到合理有效的地利用主机资源。
upstream backserver {
server 192.168.0.12 weight=2;
server 192.168.0.13 weight=8;
}
3 ip_hash( IP绑定)
每个请求按访问IP的哈希结果分配,使来自同一个IP的访客固定访问一台后端服务器,并且可以有效解决动态网页存在的session共享问题
upstream backserver {
ip_hash;
server 192.168.0.12:88;
server 192.168.0.13:80;
}
upstream backserver {
ip_hash;
server 192.168.0.12:88;
server 192.168.0.13:80;
}
4 fair(第三方插件)
必须安装upstream_fair模块。
对比 weight、ip_hash更加智能的负载均衡算法,fair算法可以根据页面大小和加载时间长短智能地进行负载均衡,响应时间短的优先分配。
upstream backserver {
server server1;
server server2;
fair;
}
对比 weight、ip_hash更加智能的负载均衡算法,fair算法可以根据页面大小和加载时间长短智能地进行负载均衡,响应时间短的优先分配。
upstream backserver {
server server1;
server server2;
fair;
}
5、url_hash(第三方插件)
必须安装Nginx的hash软件包
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。
upstream backserver {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。
upstream backserver {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}
Zookeeper
性能分析
高性能
寻找性能瓶颈
YSlow
yahoo的前端分析浏览器插件
firebug
firefox的插件
btrace
动态跟踪工具,能够快速定位和发现耗时方法
GC日志分析
JVM启动增加参数:-verbose:gc -Xloggc:/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
数据库慢查询
show variables like 'log_slow_queries'
查看是否启用慢日志
show variables like 'long_query_time'
查看慢于多少秒的SQL会记录到日志
my.cnf
log_slow_queries = /var/log/mysql/mysql-slow.log
日志地址
long_query_time=1
慢于多少秒记录
性能测试工具
ab:ApacheBench
ab [options] [http[s]://]localhost[:port]/path
-n
请求次数
-c
并发数
JMeter
使用JMeter进行压测的时候,可以使用jconsole、VisualVM等工具查看CPU和内存使用情况
LoadRunner
HP
商业未开源
反向代理引流
nginx调整负载权重
upstream
TCPCopy
请求复制工具,将在线请求复制到测试机器,模拟真实环境
TCPCopy Client
运行在线上,用来捕获在线请求数据包
TCPCopy Server
运行在线下测试机,用来截获响应包,并将响应包的头部信息传递给TCPCopy Client,以完成TCP交互
WEB前端
浏览器访问优化
浏览器缓存
设置http头中的Cache-Control
设置http头中的Expires
页面压缩
合理布局
CSS放在页面最上面
js放在最下边
减少cookie传输
减少数据量
静态资源独立域名
减少Http请求
合并css
合并js
合并图片
CDN加速
缓存静态资源,如图片、文件等
反向代理
动静分离
js、css等文件独立部署,使用专门的域名
图片服务
用户上传,独立部署
反向代理
提供页面缓存
DNS
DNS负载均衡
应用服务器
异步操作
削峰
加快响应速度
使用集群
代码优化
线程池
Future模式
新建线程异步获取数据,执行完一段逻辑后,使用线程对象的get()方法可获取线程内的执行结果,如未获取到,则线程阻塞
NIO
Selector 非阻塞IO机制
资源复用
单例模式
对象池
减少上下文切换
当可运行的线程大于CPU数量,则正在运行的某个线程可能就会被挂起,增加调度开销
锁竞争激烈也会导致上下文切换频繁
尽可能的缩短锁持有的时间
减少锁的粒度
将使用单独锁保护多个变量变为采用独立的锁分别进行保护
放弃使用独占锁,使用读写锁
JVM
JVM内存结构
堆heap
方法区(Method Area)/永久代(PermGen)
与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
程序计数器(Program Counter Register)
是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。
栈
JVM栈(JVM Stacks)
存储线程上下文信息,如方法参数、局部变量等
与程序计数器一样,Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
本地方法栈(Native Method Stacks)
与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。
总结:方法区和堆是所有线程共享的内存区域;而Java栈、本地方法栈和程序计数器是运行是线程私有的内存区域。
总结:方法区和堆是所有线程共享的内存区域;而Java栈、本地方法栈和程序计数器是运行是线程私有的内存区域。
对象分配规则
对象优先分配在Eden区,如果Eden区没有足够的空间时,虚拟机执行一次Minor GC。
大对象直接进入老年代(大对象是指需要大量连续内存空间的对象)。这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)
长期存活的对象进入老年代。虚拟机为每个对象定义了一个年龄计数器,如果对象经过了1次Minor GC那么对象会进入Survivor区,之后每经过一次Minor GC那么对象的年龄加1,知道达到阀值对象进入老年区。
动态判断对象的年龄。如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代
空间分配担保。每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小则进行一次Full GC,如果小于检查HandlePromotionFailure设置,如果true则只进行Monitor GC,如果false则进行Full GC。
JVM垃圾回收
新生代
Eden Space
新建对象总是在该区创建,当空间满,触发Young GC,将还未使用的独享复制到From区,Eden区则清空
From
当Eden区再次用完,再触发Young GC,将Eden和From区未使用的对象复制到To区
To
当Eden区再次用完,触发Young GC,将Eden和To区未使用的对象复制到From区,如此反复
老年代
经过多次Young GC,某些对象会在From和To多次复制,如果超过某个阈值对象还未释放,则将该对象复制到老年区。如果老年区空间用完,就会触发Full GC
垃圾回收器
Serial收集器
串行收集器是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收。
-XX:+UseSerialGC 串行收集器
ParNew收集器
ParNew收集器其实就是Serial收集器的多线程版本,新生代并行,老年代串行;新生代复制算法、老年代标记-压缩
-XX:+UseParNewGC ParNew收集器
-XX:ParallelGCThreads 限制线程数量
Parallel收集器
Parallel Scavenge收集器类似ParNew收集器,Parallel收集器更关注系统的吞吐量
-XX:+UseParallelGC 使用Parallel收集器+ 老年代串行(并行收集器)
Parallel Old 收集器
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法
-XX:+UseParallelOldGC 使用Parallel收集器+ 老年代并行(并行老年代收集器)
CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器
-XX:+UseConcMarkSweepGC 使用CMS收集器(并发收集器)
-XX:+ UseCMSCompactAtFullCollection Full GC后,进行一次碎片整理;整理过程是独占的,会引起停顿时间变长
-XX:+CMSFullGCsBeforeCompaction 设置进行几次Full GC后,进行一次碎片整理
-XX:ParallelCMSThreads 设定CMS的线程数量(一般情况约等于可用CPU数量)
G1收集器
G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征
特点
空间整合,G1收集器采用标记整理算法,不会产生内存空间碎片。分配大对象时不会因为无法找到连续空间而提前触发下一次GC。
可预测停顿,这是G1的另一大优势,降低停顿时间是G1和CMS的共同关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为N毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java(RTSJ)的垃圾收集器的特征了。
GC优化
堆设置
-Xmn:年轻代大小
-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
tomcat线程优化
maxThreads
Tomcat使用线程来处理接收的每个请求。这个值表示Tomcat可创建的最大的线程数。默认值150
acceptCount
指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理。默认值10
minSpareThreads
Tomcat初始化时创建的线程数。默认值25
maxSpareThreads
一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程。默认值75
enableLookups
是否反查域名,默认值为true。为了提高处理能力,应设置为false
connnectionTimeout
网络连接超时,默认值60000,单位:毫秒。设置为0表示永不超时,这样设置有隐患的。通常可设置为30000毫秒
maxKeepAliveRequests
保持请求数量,默认值100。 bufferSize: 输入流缓冲大小,默认值2048 bytes
compression
压缩传输,取值on/off/force,默认值off。 其中和最大连接数相关的参数为maxThreads和acceptCount。如果要加大并发连接数,应同时加大这两个参数
32G 内存配置示例:
```
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000" maxThreads="1000" minSpareThreads="60" maxSpareThreads="600" acceptCount="120"
redirectPort="8443" URIEncoding="utf-8"/>
```
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000" maxThreads="1000" minSpareThreads="60" maxSpareThreads="600" acceptCount="120"
redirectPort="8443" URIEncoding="utf-8"/>
```
存储性能优化
RAID
存储算法
HDFS分布式文件系统
关系型数据库
NoSQL
分布式缓存
文件存储
安全性
XSS跨站脚本攻击
防御
消毒:特殊字符进行转译
HttpOnly:对于存放敏感信息的cookie,可通过对该Cookie添加HttpOnly属性
分类
反射型:发布带攻击的链接
持久型:将攻击信息存到服务器数据库中
注入攻击
分类
SQL注入
OS注入
防御
消毒:特殊字符转译
参数绑定:sql预编译和参数绑定
CSRF跨站点请求伪造
核心:利用了浏览器的Cookie或服务器Session策略
防御
表单Token
验证码
Referer check
将cookie设置为HttpOnly
DDoS
SYN Flood
基于TCP的三次握手,攻击者伪造大量IP地址给服务器发送SYN报文,导致服务器接收不到客户端的ACK,服务器需要分配资源来维护本次握手,并不断重试。当等待队列占满后,服务器不再接收新的SYN请求。
DNS Query Flood
向被攻击的服务器发送海量的域名解析请求
CC
基于HTTP协议发起,通过控制大量肉鸡和互联网上大量的代理,模拟正常用户给网站发起请求,直到网站拒绝服务。
从应用层发起,与网站的业务紧密相连,使防守方进行过滤的时候进行大量的误杀,真正业务无法处理。
其他攻击手段
Error Code
程序内部错误,浏览器打印堆栈信息
Html注释
注释显示在客户端,给黑客攻击造成便利
文件上传
利用文件上传功能上传可执行程序,进而控制服务器
路径遍历
在请求的URL中使用相对路径,遍历未开放的目录及文件
防火墙
ModSecurity,开源
SiteShell
深信服
加解密
单向散列加密(摘要算法)
MD5
SHA-1
对称加密
加密与解密使用同一个密匙,远程通信的密匙交换是难题
DES
56位
3DES
AES
AES-128
AES-192
AES-256
RC
非对称加密
算法RSA
位数越大,加解密速度越慢
信息安全传输:公钥加密,私钥解密
数字签名(不可抵赖):私钥加密,公钥解密
发送发:将内容生成摘要,再用私钥将摘要进行加密生成数字签名,最后将数字签名和原文内容传输给接收方。
接收方:将原文内容采用相同的摘要算法生成摘要,再用公钥将数字签名解密成发送方的摘要,最后将两个摘要对比即可确认真伪。
算法
MD5withRSA
SHA1withRSA
数字证书
证书管理
keytool
Java的数字证书管理工具
OpenSSL
进行证书的签发与证书链的管理
高可用
高可用应用
负载均衡进行故障转移
集群的session管理
同IP会话黏滞
session服务器
redis共享session
高可用服务
分级管理
核心服务优先使用更好的硬件
不同级别的服务需要隔离,避免故障连锁反应
超时设置
超时后,通信框架抛出异常,程序选择继续重试或失效转移
异步调用
消息队列
防止关联的服务互相影响
服务降级
拒绝服务
拒绝低优先级应用的调用,减少服务调用并发数
随机拒绝
关闭功能
关闭部分不重要的服务
关闭服务内部部分不重要的功能
实施方式
基于Java的信号量机制:Semaphore
调用超时次数超过阈值,自动降级,后续来的流量直接拒绝,等超过休眠时间点,再次对服务进行重试
幂等性设计
重复调用和调用一次必须保证结果相同
异地多活机房
保证核心业务异地多活
核心数据最终一致性
采用多种手段同步数据
保证大部分用户的异地多活
高可用数据
数据失效转移机制
CAP
ACID
BASE
高可用存储
数据备份
主备复制
主从复制
主主复制
数据集群
分布式事务算法
自动化测试
工具:selenium
接口性能工具:Jmeter,loadrunner
监控
数据采集
监控管理
Linux命令
扩展性
核心思想:模块化
降低模块间的耦合性
提高模块的复用性
分层和分割,以消息传递和依赖调用聚合成完整系统
提高模块的复用性
分层和分割,以消息传递和依赖调用聚合成完整系统
分布式队列
分布式服务
伸缩性
网站架构伸缩
不同功能物理分离
相同功能集群伸缩
负载均衡器
DNS域名解析负载均衡,缺点是失效转移存在一定的时效性
反向代理(应用层负载均衡)
NGINX,七层负载,5万/每秒
数据链路层负载均衡
LVS,四层负载,80万/每秒
负载均衡算法
轮询
加权轮询
负载最低优先
LVS可以以连接数来判断
Nginx可以以HTTP请求数来判断
性能最优
响应最快,性能最优
原地址散列(哈希)
分布式缓存集群
一致性性Hash算法
数据存储服务器集群
关系型数据库集群
读写分离
分库
不同业务部署在不同的集群
分片
单表拆分,存在多个库中
支持数据分片的中间件:Cobar,缺点是只能在单一数据库实例上处理查询请求,无法执行跨库的Join操作
NoSql
HBase
以HRegion为单位进行管理
HDFS分布式文件系统
高并发
常见指标
响应时间(Response Time)
吞吐量(Throughput)
单位时间内处理的请求数量
每秒查询率QPS(Query Per Second)
每秒响应请求数。在互联网领域,这个指标和吞吐量区分的没有这么明显
并发用户数
同时承载正常使用系统功能的用户数量
如何提升并发
垂直扩展,提升单机处理能力
增强单机硬件性能
提升单机架构性能,例如:使用Cache来减少IO次数,使用异步来增加单服务吞吐量,使用无锁数据结构来减少响应时间
水平扩展(Scale Out)
增加服务器数量,就能线性扩充系统性能
反向代理层的水平扩展,是通过“DNS轮询”实现的
站点层的水平扩展,是通过“nginx”实现的
服务层的水平扩展,是通过“服务连接池”实现的(注册中心)
数据库水平拆分方式
负载均衡
LVS
Nginx
HAProxy
数据分析
A方案
日志收集
inotify机制
异步传输
ActiveMQ-CPP
实时处理
Storm
实时分布式流处理系统
存储
MySql
Hbase
高可用,高性能,可伸缩的列存储系统,支持数据表自动分区
Memcahe
HDFS
无需提供实时访问,通过如下工具进行分析与挖掘
MapReduce
Hive SQL
B方案
Chukwa
Agent
节点上采集原始数据,发送给Collector
Collector
ETL
数据解析与归档
PigLatin,MapReduce(任务)
数据分析
HICC
页面展示
故障排查
命令
jps
输出JVM虚拟机进程的一些信息,可以列出虚拟机当前执行的进程,并显示其主类和进程的ID
jstat
对虚拟机各种运行状态进行监控的工具,可以查看虚拟机的类加载和卸载情况,管理内存的使用和垃圾收集等信息
jinfo
查看应用程序的配置参数,以及打印运行JVM时所指定的JVM参数
jstack
生成虚拟机当前快照信息,线程快照是当前虚拟机每一个线程正在执行的方法堆栈的集合
jmap
用来查看等待回收对象的队列,查看堆的概要信息,包括采用的哪种GC收集器,堆空间的使用情况,以及通过JVM参数指定的各个内存空间的大小。
可以dump当前堆快照,并使用Memory Analyzer分析
BTrace
开源的Java程序动态跟踪工具,动态查看程序运行的细节,方便对程序进行调试
JConsole
JDK内置的图形化性能分析工具,对运行的java程序的性能及资源消耗情况进行分析和监控,提供可视化的图表对相关数据进行展现
Memory Analyzer(MAT)
堆分析工具,能够快速找到占用堆内存空间最大的对象
Eclipse插件,亦可独立客户端运行
VisualVM
功能十分强大,通过插件组装,可完成:内存监控、GC监控、应用程序分析、线程分析、堆dump分析、CPU,以及内存抽样、BTrace跟踪等。
重点推荐使用
远程配置方式
vi catalina.sh
找到如下内容“#—–Execute The Requested Command”,在其上添加以下配置,后重启tomcat
```
CATALINA_OPTS="$CATALINA_OPTS
-Dcom.sun.management.jmxremote
-Djava.rmi.server.hostname=192.168.23.1
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
```
找到如下内容“#—–Execute The Requested Command”,在其上添加以下配置,后重启tomcat
```
CATALINA_OPTS="$CATALINA_OPTS
-Dcom.sun.management.jmxremote
-Djava.rmi.server.hostname=192.168.23.1
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
```
软技能
不做宅男
成为自由职业者
假装自己能成功;
打造自身品牌:坚持写博客;
有效管理时间以提升效率;
学会理财:要善于炒股炒房(炒股在中国可能不算理财算赌博);
不要刷爆信用卡(这个问题可能美国人比较严重);
少看电视多运动,争取练成肌肉男。
如何和产品/测试互怼
代码重构
什么是重构
Refactoring是对软件内部结构的一种调整,目的是在不改变外部行为的前提下,提高其可理解性,降低其修改成本。
为什么重构
改进软件的设计
程序员对代码所做的为了满足短期利益代码改动,或再没有完全清楚整个架构下的改动,都很容易是代码失去它的清晰结构,偏离需求或设计。而这些改动的积累很容易使代码偏离它原先设计的初衷而变得不可理解和无法维护。
Refactoring则帮助重新组织代码,重新清晰的体现结构和进一步改进设计。
提高代码质量,更易被理解
容易理解的代码可以很容易的维护和做进一步的开发。即使对写这些代码的程序员本身,容易理解代码也可以帮助容易地做修改。程序代码也是文档。而代码首先是写给人看的,然后才是给计算机看的。
Refactoring帮助尽早的发现错(Bugs)
Refactoring是一个code review和反馈的过程。在另一个时段重新审视自己或别人代码,可以更容易的发现问题和加深对代码的理解。
Refactoring是一个良好的软件开发习惯。
Refactoring可以提高开发速度
Refactoring对设计和代码的改进,都可以有效的提高开发速度。好的设计和代码质量是提高开发速度的关键。在一个有缺陷的设计和混乱代码基础上的开发,即使表面上进度较快,但本质是延后了对设计缺陷的发现和对错误的修改,也就是延后了开发风险,最终要在开发的后期付出更多的时间和代价。
项目的维护成本远高于开发成本。
何时不该重构?
代码太混乱,设计完全错误。与其Refactor,不如重写。
明天是DeadLine
永远不要做Last-Minute-Change。推迟Refactoring,但不可以忽略,即使已经正式发布的代码都正确的运行。
Refactoring的工作量显著的影响最后期限
一个Task的计划是3天,如果为了Refactoring,需要更多的时间( 2天或更多)。推迟Refactoring,同步可以忽略。可以把这个Refactoring作为一个新的Task,或者安排在二次Refactoring中完成。
重构与设计
重构可以从很大程度上去辅助设计,通常情况下我们的设计不是能贯穿我们软件开发的全过程的,在这个过程中,我们的需求变更的可能性非常大,当需求变了,设计也得变,但是我们已有的实现怎么办?全部废除?显然不能!这时候就要依靠重构来解决这种设计的矛盾
重构与性能
关于重构,有一个常被提出的问题:它对程序的性能将造成怎样的影响?为了让软件易于理解,你常会作出一些使程序运行变慢的修改。这是个重要的问题。我并不赞成为了提高设计的纯洁性或把希望寄托于更快的硬件身上,而忽略了程序性能。已经有很多软件因为速度太慢而被用户拒绝,日益提高的机器速度亦只不过略微放宽了速度方面的限制而已。但是,换个角度说,虽然重构必然会使软件运行更慢,但它也使软件的性能优化更易进行。关键在于自己的理解,当你拥有了重构的经验,你也就有能力在重构的基础上来改进程序的性能。
重构与模式
那么真正要实现重构时,我们有哪些具体的方法呢?可以这样说,重构的准则由很多条,见《重构》这本书。但它不是最终的标准,因为你要是完全按照它的标准来执行,那你也就等于不会重构,重构是一本武功秘籍,而真正的武林高手是不用武功秘籍的,一般是“无招胜有招”。只有根据实际的需要,凭借一定的思想,才能实现符合实际的重构,我们不能被一些固定的模式套牢了,这样你的程序会很僵化。究竟如何把握这个度,需要大家去总结。
重构与思想
要想实现一个好的重构,不是重构本身,而是我们在写代码的时候,思想当中时刻有它的位置存在!非常重要!如果你本身就没想着要去重构,那么就是有再好的模式供你调用又怎么样?就是有了好的模式,你不能根据实际的需要去融会贯通,那你做出来的重构有意义么?
重构流程
Refactoring的流程
流程1
读懂代码(包括测试例子代码)
Refactoring
运行所有的Unit Tests
流程2
读懂代码
应用重构工具进行重构(如Eclipse)
重构技巧
重新组织你的函数
在对象之间搬移特性
重新组织数据
简化条件表达式
简化函数调用
0 条评论
下一页