当前位置: 首页 > news >正文

梅州兴宁网站建设培训如何看网站的流量

梅州兴宁网站建设培训,如何看网站的流量,如何建平台网站,wordpress网页怎么上传到服务器错误Java 基础 知识体系 Questions 1. HashMap 1.8与1.7的区别 1.71.8底层结构数组链表数组链表/红黑树插入方式头插法尾插法计算hash值4次位运算5次异或运算1次位运算1次异或运算扩容、插入先扩容再插入先插入再扩容扩容后位置计算重新hash原位置或原位置旧容量 (1) 扩容因子…Java 基础 知识体系 Questions 1. HashMap 1.8与1.7的区别 1.71.8底层结构数组链表数组链表/红黑树插入方式头插法尾插法计算hash值4次位运算5次异或运算1次位运算1次异或运算扩容、插入先扩容再插入先插入再扩容扩容后位置计算重新hash原位置或原位置旧容量 (1) 扩容因子默认为什么是0.75 如果扩容因子过高空间利用率提高但是哈希冲突概率增加如果扩容因子过低会造成频繁扩容哈希冲突概率降低但是空间利用率变低。选择0.75是基于泊松分布是时间和空间成本上寻求的一种折中选择 (2)为什么链表长度为8要转化为红黑树 首先和hashcode碰撞次数的泊松分布有关主要是为了寻找一种时间和空间的平衡。在负载因子0.75HashMap默认的情况下单个hash槽内元素个数为8的概率小于百万分之一将7作为一个分水岭等于7时不做转换大于等于8才转红黑树小于等于6才转链表。链表中元素个数为8时的概率已经非常小再多的就更少了所以原作者在选择链表元素个数时选择了8是根据概率统计而选择的。红黑树中的TreeNode是链表中的Node所占空间的2倍虽然红黑树的查找效率为 O ( l o g N ) O(logN) O(logN)要优于链表的 O ( N ) O(N) O(N)但是当链表长度比较小的时候即使全部遍历时间复杂度也不会太高。所以要寻找一种时间和空间的平衡即在链表长度达到一个阈值之后再转换为红黑树 2. String 、StringBuffer 、StringBuilder 的区别 是否可变线程是否安全性能String不可变安全低StringBuilder可变不安全高StringBuffer可变安全较高 3.强引用、软引用、弱引用、虚引用的区别 强引用如果一个对象具有强引用垃圾回收器绝不会回收它。当内存空间不足时JVM 宁愿抛出OOM错误使程序异常终止 软引用如果内存空间足够垃圾回收器就不会回收它。如果内存空间不足了就会回收这些对象的内存只要垃圾回收器没有回收它该对象就可以被程序使用 弱引用只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中一旦发现了只具有弱引用的对象不管当前内存空间足够与否都会回收它的内存 虚引用在任何时候都可能被垃圾回收器回收 4.和 equals 区别 如果是基本数据类型比较的是值如果是引用数据类型比较的是地址equals继承自 Object 类具体实现时可以覆盖父类的实现。如果没有复写则和 一样比较地址如果复写了则根据复写的判断方式 5.Object 类的 hashCode 方法的作用 hashCode 的哈希码主要作用是给散列表快速确定索引的通过哈希码先判断对象是否有可能相同因为相同的对象哈希码也一定相同再去用 equals() 做进一步的比较这样可以大大减少使用 equals()比较的次数 Java并发 知识体系 Questions 1.线性池了解吗参数有哪些任务到达线程池的过程线程池的大小如何设置 线程池参数 参数作用corePoolSize核心线程池大小maximumPoolSize最大线程池大小keepAliveTime线程池中超过 corePoolSize 数目的空闲线程最大存活时间可以allowCoreThreadTimeOut(true) 使得核心线程有效时间TimeUnitkeepAliveTime 时间单位workQueue阻塞任务队列threadFactory新建线程工厂RejectedExecutionHandler拒绝策略。当提交任务数超过 maxmumPoolSizeworkQueue 之和时任务会交给RejectedExecutionHandler 来处理 线程处理任务过程 当线程池小于 corePoolSize新提交任务将创建一个新线程执行任务即使此时线程池中存在空闲线程当线程池达到 corePoolSize 时新提交任务将被放入 workQueue 中等待线程池中任务调度执行当 workQueue 已满且 maximumPoolSize 大于 corePoolSize 时新提交任务会创建新线程执行任务当提交任务数超过 maximumPoolSize 时新提交任务由 RejectedExecutionHandler 处理当线程池中超过 corePoolSize 线程空闲时间达到 keepAliveTime 时关闭空闲线程 线程池的大小设置 CPU 密集型 CPU 密集的意思是该任务需要大量的运算而没有阻塞CPU 一直全速运行CPU 密集型任务尽可能的少的线程数量一般为 CPU 核数 1 个线程的线程池 IO 密集型 由于 IO 密集型任务线程并不是一直在执行任务可以多分配一点线程数如 CPU * 2也可以使用公式CPU 核数 / (1 - 阻塞系数)其中阻塞系数在 0.8 0.9 之间 2.Java乐观锁机制CAS思想缺点是否原子性 Java乐观锁机制 乐观锁体现的是悲观锁的反面。它是一种积极的思想它总是认为数据是不会被修改的所以是不会对数据上锁的。但是乐观锁在更新的时候会去判断数据是否被更新过。乐观锁的实现方案一般有两种版本号机制和 CAS。乐观锁适用于读多写少的场景这样可以提高系统的并发量。在 Java 中 java.util.concurrent.atomic下的原子变量类就是使用了乐观锁的一种实现方式 CAS 实现的。 乐观锁大多是基于数据版本 (Version)记录机制实现。即为数据增加一个版本标识在基于数据库表的版本解决方案中一般是通过为数据库表增加一个 “version” 字段来 实现。 读取出数据时将此版本号一同读出之后更新时对此版本号加一。此时将提 交数据的版本数据与数据库表对应记录的当前版本信息进行比对如果提交的数据 版本号大于数据库表当前版本号则予以更新否则认为是过期数据。 CAS思想 CAS 就是 compare and swap比较交换是一种很出名的无锁的算法就是可以不使用锁机制实现线程间的同步。使用CAS线程是不会被阻塞的所以又称为非阻塞同步。CAS 算法涉及到三个操作需要读写内存值 V 进行比较的值 A 准备写入的值 B。当且仅当 V 的值等于 A 的值等于 V 的值的时候才用 B 的值去更新 V 的值否则不会执行任何操作比较和替换是一个原子操作 A 和 V 比较V 和 B 替换一般情况下是一个自旋操作即不断重试。缺点高并发的情况下很容易发生并发冲突如果 CAS 一直失败那么就会一直重试浪费 CPU 资源。 原子性 功能限制 CAS 是能保证单个变量的操作是原子性的在 Java 中要配合使用 volatile 关键字来保证线程的安全当涉及到多个变量的时候 CAS 无能为力除此之外 CAS 实现需要硬件层面的支持在 Java 的普通用户中无法直接使用只能借助 atomic 包下的原子类实现灵活性受到了限制。 3.ReenTrantLock 使用方法底层实现和 synchronized 区别 由于 ReentrantLock 是 java.util.concurrent 包下提供的一套互斥锁相比 SynchronizedReentrantLock类提供了一些高级功能主要有以下三项 等待可中断持有锁的线程长期不释放的时候正在等待的线程可以选择放弃等待这相当于 Synchronized 来说可以避免出现死锁的情况。通过 lock.lockInterruptibly()来实现这个机制公平锁多个线程等待同一个锁时必须按照申请锁的时间顺序获得锁Synchronized 锁非公平锁ReentrantLock 默认的构造函数是创建的非公平锁可以通过参数 true 设为公平锁但公平锁表现的性能不是很好锁绑定多个条件一个 ReentrantLock 对象可以同时绑定对个对象。ReenTrantLock 提供了一个 Condition条件类用来实现分组唤醒需要唤醒的线程们而不是像 synchronized 要么随机唤醒一个线程要么唤醒全部线程 使用方法 基于 API 层面的互斥锁需要 lock() 和 unlock() 方法配合 try/finally 语句块来完成 底层实现 ReenTrantLock 的实现是一种自旋锁通过循环调用 CAS 操作来实现加锁。它的性能比较好也是因为避免了使线程进入内核态的阻塞状态。想尽办法避免线程进入内核的阻塞状态是我们去分析和理解锁设计的关键钥匙 ReenTrantLock和synchronized 的区别 1、底层实现上来说synchronized 是 JVM 层面的锁是 Java 关键字通过 monitor 对象来完成monitorenter与monitorexit对象只有在同步块或同步方法中才能调用 wait/notify 方法ReentrantLock 是从 jdk1.5 以来java.util.concurrent.locks.Lock提供的 API 层面的锁。synchronized 的实现涉及到锁的升级具体为无锁、偏向锁、自旋锁、向OS申请重量级锁ReentrantLock 实现则是通过利用 CAS CompareAndSwap自旋机制保证线程操作的原子性和 volatile 保证数据可见性以实现锁的功能 2、**是否可手动释放**synchronized 不需要用户去手动释放锁synchronized 代码执行完后系统会自动让线程释放对锁的占用 ReentrantLock 则需要用户去手动释放锁如果没有手动释放锁就可能导致死锁现象。一般通过lock() 和 unlock() 方法配合 try/finally 语句块来完成使用释放更加灵活 3、是否可中断 synchronized 是不可中断类型的锁除非加锁的代码中出现异常或正常执行完成 ReentrantLock 则可以中断可通过 trylock(long timeout,TimeUnit unit) 设置超时方法或者将 lockInterruptibly() 放到代码块中调用 interrupt 方法进行中断。 4、**是否公平锁 **synchronized 为非公平锁 ReentrantLock 则即可以选公平锁也可以选非公平锁通过构造方法new ReentrantLock 时传入 boolean 值进行选择为空默认 false 非公平锁true 为公平锁 4.介绍一下 Java 的内存模型 Java 内存模型Java Memory ModelJMM就是一种符合内存模型规范的屏蔽了各种硬件和操作系统的访问差异的保证了 Java 程序在各种平台下对内存的访问都能保证效果一致的机制及规范。JMM 是一种规范是解决由于多线程通过共享内存进行通信时存在的本地内存数据不一致、编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题。目的是保证并发编程场景中的原子性、可见性和有序性。所以Java 内存模型除了定义了一套规范还提供了一系列原语封装了底层实现后供开发者直接使用。我们前面提到并发编程要解决原子性、有序性和一致性的问题。 原子性 在 Java 中为了保证原子性提供了两个高级的字节码指令 Monitorenter 和 Monitorexit。这两个字节码在 Java 中对应的关键字就是 Synchronized。因此在 Java 中可以使用 Synchronized 来保证方法和代码块内的操作是原子性的可见性 Java 内存模型是通过在变量修改后将新值同步回主内存在变量读取前从主内存刷新变量值的这种依赖主内存作为传递媒介的方式来实现的。Java 中的 Volatile 关键字修饰的变量在被修改后可以立即同步到主内存。被其修饰的变量在每次使用之前都从主内存刷新。因此可以使用 Volatile 来保证多线程操作时变量的可见性。除了 VolatileJava 中的 Synchronized 和 Final 两个关键字也可以实现可见性。只不过实现方式不同**有序性**在 Java 中可以使用 Synchronized 和 Volatile 来保证多线程之间操作的有序性。区别Volatile 禁止指令重排。Synchronized 保证同一时刻只允许一条线程操作 5.volatile 作用底层实现单例模式中 volatile 的作用 作用 保证数据的“可见性”被 volatile 修饰的变量能够保证每个线程能够获取该变量的最新值从而避免出现数据脏读的现象。 禁止指令重排在多线程操作情况下指令重排会导致计算结果不一致。 底层实现 观察加入 volatile 关键字和没有加入 volatile 关键字时所生成的汇编代码发现加入 volatile 关键字时会多出一个 lock 前缀指令 lock 前缀指令实际上相当于一个内存屏障也成内存栅栏内存屏障会提供3个功能 它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置也不会把前面的指令排到内存屏障的后面即在执行到内存屏障这句指令时在它前面的操作已经全部完成它会强制将对缓存的修改操作立即写入主存如果是写操作它会导致其他 CPU 中对应的缓存行无效 单例模式中 volatile 的作用 防止代码读取到 instance 不为 null 时instance 引用的对象有可能还没有完成初始化 class Singleton{private volatile static Singleton instance null; //禁止指令重排private Singleton() { }public static Singleton getInstance() {if(instancenull) {synchronized (Singleton.class) {if(instancenull)instance new Singleton();}}return instance;} }6.ThreadLocal 原理 7.CAS 和 ABA 问题 8.原子类的实现原理 9.说一下 CurrentHashMap 如何实现线程安全的 JVM 知识体系 Questions 1.JVM 内存划分 2.GC 垃圾收集器 3.垃圾收集算法为什么新生代用标记-复制老年代用标记-整理 4.类加载流程 5.双亲委派机制怎么样会打破双亲委派模型 6.JVM 1.7 和 1.8 的区别 数据库 知识体系 Questions 1.MySQL的引擎了解吗默认的是哪个InnoDB 和 myISAM 的区别 myISAM: 支持表锁适合读密集的场景不支持外键不支持事务索引与数据在不同的文件非聚簇索引 InnoDB:支持行、表锁默认为行锁适合并发场景支持外键支持事务索引与数据同一文件聚簇索引 2.介绍 MVCC MVCC 是一种多版本并发控制机制在大多数情况下代替行级锁使用 MVCC能降低其系统开销。MVCC 是通过保存数据在某个时间点的快照来实现的.。不同存储引擎的 MVCC 实现是不同的典型的有乐观并发控制和悲观并发控制。InnoDB 的 MVCC 是通过在每行记录后面保存两个隐藏的列来实现的这两个列分别保存了这个行的创建时间一个保存的是行的删除时间。这里存储的并不是实际的时间值而是系统版本号(可以理解为事务的 ID)每开始一个新的事务系统版本号就会自动递增事务开始时刻的系统版本号会作为事务的 ID。InnoDB 只会查找版本早于当前事务版本的数据行(也就是行的系统版本号小于或等于事务的系统版本号)这样可以确保事务读取的行要么是在事务开始前已经存在的要么是事务自身插入或者修改过的。 3.MySQL 中一条 SQL 语句的执行过程 以查询语句为例 select * from tb_student A where A.age18 and A.name张三;先检查该语句是否有权限如果没有权限直接返回错误信息如果有权限在 MySQL8.0 版本以前会先查询缓存以这条 sql 语句为 key 在内存中查询是否有结果如果有直接缓存如果没有执行下一步通过分析器进行词法分析提取 sql 语句的关键元素比如提取上面这个语句是查询 select提取需要查询的表名为 tb_student,需要查询所有的列查询条件是这个表的 id1。然后判断这个 sql 语句是否有语法错误比如关键词是否正确等等如果检查没问题就执行下一步接下来就是优化器进行确定执行方案上面的 sql 语句可以有两种执行方案 a.先查询学生表中姓名为“张三”的学生然后判断是否年龄是18。 b.先找出学生中年龄18岁的学生然后再查询姓名为“张三”的学生。 那么优化器根据自己的优化算法进行选择执行效率最好的一个方案优化器认为有时候不一定最好。那么确认了执行计划后就准备开始执行了进行权限校验如果没有权限就会返回错误信息如果有权限就会调用数据库引擎接口返回引擎的执行结果 4.如何查看 sql 语句的执行计划用哪个关键字使用这个关键字可以得到哪些信息 用关键字 explain 来查看执行计划 5.聚簇索引和非聚簇索引的区别非聚簇索引是如何查询的 聚簇索引就是按照每张表的主键构造一颗B树同时叶子节点中存放的就是整张表的行记录数据也将聚集索引的叶子节点称为数据页。这个特性决定了索引组织表中数据也是索引的一部分每张表只能拥有一个聚簇索引。InnoDB 通过主键聚集数据如果没有定义主键InnoDB 会选择非空的唯一索引代替。如果没有这样的索引InnoDB 会隐式的定义一个主键来作为聚簇索引。 在聚簇索引之上创建的索引称之为辅助索引辅助索引访问数据总是需要二次查找。辅助索引叶子节点存储的不再是行的物理位置而是主键值。通过辅助索引首先找到的是主键值再通过主键值找到数据行的数据页再通过数据页中的 Page Directory找到数据行。InnoDB 辅助索引的叶子节点并不包含行记录的全部数据叶子节点除了包含键值外还包含了相应行数据的聚簇索引键。辅助索引的存在不影响数据在聚簇索引中的组织所以一张表可以有多个辅助索引。在 InnoDB 中有时也称辅助索引为二级索引。 二级索引需要两次索引查找 二级索引中保存的“行指针”的本质不是物理地址的指针而是行的主键值。所以通过二级索引查找行引擎需要找到二级索引的子节点获得对应主键值然后根据该值去聚簇索引找到对应行。 出现重复工作两次B-Tree查找而非一次。对于InnoDB自适应哈希索引能够减少这样重复。 6.MySQL的 ACID分别解释一下 原⼦性 事务是最⼩的执⾏单位不允许分割。事务的原⼦性确保动作要么全部完成要么全不执行 一致性 执⾏事务前后数据保持⼀致多个事务对同⼀个数据读取的结果是相同的 隔离性 并发访问数据库时⼀个⽤户的事务不被其他事务所⼲扰各并发事务之间数据库是独⽴的 持久性 ⼀个事务被提交之后。它对数据库中数据的改变是持久的即使数据库发⽣故障也不应该对其有任何影响 7.数据库索引的实现原理 MySQL 中默认的引擎为 InnoDBinnoDB 的索引使用的是 B 树实现 B 树对比 B树 的好处 IO 次数少B 树的中间结点只存放索引数据都存在叶结点中因此中间结点可以存更多的数据让索引树更加矮胖 范围查询效率更高B 树需要中序遍历整个树B 树只需要遍历叶结点中的链表 查询效率更加稳定每次查询都需要从根结点到叶结点路径长度相同所以每次查询的效率都差不多 使用 B 树索引和哈希索引的比较 哈希索引能以 O(1) 时间进行查找但是只支持精确查找无法用于部分查找和范围查找无法用于排序与分组B 树索引支持大于小于等于查找范围查找。哈希索引遇到大量哈希值相等的情况后查找效率会降低。哈希索引不支持数据的排序 8.联合索引最左前缀匹配规则 联合索引又叫复合索引。两个或更多个列上的索引被称作复合索引。对于复合索引MySQL 从左到右的使用索引中的字段一个查询可以只使用索引中的一部份但只能是最左侧部分。当最左侧字段是常量引用时索引就十分有效 优点 避免回表 两个单列查询返回行较多同时查返回行较少联合索引更高效 如何设计 等值查询中查询条件a返回的条目比较多查询条件b返回的条目比较多而同时查询a、b返回的条目比较少那么适合建立联合索引 对于有等值查询的列和范围查询的列等值查询的列建在前、范围查询的列建在后比较实用 如果联合索引列的前置列与索引单列一致那么单列查询可以用到索引这样就避免了再建单列索引因此联合索引的前置列应尽量与单列一致 **最左前缀匹配原则**在MySQL建立联合索引时会遵守最左前缀匹配原则即最左优先在检索数据时从联合索引的最左边开始匹配 9.索引怎么优化 like 语句的前导模糊查询不能使用索引联合索引最左前缀原则不能使用索引中范围条件右边的列(范围列可以用到索引)范围列之后列的索引全失效不要在索引列上面做任何操作(计算、函数)否则会导致索引失效而转向全表扫描使用短索引如果对长字符串列进行索引应该指定一个前缀长度这样能够节省大量索引空间常查询数据建立索引或者组合索引不要建立无意义的索引 10.事物隔离级别 读未提交read uncommittedRU 一个事务还没提交它的变更就能被其它事务看到读已提交read committedRC 一个事务提交后其变更才会被其他事务看到可重复读repeatable readRR 一个事务执行过程中看到的数据和该事务在启动时看到的数据一致。 自然未提交的变更对其他事务也是不可见的。一个事务启动时能够看到所有已提交的事务结果。但之后的该事务执行期间其他事务的更新对它就不可见了串行化serializable 对同行记录“写”加“写锁”“读”加“读锁”。出现读写锁冲突时后访问的事务必须等前一个事务执行完成 11.binlog、redo log、undo log binlog binlog用于记录数据库执行的写入性操作(不包括查询)信息以二进制的形式保存在磁盘中。binlog是mysql的逻辑日志并且由Server层进行记录使用任何存储引擎的mysql数据库都会记录binlog日志 使用场景 主从复制在Master端开启binlog然后将binlog发送到各个Slave端Slave端重放binlog从而达到主从数据一致数据恢复通过使用mysqlbinlog工具来恢复数据 redo log redo log包括两部分一个是内存中的日志缓冲(redo log buffer)另一个是磁盘上的日志文件(redo log file)。mysql每执行一条DML语句先将记录写入redo log buffer后续某个时间点再一次性将多个操作记录写到redo log file。这种先写日志再写磁盘的技术就是MySQL里经常说到的WAL(Write-Ahead Logging) 技术 区别 redo logbinlog文件大小redo log的大小是固定的。binlog可通过配置参数max_binlog_size设置每个binlog文件的大小。实现方式redo log是InnoDB引擎层实现的并不是所有引擎都有。binlog是Server层实现的所有引擎都可以使用 binlog日志记录方式redo log 采用循环写的方式记录当写到结尾时会回到开头循环写日志。binlog 通过追加的方式记录当文件大小大于给定值后后续的日志会记录到新的文件上适用场景redo log适用于崩溃恢复(crash-safe)binlog适用于主从复制和数据恢复 undo log undo log 主要有两个作用回滚和多版本控制(MVCC) 。在数据修改的时候不仅记录了 redo log还记录 undo log如果因为某些原因导致事务失败或回滚了可以用 undo log 进行回滚保证了原子性 。undo log 主要存储的是逻辑日志用来回滚的相反操作日志。比如我们要 insert 一条数据了那 undo log 会记录的一条对应的 delete 日志。我们要 update 一条记录时它会记录一条对应相反的 update 记录。因为 undo log 存储着修改之前的数据相当于一个前版本MVCC 实现的是读写不阻塞读的时候只要返回前一个版本的数据就行了 Spring 知识体系 Questions 1.Sping IOC AOP 的实现原理 2.Spring 事务的实现原理 3.bean 的生命周期 Redis 知识体系 Questions 1.基于 redis 的分布式锁是如何实现的 实现思想获取锁的时候使用 setnc 加锁并使用 expire 命令为锁添加一个超时时间超过该时间则自动释放锁锁的 value 值为一个随机生成的 UUID通过此在释放锁的时候进行判断获取锁的时候还设置一个获取的超时时间若超过这个时间则放弃获取锁释放锁的时候通过 UUID 判断是不是该锁若是该锁则执行 delete 进行锁释放。因为 redis 是单线程的这样的话如果4个请求打过来的话只有一个请求能获得锁获得锁即为 key 设置一个值如果这个 key 存在就设置失败也就是只有一个请求可以设置成功这个请求处理完之后会把这个 key 释放掉那么剩下等着的3个请求一定会有一个请求重新对这个 key 设置一个值再次获得锁依次类推。这样即当不同机子上的请求打过来的时候能够保证某一时刻只能有一个请求去消费资源间接地形成一种加锁的机制。 Redisson 实现 Redis 分布式锁 加锁机制客户端1面对分布式集群下首先根据 hash 节点选择一台机器发送一段 lua 脚本保证复杂业务的原子性将 key 加锁如果 key 不存在就进行加锁、设置过期时间、客户端 id 锁互斥机制如果客户端2执行同样的lua脚本代码中则会判断该锁 key 已存在紧接着判断锁 key 的 hash 数据结构中是否包含客户端2的 id如果不包含则会获得一个返回的数字代表这个锁 key 的剩余生存时间紧接着客户端2会进入 while 循环不断尝试加锁 watch dog 自动延期机制客户端1加锁有默认生存时间如果想继续持有可以在加锁成功时启动一个 watch dog看门狗后台线程每10秒检查一下如果客户端1还持有锁 key就会不断的延长锁 key 的生存时间。(是对1中如何设置有效期的优化) 可重入加锁机制 hash 数据结构中的客户端 id 加锁次数1**(是对锁只能加一次不可重入的优化)** 释放锁机制每次对数据结构中的加锁次数-1当加锁次数为0说明该客户端不持有锁此时会从 redis 里删除这个 key 另外的客户端可以尝试完成加锁。 缺点如果采用这种方案对某个 redis master 实例写入 mylock 这种锁的 value此时异步复制给对应的 master slave 实例这个过程中一旦 redis master 宕机redis slave 就变成了 redis master 会导致客户端2尝试加锁时在新的redis master 上完成了加锁而客户端1也以为自己成功加了锁。导致多个客户端对一个分布式锁完成了加锁导致各种脏数据产生。【redis 主从架构的主从异步复制导致 redis 分布式锁的最大缺陷】 2.跳表数据结构redis 中哪里用到了跳表 跳跃表skiplist是一种随机化的数据 由 William Pugh 在论文《Skip lists: a probabilistic alternative to balanced trees》中提出 跳跃表以有序的方式在层次化的链表中保存元素 效率和平衡树媲美 —— 查找、删除、添加等操作都可以在对数期望时间下完成 并且比起平衡树来说 跳跃表的实现要简单直观得多 跳跃表主要由以下部分构成 表头head负责维护跳跃表的节点指针跳跃表节点保存着元素值以及多个层层保存着指向其他元素的指针。高层的指针越过的元素数量大于等于低层的指针为了提高查找的效率程序总是从高层先开始访问然后随着元素值范围的缩小慢慢降低层次表尾全部由 NULL 组成表示跳跃表的末尾 redis 数据类型 zset 实现有序集合底层使用的数据结构是跳表 3.出现缓存雪崩、击穿、穿透的情况及解决方法 缓存雪崩 缓存雪崩指缓存同一时间大面积的失效所以后面的请求都会落到数据库上造成数据库短时间内承受大量请求而崩掉。 解决方案 Redis 高可用主从哨兵Redis cluster避免全盘崩溃本地 ehcache 缓存 hystrix 限流降级避免 MySQL 被打死缓存数据的过期时间设置随机防止同一时间大量数据过期现象发生逻辑上永不过期给每一个缓存数据增加相应的缓存标记缓存标记失效则更新数据缓存多级缓存失效时通过二级更新一级由第三方插件更新二级缓存 缓存穿透 缓存穿透是指缓存和数据库中都没有的数据导致所有的请求都落到数据库上造成数据库短时间内承受大量请求而崩掉。 解决方案 接口层增加校验如用户鉴权校验id 做基础校验id0 的直接拦截从缓存取不到的数据在数据库中也没有取到这时也可以将key-value 对写为 key-null缓存有效时间可以设置短点如30秒。这样可以防止攻击用户反复用同一个id暴力攻击采用布隆过滤器将所有可能存在的数据哈希到一个足够大的 bitmap 中一个一定不存在的数据会被这个 bitmap 拦截掉从而避免了对底层存储系统的查询压力 缓存击穿 由于并发用户特别多同时读缓存没读到数据又同时去数据库去取数据引起数据库压力瞬间增大造成过大压力。和缓存雪崩不同的是缓存击穿指并发查同一条数据缓存雪崩是不同数据都过期了很多数据都查不到从而查数据库 解决方案 设置热点数据永远不过期异步线程处理加写回操作加互斥锁查询失败默认值快速返回缓存预热 ​ 系统上线后将相关**可预期例如排行榜**热点数据直接加载到缓存 ​ 写一个缓存刷新页面手动操作热点数据**例如广告推广**上下线 4.持久化策略 RDB RDB 持久化是指在指定时间间隔内将内存中的数据集快照写入磁盘。实际上 fork 子线程先将数据集写入临时文件写入成功后在替换之前的文件用二进制压缩文件RDB 是 Redis 默认的持久化方式会在对应目录下生产一个dump.rdb 文件重启会通过加载 dump.rdb 文件恢复数据 优点 RDB 会生成多个数据文件每个文件都代表了某时刻 redis 中的所有数据这种方式非常适合做冷备可将这种完整数据文件发送到云服务器存储比如 ODPS 分布式存储以预定好的备份策略来定期备份 redis 中的数据RDB 对 Redis 对外提供的读写服务影响非常小可让 redis 保持高性能因为 redis 主进程只要 fork 一个子进程让子进程执行 RDB相对于 AOF直接基于 RDB 文件重启和恢复 redis进程更加快速 缺点 fork 耗内存copy-on-write 策略 RDB 每次在 fork 子进程来执行 RDB 快照数据文件生成的时候如果数据文件特别大可能会导致对客户端提供的服务暂停数毫秒或者甚至数秒不可控容易丢失数据 一般 RDB 每隔5分钟或者更长时间生成一次若过程中 redis 宕机就会丢失最近未持久化的数据 AOF AOF持久化是以日志的形式记录记录每一个增删操作然后追加到文件中。AOF的出现是为了弥补RDB备份的不足数据不一致性 AOF的备份策略 appendfsync always每次有数据修改发生时都会同步appendfsync everysec每秒同步一次appendsync no让操作系统决定何时进行同步 优点 更好避免数据丢失 一般AOF每隔1s通过子进程执行一次fsync最多丢1s数据append-only模式追加写 所以没有任何磁盘寻址的开销写入性能高且文件不易破损即使文件尾部破损也易修复日志文件即使过大出现后台重写操作也不会影响客户端的读写 因为在rewrite log时会压缩其中的指令创建出一份需要恢复数据的最小日志。在创建新日志时旧日志文件还是照常写入。当新的merge后的日志文件准备好时再交换新旧日志文件即可 缺点 对于同一份数据AOF日志一般比RDB快照更大恢复慢AOF开启后写QPS会比RDB的低因为AOF一般会配置成每s fsync一次日志文件当然每s一次fsync性能也还是很高的 5.主从复制原理 主从复制是指将一台redis服务器的数据复制到其他的redis服务器。前者称为主节点(master)后者称为从节点(slave)。数据的复制是单向的只能由主节点到从节点 作用 数据冗余主从复制实现了数据的热备份是持久化之外的一种数据冗余方式故障恢复当主节点出现问题时可以由从节点提供服务实现快速的故障恢复实际上是一种服务的冗余负载均衡在主从复制的基础上配合读写分离可以由主节点提供写服务由从节点提供读服务即写redis数据时应用连接主节点读redis数据时应用连接从节点分担服务器负载尤其是在写少读多的场景下通过多个从节点分担读负载可以大大提高redis服务器的并发量高可用基石除了上述作用以外主从复制还是哨兵和集群能够实施的基础因此说主从复制是redis高可用的基础 原理 通过从服务器发送到PSYNC命令给主服务器 如果是首次连接触发一次全量复制。此时主节点会启动一个后台线程生成 RDB 快照文件 主节点会将这个 RDB 发送给从节点slave 会先写入本地磁盘再从本地磁盘加载到内存中 master会将此过程中的写命令写入缓存从节点实时同步这些数据 如果网络断开了连接自动重连后主节点通过命令传播增量复制给从节点部分缺少的数据 6.数据库缓存一致性 先更新数据库再更新缓存 线程安全同时有请求A和请求B进行更新操作 线程A更新了数据库线程B更新了数据库线程B更新了缓存线程A更新了缓存 这就出现请求A更新缓存应该比请求B更新缓存早才对但是因为网络等原因B却比A更早更新了缓存。这就导致了脏数据因此不考虑 业务场景1如果你是一个写数据库场景比较多而读数据场景比较少的业务需求采用这种方案就会导致数据压根还没读到缓存就被频繁的更新浪费性能2如果你写入数据库的值并不是直接写入缓存的而是要经过一系列复杂的计算再写入缓存。那么每次写入数据库后都再次计算写入缓存的值无疑是浪费性能的。显然删除缓存更为适合 先删除缓存再更新数据库 请求A进行写操作删除缓存请求B查询发现缓存不存在请求B去数据库查询得到旧值请求B将旧值写入缓存请求A将新值写入数据库 上述情况就会导致不一致的情形出现。而且如果不采用给缓存设置过期时间策略该数据永远都是脏数据。 先更新数据库再删除缓存 请求缓存刚好失效请求A查询数据库得一个旧值请求B将新值写入数据库请求B删除缓存请求A将查到的旧值写入缓存 这样就出现脏数据了然而实际上出现的概率可能非常低因为这个条件需要发生在读缓存时缓存失效而且并发着有一个写操作。而实际上数据库的写操作会比读操作慢得多而且还要锁表而读操作必需在写操作前进入数据库操作而又要晚于写操作删除缓存所有的这些条件都具备的概率基本并不大但是还是会有出现的概率。并且假如第一步写数据库成功第二步删除缓存失败这样也导致脏数据 延时双删 先删除(淘汰)缓存再写数据库这两步和原来一样休眠1秒再次删除(淘汰)缓存 或者 先写数据库再删除(淘汰)缓存这两步和原来一样休眠1秒再次删除(淘汰)缓存 这个1秒应该看你的业务场景应该自行评估自己的项目的读数据业务逻辑的耗时然后写数据的休眠时间则在读数据业务逻辑的耗时基础上加几百ms即可这么做确保读请求结束写请求可以删除读请求造成的缓存脏数据 为了性能更快可以把第二次删除缓存可以做成异步的这样不会阻塞请求了如果再严谨点防止第二次删除缓存失败这个异步删除缓存可以加上重试机制失败一直重试直到成功 方案一 更新数据库数据缓存因为种种问题删除失败将需要删除的key发送至消息队列自己消费消息获得需要删除的key继续重试删除操作直到成功 该方案有一个缺点对业务线代码造成大量的侵入于是有了方案二启动一个订阅程序去订阅数据库的Binlog获得需要操作的数据。在应用程序中另起一段程序获得这个订阅程序传来的信息进行删除缓存操作 方案二 更新数据库数据数据库会将操作信息写入binlog日志当中订阅程序提取出所需要的数据以及key另起一段非业务代码获得该信息尝试删除缓存操作发现删除失败将这些信息发送至消息队列重新从消息队列中获得该数据重试操作 7.redis 的内存淘汰策略 volatile-ttl 在筛选时会针对设置了过期时间的键值对根据过期时间的先后进行删除越早过期的越先被删除 volatiile-random 在筛选时对设置了过期时间的键值对进行随机删除 volatile-lru 使用 lru 算法筛选设置了过期时间的键值对 volatile-lfu 使用 lfu 算法筛选设置了过期时间的键值对 优先使用 allkeys-lru 可以充分利用 lru 这一经典算法的优势把最近最常访问的数据留在缓存中提升应用的访问性能 如果业务中有置顶的需求可以使用 volatile-lru 策略同时不给这些置顶数据设置过期时间 8.redis 的 key 的过期策略 定时过期每个设置过期时间的key都需要创建一个定时器到过期时间就会立即清除。该策略可以立即清除过期的数据对内存很友好但是会占用大量的CPU资源去处理过期的数据从而影响缓存的响应时间和吞吐量 惰性过期只有当访问一个key时才会判断该key是否已过期过期则清除。该策略可以最大化地节省CPU资源却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问从而不会被清除占用大量内存 定期过期每隔一定的时间会扫描一定数量的数据库的expires字典中一定数量的key并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时可以在不同情况下使得CPU和内存资源达到最优的平衡效果 9.redis 是单线程的吗为什么这么快 单线程 没有了多线程上下文切换的性能损耗没有了访问共享资源加锁的性能损耗开发和调试非常友好可维护性高 纯内存操作 redis是一个内存数据库它的数据都存储在内存中这意味着我们读写数据都是在内存中完成这个速度是非常快的。redis是一个KV内存数据库它内部构建了一个哈希表根据指定的KEY访问时只需要O(1)的时间复杂度就可以找到对应的数据。同时redis提供了丰富的数据类型并使用高效的操作方式进行操作这些操作都在内存中进行并不会大量消耗CPU资源所以速度极快 IO 多路复用技术 redis 服务采用 Reactor 的方式来实现文件事件处理器每一个网络连接其实都对应一个文件描述符。文件事件处理器使用 I/O 多路复用模块同时监听多个 FD当 accept、read、write 和 close 文件事件产生时文件事件处理器就会回调 FD 绑定的事件处理器。虽然整个文件事件处理器是在单线程上运行的但是通过 I/O 多路复用模块的引入实现了同时对多个 FD 读写的监控提高了网络通信模型的性能同时也可以保证整个 redis 服务实现的简单
http://www.zqtcl.cn/news/741693/

相关文章:

  • 保定建站价格dw软件免费安装
  • 在建设部网站上的举报凡科网怎么建网站
  • wordpress做小说网站工作期间员工花钱做的网站
  • 婚介网站方案小说网站架构
  • 英文在线购物网站建设湖北建设厅举报网站
  • 漯河网络推广哪家好宁波网站seo公司
  • 网站设计ppt案例做物流用哪个网站好
  • 做网站官网需多少钱天元建设集团有限公司财务分析
  • 一般网站建设用什么语言网络规划设计师历年考点
  • 做网站卖菜刀需要什么手续江苏网站优化
  • 花生壳内网穿透网站如何做seo优化鞍山58同城网
  • 怎么为一个网站做外链跨境电商app
  • 医疗网站不备案seo技巧课程
  • 网页和网站有什么区别湖南省郴州市邮编
  • 公考在哪个网站上做试题武威做网站的公司
  • 河南如何做网站常州网站建设价位
  • 昆山网站建设培训班成都百度
  • 兰山网站建设郑州最好的网站建设
  • 手机网站后台源码枣庄市建设局网站
  • 网站建设傲鸿wordpress 获取分类下的文章
  • 网站运行速度优化wordpress国内优化
  • wordpress全站网易云音乐播放网站建设案例公司
  • 湘潭网站建设多少钱 报价表湘潭磐石网络北京百度seo点击器
  • 什么做的网站电子商务网站的建设的原理
  • 河北建站科技网络公司媒体平台
  • 做同城信息类网站如何赚钱石景山网站建设多少钱
  • 用ip的网站要备案吗网站的建设维护及管理制度
  • dedecms 百度网站地图南宁比优建站
  • 沈阳大熊网站建设制作怎么增加网站的权重
  • 网站建设 价格低建设网站大约多少钱