一、Java基础
1.集合(数据结构:数组 、链表、栈和队列、二叉树、堆和堆栈、散列表、红黑树)
1.1 List:元素按进入先后有序保存,可重复。
(1)ArrayList: 底层数据结构是数组,查询快,增删慢,线程不安全,效率高,可存贮重复元素;
(2)LinkList: 底层数据结构是链表,查询慢,增删快,线程不安全,效率高,可存贮重复元素;
(3)Vector: 底层数据结构是数组,查询快,增删慢,线程安全,效率低,可存贮重复元素;
1.2 Set: 仅接收一次,不可重复,并做内部排序,唯一性需重写hashcode和equals方法。
(1) HashSet: 底层数据结构采用哈希表实现,元素无序且唯一,线程不安全,效率高;
(2) ListHashSet: 底层数据结构链表+hash,有序且唯一,线程不安全,效率高;
(3) TreeSet: 底层数据结构采用二叉树实现,有序且唯一;
1.3 Map:
(1) HashMap: 非线程安全
a. 底层数据结构: 基于hash表, 数组+ 链表(jdk1.8加入红黑树);当链表的长度 >= 8的时候,将链表转换成红黑树;
红黑树数量 <= 6,红黑树转换为链表;
b. HashMap主干是一个静态内部类Entry,包含key,value,next, hash;
c. 初始化容量initialCapacity默认16,加载因子默认0.75, 实际容量 = 负载因子 x 容量,也就是 12 = 0.75 x 16;
d. 数组长度一定是2的次幂, 方便&二进制中的与运算, 减少hash冲突;
e. Hash冲突:一种是开放寻址法,另一种是链表法
两个节点的key值相同(hash值一定相同),导致冲突
两个节点的key值不同,由于hash函数的局限性导致hash值相同,导致冲突
两个节点的key值不同,hash值不同,但hash值对数组长度取模后相同,导致冲突
解决hash冲突:
链表法也正是被应用HashMap中,每一个Entry对象通过next指针指向它的下一个Entry节点。当新来的Entry映射到与之冲突的数组位置时,只需要插入到对应的链表中即可。
f. 允许使用 null 做为值(key)和键(value)
g. 解决线程安全问题:
Map<String, Integer> map = Collections.synchronizedMap(hashMap)
(2) HashTable: 线程安全,加入synchronized关键字
2.多线程
2.1 多线程状态:
线程在一定条件下,状态会发生变化。线程变化的状态转换图如下:
(1)、新建状态(New):新创建了一个线程对象。
(2)、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
(3)、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
(4)、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
(5)、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
2.2 线程调度:
- a. sleep 线程转到阻塞状态,结束后转为就绪;
- b. wait 当前线程等待,notify或notifyAll唤醒;
- c. yield 暂定当前正在执行线程对象,让相同或者优先级高的线程执行;
- d. join 等待其他线程终止,当前线程调用另一个线程join,当前线程转入阻塞,直到另一个线程结束,当前线程阻塞转为就绪,如多个线程统计累加数量。
2.3 并发编程三大特性:可见性、原子性、有序性
(1) Volatile保证变量可见性与有序性,但不能保证原子性,原子性要借助synchronized这样的锁机制。
(2)JMM内存模型
所有的变量都存储在主内存中, 总线MESI缓存一致性协议,store写回内存操作,会使其他CPU缓存地址数据无效
(3) Synchronized关键字: 锁是存在对象头里面。
a. 三种方式:
- A. 修饰普通方法: new出来的实例对象锁;
- B. 修饰静态方法: 其锁就是当前类的class对象锁;
- C. 修饰代码块: 实例对象锁;
b. synchronized底层原理: 是由一对monitorenter和monitorexit指令实现的,Monitor对象是同步的基本实现单元。
- 同步代码块是通过monitorenter和monitorexit来实现,当线程执行到monitorenter的时候要先获得monitor锁,才能执行后面的方法。当线程执行到monitorexit的时候则要释放锁。
- 同步方法是通过中设置ACC_SYNCHRONIZED标志来实现,当线程执行有ACC_SYNCHRONI标志的方法,需要获得monitor锁。
- 每个对象维护一个加锁计数器,为0表示可以被其他线程获得锁,不为0时,只有当前锁的线程才能再次获得锁。
- 同步方法和同步代码块底层都是通过monitor来实现同步的。
- 每个对象都与一个monitor相关联,线程可以占有或者释放monitor。
(4)线程池
a. Executors四种线程池:
- newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
- newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
- newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
- newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
b. 执行方法
- execute(Runnable): 接收的是一个Runnable实例,并异步执行,run()方法是void,没有返回值;
- submit(Runnable): 和execute一样,只是会返回一个Future对象,可以检测任务是否执行完毕;
- submit(Callable): 接收的是一个Callable实例,Callable接口中的call()方法有返回值,可返回任务执行结果;
- invokeAny(...): 接收的是一个Callable的集合,不会返回Future,会返回任意一个执行结果;
- invokeAll(...): 和invokeAny一样,返回Future的List;
3.设计模式
4.JVM
对象包含对象头、实例数据和填充数据三部分。
4.1 JVM构成:字节码命令:javap -v Test.class
4.2 五大内存区域
(1) 程序计数器:当前线程的行号指标号,记录虚拟机字节码指令的位置。
(2) 本地方法栈:使用native方法服务的,底层调用c或者c++;
(3) 栈:先进后出(FILO), 栈帧是一种数据结构, 入栈和出栈的一个单元。
- 局部变量表:存放方法参数和方法内部定义的局部变量。
- 操作数栈:把局部变量表里的数据、实例的字段等数据入栈。(字节码指令,压入栈)
- 动态链接:方法之间调用,符号引用和直接引用在运行时进行解析和链接的过程。
- 方法出口:方法调用完成,返回给调用方法的值。
(4) 堆:
a. 堆内存分为年轻代、老年代
b. 年轻代分为Eden(伊甸园区)和Survivor,Survivor又分为FromSpace和ToSpace。默认比例Eden:S0:S1=8:1:1。
c. Eden存放new出来的新对象,Eden内存满了,会进行minor GC, 每经历一次GC年龄+1,默认年龄阈值到达15, 进入老年代。
(5) 方法区(非堆内存):也称元空间(Metaspace), jdk1.8以前叫永久代(已废弃),存储程序运行时长期存活的对象,比如类的元 数据、方法、常量、属性等。
- MetaspaceSize :初始化元空间大小,控制发生GC阈值。
- MaxMetaspaceSize : 限制元空间大小上限,防止异常占用过多物理内存。
4.3 JVM 调优:减少fullgc次数和时间
1. 三大GC收集算法:效率:复制算法 > 标记/整理算法 > 标记/清除算法
- 标记/清除算法(最基础):老年代GC算法)
- 标记阶段:对象的header中, 遍历所有的GC Roots对象, 可达的对象(可达性分析算法)都打上一个标识。
- 清除阶段:遍历堆内存,发现某个对象没有被标记为可达对象(通过读取对象header信息),则将其收回。
- 复制算法:(新生代GC算法) 将可用内存按容量划分为大小相等的两块,每次使用其中的一块。当这一块的内存用完了,就将还存活的对象复制到另一块内存上,然后把这一块内存所有的对象一次性清理掉。Eden区中所有存活的对象都会被复制到To Survivor区,而在From Survivor区中,仍存活的对象会根据它们的年龄值决定去向,年龄值达到年龄阀值(默认为15,新生代中的对象每熬过一轮垃圾回收,年龄值就加1)的对象会被移到老年代中。
- 标记整理算法: (老年代GC算法)跟标标记清除算法类似,让所有存活的对象都向一端移动,然后直接清理掉端边线以外的内存。
2.调优工具:jconsole、VisualVM、jstat
JAVA内存管理机制及配置参数:
JAVA_OPTS="-server -Xms512m -Xmx2g -XX:+UseG1GC -XX:SurvivorRatio=6 -XX:MaxGCPauseMillis=400 -XX:G1ReservePercent=15 -XX:ParallelGCThreads=4 -XX:
ConcGCThreads=1 -XX:InitiatingHeapOccupancyPercent=40 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:../logs/gc.log"
- 设置堆内存最小和最大值,最大值参考历史利用率设置
- 设置GC垃圾收集器为G1
- 启用GC日志,方便后期分析,idea配置参数(-XX:+PrintGCDetails)
3.垃圾收集器
- 串行收集器(Serial)
比较老的收集器,单线程。收集时,必须暂停应用的工作线程,直到收集结束。 - 并行收集器(Parallel)
多条垃圾收集线程并行工作,在多核CPU下效率更高,应用线程仍然处于等待状态。 - CMS收集器(Concurrent Mark Sweep)
CMS收集器是缩短暂停应用时间为目标而设计的,是基于标记-清除算法实现,整个过程分为4个步骤,包括:- 初始标记(Initial Mark)
- 并发标记(Concurrent Mark)
- 重新标记(Remark)
- 并发清除(Concurrent Sweep)
初始标记、重新标记这两个步骤仍然需要暂停应用线程(stop the world)
4.内存溢出(OOM)
- 老年代内存不足:java.lang.OutOfMemoryError:Javaheapspace
- 永久代内存不足:java.lang.OutOfMemoryError:PermGenspace
- 代码bug,占用内存无法及时回收。
二、Spring
1.Spring IOC(反射机制)
- 依赖注入:通过诸如实例化对象,替代new对象,由Spring 容器进行管理,解耦。
- 控制反转:对象创建权交给是spring容器。
- 注入三种方式:构造方法注入,setter注入,基于注解的注入。
- 自动装配有三种模式:byType(类型模式),byName(名称模式)、constructor(构造函数模式)。
2.Spring AOP
(1) 面向切面编程,主要是日志记录、权限认证、安全控制、事务处理、异常处理。
(2) 底层原理:使用代理模式
- JDK动态代理:必须是面向接口,目标业务类必须实现接口。通过反射代理目标信息,InvokeHandler来处理。
- CGLIB动态代理:利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
如果目标对象实现了接口,默认使用JDK动态代理,也可以使用CGLIB代理;如果目标对象没有实现接口,则必须实现CGLIB。
(3) AOP注解方式:
@Aspect 注释修饰,声明为一个切面类。@Component注解注释为一个bean对象。
@Pointcut:定义切点。
@Around:环绕通知("execution(public * com.xxx.controller..*.*(..))")。
(4) 过滤器和拦截器
- Filter:依赖Servlet容器,基于函数回调,filter一般实现统一设置编码、用户是否登录、权限访问等。拦截web访问url地址。
- Interceptor:拦截器基于Java反射,使用代理模式。可以继承HandlerInterceptorAdapter类。拦截Action的访问。
3.Spring MVC
(1) 流程图
(2) 运行原理:
- 客户端发起Http请求到DispatcherServlet
- DispatcherServlet控制器寻找HanderMapping, 查询具体的Handler
- HanderMapping调用HandlerAdapter执行handler
- HandlerAdapter经过适配调用具体Controller,处理业务逻辑
- Controller处理完成将ModelAndView返回DispatcherServlet
- DispatcherServlet请求视图解析器ViewReslover解析ModelAndView
4.Spring 事务
(1) 四个原则:
- 原子性:一个事务要么全部执行,要么不执行
- 一致性:事务执行前后数据处于正确状态
- 隔离性:并发事务之间互不影响
- 持久性:事务一旦执行成功,数据永久存在
(2) 事务分类:
- 编程式事务:在业务逻辑中自行实现事务
- 声明式事务:通过XML配置或者注解@Transactional实现
(3) 隔离级别
- ISOLATION_DEFAULT:用数据库默认隔离级别
- ISOLATION_READ_UNCOMMITTED(未提交读):最低隔离级别,事务未提交,可被其他事务读取(幻读、脏读、不可重复读)
- ISOLATION_READ_COMMITTED(提交读):一个事务修改的数据提交后才能被其他事务读取(幻读、不能重复读)(Oracle默认级别)
- ISOLATION_REPEATABLE_READ(可重复读):保证多次读取同一数据是一致(幻读)(MySql默认级别)
- ISOLATION_SERIALIZABLE(序列化):代价最高最可靠的隔离级别
(4) 事务传播性:
- PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。(Spring 默认)
- PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
- PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
- PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常
- PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
- PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
- PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。
4.Mybatis
(1) 封装JDBC操作,利用反射打通Java类与SQL语句之间的相互转换
(2) 工作原理:
- 读取 MyBatis 配置文件:mybatis-config.xml
- 加载映射文件。映射文件即 SQL 映射文件
- 通过配置信息构建会话工厂 SqlSessionFactory
- 由会话工厂创建 SqlSession 对象, 包含了执行 SQL 语句的所有方法
- Executor 执行器:在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数
- 输入参数映射:输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型
- 输出结果映射:输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型
三、Spring Boot/Spring Cloud
1、原理
Eureka:注册中心,心跳机制,30时间s,最长时间90s。底层是ConcurrentHashMap实现数据存取,有多层缓存机制,读缓存,写缓存等多级。
2、Eureka服务注册与发现
(1) Euraka Server:注册中心服务端
- 服务注册: 服务提供者启动时,通过Euraka Client向Euraka Server注册元数据(IP 地址、端口、状态等信息)。Eureka采用的是ConcurrentHashMap来存储注册表信息,使用二层缓存机制来维护整个注册表。
- 提供注册表: 服务消费者调用服务,若本地没有,会去服务端Euraka Server拉取存放本地。
(2) Euraka Client:Eureka Client 会拉取、更新和缓存 Eureka Server 中的信息。
(3) Renew: 服务续约,Eureka Client 会每隔 30 秒发送一次心跳来检测续约,告知 Eureka Server 该 Eureka Client 运行正常。
如果 Eureka Server 在 90 秒内没有收到 Eureka Client 的续约,Server 端会将实例从其注册表中删除。
(4) 自我保护机制:
Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 即会进入自我保护机制。
(5) Eureka集群:
Eureka Server 高可用集群,集群相互之间通过 Replicate(复制)来同步数据,不区分主从,如果某台Euraka Server宕机,Euraka Client的请求会自动切换新的Eureka Server。
Eureka 提供了 Region(地址位置的区域)和 Zone(具体机房) 两个概念来进行分区。
(6) 工作流程:
- Eureka Server 启动成功,等待服务端注册。在启动过程中如果配置了集群,集群之间定时通过 Replicate 同步注册表,每个 Eureka Server 都存在独立完整的服务注册表信息
- Eureka Client 启动时根据配置的 Eureka Server 地址去注册中心注册服务
- Eureka Client 会每 30s 向 Eureka Server 发送一次心跳请求,证明客户端服务正常
- 当 Eureka Server 90s 内没有收到 Eureka Client 的心跳,注册中心则认为该节点失效,会注销该实例
- 单位时间内 Eureka Server 统计到有大量的 Eureka Client 没有上送心跳,则认为可能为网络异常,进入自我保护机制,不再剔除没有上送心跳的客户端
- 当 Eureka Client 心跳请求恢复正常之后,Eureka Server 自动退出自我保护模式
- Eureka Client 定时全量或者增量从注册中心获取服务注册表,并且将获取到的信息缓存到本地
- 服务调用时,Eureka Client 会先从本地缓存找寻调取的服务。如果获取不到,先从注册中心刷新注册表,再同步到本地缓存
- Eureka Client 获取到目标服务器信息,发起服务调用
- Eureka Client 程序关闭时向 Eureka Server 发送取消请求,Eureka Server 将实例从注册表中删除
3、ribbon客服端负载均衡
实现客户端负载均衡,可以自定义Ribbon Client, 也可以yml中配置负载的策略(随机、轮询、权重),默认是轮询。
4、hystrix熔断
(1) 服务雪崩效应:分布式系统中经常会出现某个基础服务不可用造成整个系统不可用的情况(如:服务器宕机、缓存击穿、程序bug等)
(2) 服务之间相互调用,分布式环境中经常出现某个服务节点故障,调用失败。熔断器就是当服务调用失败时候提供保障服务正常运行不被卡死。@HystrixCommand(fallbackMethod = "fallback")
(3) 断路器机制:hystrix存在三种状态:CLOSED、OPEN、HALF_OPEN。默认closed时,服务在一定时间内(10s) 请求次数达到了某个阀值(20次),并且错误率也达到了某个阀值(>50%)此时断路器变成了OPEN的状态, 过了一定的时间(5s)将会放行一个请求,此时变成HALF_OPEN状态,如果可以访问就变成CLOSED否则变成OPEN状态。
5、feign 基于Ribbon和Hystrix的声明式服务调用组件
JAX-RS 注意不能使用GetMapping不支持,PathVariable需设置value
6、zuul网关(通过过滤器来实现)
生命周期:
- pre Filter:这种过滤器再请求被路由之前调用。如:认证鉴权、限流等。
- route:将请求路由到微服务,构建发送给微服务的请求,HttpClient或Ribbon请求微服务。
- post:在路由到微服务执行之后执行,返回结果或者发生异常后执行的filter。
- error:发生异常,执行改filter。
7、Springcloud config 配置中心(实现方式是git管理配置)
- 环境部署之前,将所需的配置信息推送到配置仓库
- 启动配置中心服务端,将配置仓库的配置信息拉取到服务端,配置服务端对外提供REST接口
- 启动配置客户端,客户端根据 spring.cloud.config 配置的信息去服务器拉取相应的配置
8、zipkin服务追踪
分布式服务追踪,收集来自各个系统的监控数据。
- Collector 接受或者收集各个应用传输的数据
- Storage:负责存储接收到的数据,默认是存储在内存当中的,也可以支持存在MySQL当中
- API:负责查询Storage中存储的数据,主要是提供给Web UI来使用
- Web:主要是提供简单的web界面
四、redis
1、数据结构
redis是一个key-value存储系统,常见数据结构:
- String:常用命令(set,get,decr,incr,mget)value可以是String,也可以是数字。常规计数:微博数,粉丝数等
- Hash:常用命令(hget,hset,hgetall)跟map一样,适合用于存储对象,如:用户信息,商品信息等。
- List:常用命令(lpush,rpush,lpop,rpop,lrange)list就是双向链表,即可以支持反向查找和遍历。如:微博粉丝列表、最小消息排行等。
- Set:常用命令(sadd,spop,smembers,sunion)与list类似是一个列表的功能,可以自动去重复数据。如:共同好友、好友推荐。
-
Sorted Set:常用命令(zadd,zrange,zrem,zcard)和set相比,sorted set增加了一个权重参数score,能够按score进行有序排列。如:礼物排行榜,弹幕消息。
-
hyperloglog:统计页面访问量等数据。
-
GEO:用于处理地理位置的信息,可以保存地理位置,可以计算地理位置的距离。
2、分布式锁
(1) 原理
- 加锁:(setnx) key设置一个值(SET lock_key random_value NX PX 5000)
- 解锁:删除key 先判断当前锁的字符串random_value是否与传入的值相等,是的话就删除Key,解锁成功。
- 锁超时:避免死锁,给定一个过期时间。
(2) redisson实现分布式锁
- 原子性,lua脚本发送给redist。
- watch dog自动延期机制,后台守护线程,每隔10s检查。
3、缓存:数据保存在内存,存取速度快,并发能力强(mybatis二级缓存)
持久化方式:(开机的时候扫描持久化文件)
- RDB:RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照
- AOF:AOF 持久化记录服务器执行的所有写操作命令
4、缓存失效
1. 缓存过了失效时间,缓存被删除,需要更新缓存。
-
互斥锁:发起请求,将缓存中该数据上锁。无缓存,则等待数据库查询,并更新缓存。
-
设置不同的失效时间:缓存失效时间错开,加个随机数等。
2.redis内存不足时的策略
(1)noeviction: 拒绝写操作, 读、删除可以正常使用。默认策略,不建议使用;
(2)allkeys-lru: 移除最近最少使用的key,最常用的策略;
(3)allkeys-random:随机删除某个key,不建议使用;
(4)volatile-lru:在设置了过期时间的key中,移除最近最少使用的key,不建议使用;
(5)volatile-random:在设置了过期时间的key中,随机删除某个key,不建议使用;
(6)volatile-ttl: 在设置了过期时间的key中,把最早要过期的key优先删除。
5、缓存雪崩
(1) 雪崩:网络不稳定或服务器宕机,服务调用者阻塞,引发雪崩连锁效应。
(2) 缓存雪崩:当缓存服务器重启或者大量缓存集中在某一个时间段失效,直接访问数据库,数据库宕机,从而造成系统的崩溃。
(3) 雪崩解决方案:
- 熔断模式:使用Hystrix(熔断、降级、限流)一旦发现当前服务的请求失败率达到预设的值,Hystrix将会拒绝随后该服务的所有请求,直接返回一个预设的结果。这就是所谓的“熔断”。
- 隔离模式:缓存失效后,通过枷锁,对某个key只允许一个线程查询数据和写缓存。
- 限流模式:对请求设置最高的QPS阈值,高于阈值直接返回。
6、缓存穿透
一般缓存系统,都是按照key去缓存查询数据,如果不存在对应的value,就去数据库查询。频繁访问数据库,这就叫缓存穿透。
1.缓存空数据:查询结果为空的key也存储在缓存中,该key的查询请求时,缓存直接返回null,而无需查询数据库。
2.BloomFilter(推荐):bloomFilter就类似一个hashset(bigmap),判断某个key是否存在,不存在直接返回null。
7、集群(高可用、可扩展性、分布式、容错)
- 主从复制
将Master(读写操作)的数据自动同步到Slave数据库。
实现原理:
- 从服务器向主服务器发送SYNC命令
- 主服务器收到SYNC命令后,执行BGSAVE命令,在后台生成RDB文件,使用缓冲区记录从现在开始执行的所有的写命令。
- 当主服务器的BGSAVE命令执行完毕后,主服务器后将BGSAVE命令生成的RDB文件发送给从服务器,从服务器接收并载入这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态。
- 主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。
缺点:master 宕机需要手动将slave提升为master。
- 哨兵模式
Redis Sentinel(哨兵):节点数量要满足 2n+1奇数个。
Sentinel功能:
- 监控主从数据库是否正常运行
- master出现故障时,自动将slave转化为master
- 多哨兵配置的时候,哨兵之间也会自动监控
- 多个哨兵可以监控同一个redis
缺点:Redis较难支持在线扩容,选举leader(slave转化为master)时候服务无法工作。
- Cluster集群(3.0版本)推荐使用
(1) Redis Cluster是多个Redis主从节点,在分区期间还提供了一定程度的可用性。
(2) Redis集群数据分片,分片采用slot(槽)的概念,一共分成16384个槽。对于每个进入Redis的键值对,每个key通过CRC16校验,分配到这16384个slot中的某一个中。
比如当前集群有3个节点:(slots)默认是平均分配槽,推荐工具redis client
-
节点 A 包含 0 到 5500号哈希槽;
-
节点 B 包含5501 到 11000 号哈希槽;
-
节点 C 包含11001 到 16384号哈希槽;
(3) 扩容
-
增加节点的顺序是先增加Master主节点,然后在增加Slave从节点
-
分配数据槽,从其他节点分配槽。
五、数据库
1.mysql
1. InnoDB:存储引擎,支持行锁(B+Tree)
局部内存,按照页取数据,每页16kb,放在内存中 每行数据最多存65535个字节 占位符3个
数据插入的时候是B+Tree聚集索引
按照主键创建索引,没有使用唯一索引,没有才使用rowId
2. myISAM:非聚集性索引
3. mysql explain 详解
explain查看sql执行计划,查看sql有没有使用索引,有没有全表扫描。
- id:选择标识符
- select_type:表示查询的类型。
- table:输出结果集的表
- partitions:匹配的分区
- type:表示表的连接类型
- possible_keys:表示查询时,可能使用的索引
- key:表示实际使用的索引
- key_len:索引字段的长度
- ref:列与索引的比较
- rows:扫描出的行数(估算的行数)
- filtered:按表条件过滤的行百分比
- Extra:执行情况的描述和说明
2. Sql优化
- sql避免全表扫描,避免 ‘ * ‘ 或 is null 或 != 或 <> 或 or 等查询
- 尽量使用(NOT) EXISTS 替代( NOT)IN
- 通配符%,like '%c%'不会使用索引,而 like 'c%'会使用所有
- 合理的建立索引能够加速数据读取效率,不合理的建立索引反而会拖慢数据库的响应速度
- 索引越多,更新数据的速度越慢
- 尽量用union all代替union
- 对于联合索引来说,要遵守最左前缀法则,创建联合索引的时候一定要注意索引字段顺序,常用的查询字段放在最前面。
3. Oracle
(1) LATCH:Latch是用于保护SGA区数据结构的一种串行化锁定机制,对内存数据结构提供互斥访问的一种机制。
(2) Latch和Lock的区别:
- Latch是对内存数据结构提供互斥访问的一种机制,而Lock是以不同的模式来套取共享资源对象,各个模式间存在着兼容或排斥,从这点看出,Latch的访问,包括查询也是互斥的,任何时候,只能有一个进程能pin住内存的某一块,幸好这个过程是相当的短暂,否则系统性能将没的保障,现在从9I开始,允许多个进程同时查询相同的内存块,但性能并没有想象中的好。
- Latch只作用于内存中,他只能被当前实例访问,而L ock作用于数据库对象,在RAC体系中实例间允许Lock检测与访问
- Latch是瞬间的占用,释放,Lock的释放需要等到事务正确的结束,他占用的时间长短由事务大小决定
- Latch是非入队的,而Lock是入队的
- Latch不存在死锁,而Lock中存在(死锁在Oracle中是非常少见的)
(3) 按锁的机制分类
排他锁( X ):如果事务T对对象A加上排他锁,则只允许T对A对象读取和修改,其他事务不能对A增加任何锁,直到T释放加载A上的排他锁
共享锁( S ):如果事务T对表A加上共享锁,则事务T可以读该表,但是不能修改该表数据。其他事务也只能对该对象加上共享锁,但是不能加上排他锁。这就保证了其他事务可以读A表数据,但是不能修改A表数据(这就不会影响到读该表的事务了,有利于并发操作)。
(4) 按操作行为分类
- DML Locks 保证并发情况下的数据完整性
- Row Locks (TX) 称为行级锁。当事务执行 DML 语句(INSERT, UPDATE, DELETE, and SELECT with the FOR UPDATE clause)时会申请TX 类型的锁,TX 的机制是排他锁。
- Table Locks (TM) 称为表级锁。当Oracle执行 DML 语句时,系统自动在所要操作的表上申请TM类型的锁。
- DDL Locks 用于保护数据库对象的结构
- 排他DDL锁(Exclusive DDL lock):阻塞其他会话得到该对象的DDL锁或DML锁。在DDL操作期间你可以查询一个表,但是无法以任何方式修改这个表。
- 共享DDL锁(Share DDL lock):保护所引用对象的结构,使其结构不会被其他会话修改
- System Locks 保护数据库的内部结构