zoukankan      html  css  js  c++  java
  • java基础知识

    一: reids

    1:redis 数据持久化

    RDB:指定的时间间隔内保存数据快照

         1、编辑 redis.conf    注:使用whereis redis命令查看redis安装在哪个位置,然后进入redis安装目录的etc目录下,编辑redis.conf。通过备份的方式来实现

          缺点:  因为是特定条件下进行一次持久化(每隔一段时间),就可能会导致一旦redis崩溃,再次回复时,可能会导致部分数据丢失。

           注:如果设置的备份时间间隔较短,比较耗服务器性能,如果设置的备份时间间隔较长,又可能会导致数据恢复时部分数据丢失。

    2:AOF持久化方案

           先把命令追加到操作日志的尾部,保存所有的历史操作。

           1、相比于RDB持久化方案的优点:

             (1)数据非常完整,故障恢复丢失数据少

             (2)可对历史操作进行处理

            将redis.conf 配置文件中的appendonly 参数改为yes 后,则redis开始启动AOF数据持久化模式

    3、RDB模式和AOF模式的恢复

     

    2: redis 的缓冲穿透与 雪崩的解决方式

     缓冲穿透:

     缓存穿透是指查询一个根本不存在的数据,缓存层和持久层都不会命中。在日常工作中出于容错的考虑,
    如果从持久层查不到数据则不写入缓存层,缓存穿透将导致不存在的数据每次请求都要到持久层去查询,失去了缓存保护后端持久的意义
     

    解决方法:

     2.1: 

    ,如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

     2.2:

     最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。

    缓冲雪崩

    缓存雪崩是指缓存大量失效,导致大量的请求都直接向数据库获取数据,造成数据库的压力。缓存大量失效的原因可能是缓存服务器宏机,或者大量Redis的键设置的过期时间相同。

      Redis不可能把所有的数据都缓存起来(内存昂贵且有限),所以Redis需要对数据设置过期时间,并采用的是惰性删除+定期删除两种策略对过期键删除。Redis对过期键的策略+持久化

      如果缓存数据设置的过期时间是相同的,并且Redis恰好将这部分数据全部删光了。这就会导致在这段时间内,这些缓存同时失效,全部请求到数据库中。

    解决方案

      对缓存数据设置相同的过期时间,导致某段时间内缓存失效,请求全部走数据库。”这种情况,非常好解决:

         解决方法:1、在缓存的时候给过期时间加上一个随机值,这样就会大幅度的减少缓存在同一时间过期。

     对于“Redis挂掉了,请求全部走数据库”这种情况,我们可以有以下的思路:
    事发前:实现Redis的高可用(主从架构+Sentinel(哨兵) 或者Redis Cluster(集群)),尽量避免Redis挂掉这种情况发生。
    事发中:万一Redis真的挂了,我们可以设置本地缓存(ehcache)+限流(hystrix),尽量避免我们的数据库被干掉(起码能保证我们的服务还是能正常工作的)
    事发后:redis持久化,重启后自动从磁盘上加载数据,快速恢复缓存数据。

    3: redis 的缓冲击穿

     缓冲击穿:

    系统中存在以下两个问题时需要引起注意: 当前key是一个热点key(例如一个秒杀活动),并发量非常大。 重建缓存不能在短时间完成,可能是一个复杂计算,例如复杂的SQL、多次IO、多个依赖等。 在缓存失效的瞬间,有大量线程来重建缓存,造成后端负载加大,甚至可能会让应用崩溃

    解决方案:

     1:分布式互斥锁

          只允许一个线程重建缓存,其他线程等待重建缓存的线程执行完,重新从缓存获取数据即可。set(key,value,timeout)

     2:设置永不过期时间

        从缓存层面来看,确实没有设置过期时间,所以不会出现热点key过期后产生的问题,也就是“物理”不过期。

        从功能层面来看,为每个value设置一个逻辑过期时间,当发现超过逻辑过期时间后,会使用单独的线程去更新缓

    2种方案对比:

    分布式互斥锁:这种方案思路比较简单,但是存在一定的隐患,如果在查询数据库 + 和 重建缓存(key失效后进行了大量的计算)时间过长,也可能会存在死锁和线程池阻塞的风险,高并发情景下吞吐量会大大降低!但是这种方法能够较好地降低后端存储负载,并在一致性上做得比较好。

    “永远不过期”:这种方案由于没有设置真正的过期时间,实际上已经不存在热点key产生的一系列危害,但是会存在数据不一致的情况,同时代码复杂度会增大。

    4:redis 的并发竞争问题如何解决

     redis  的并发竞争问题是什么

     

    多个客户端同时并发写入一个key,可能本来先写入到的数据 后到了,导致数据版本错了
    
    或许 多个客户端同时获取一个key,修改值后在写回去,只要顺序错了,数据就错了

    这里的并发指的是多个redis的client同时set key引起的并发问题。

     解决方法

    1: 分布式锁加 时间戳 ,加一把分布式锁,大家去抢锁,抢到锁就进行set 操作, 加锁的目的是吧一些并行读写的方式改为了串行读写

    2:利用消息队里      在并发量过大的情况下,可以通过消息中间件进行处理,把并行读写进行串行化。把Redis.set操作放在队列中使其串行化,必须的一个一个执行。


    5: redis 的缓冲失效策略与主键失效机制

      惰性过期

       1:访问key 的时候判断key 是否过期,过期则清除,对内存不够友好,对cpu友好

      定期过期

        隔一段 时间去扫描一次,会扫描一定数量的key,并清除过期的key

    6: redis 的事务,以及分布式锁

     redis 的事务机制

     

     分布式锁
    7: redis 的同步机制

    8:简述 redis 的事务实现 

    9: 缓存与数据库双写一致

    二:mq 

     1: 如何解决重复消费

     2:mq 数据丢失怎么解决(数据丢失分为 生产者丢失数据,消费者丢失数据,mq 本身丢失数据)

        2.1:  生产者丢失数据

        2.2: 消费者丢失数据

        2.3 :mq 丢失数据

    3:    如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路。

    4: 如何保证mq 的高可用的

    5:  如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?

    6:  那如何保证消息的顺序性?

    三:线程问题

    1:  线程池,怎么设置核心线程池

    2:如果有50 个任务,队列是100,有两个核心线程池,最大线程池是4 个,这时候会运行几个线程

    3:   线程池的拒绝策略

    4:callback 线程返回值是什么

    5: 比如有10 个线程,7个线程运行完毕,怎么让退出线程

    四:sql 问题

    1:什么是回表操作,使用索引查询时如何尽量的避免回表操作

    2:mysql 的索引有哪些 结构

    3:hash 索引 2 b+tree 树索引,就是平衡二叉树,左子树节点小于父节点
    右子树节点大于父节点

    4:什么情况下使用 hash 树,以及b+tree 树

    5:联合索引,最左匹配原则

    6:  什么情况下明明创建了索引,当是执行的时候并没有通过索引

    7:  数据的事务级别这块

    8:  数据库查询如何优化,怎么减少回表操作,索引如何加,索引过多有什么坏处

    9:分库分表后怎么关联查询,这块是怎么做到分布式事务一致性的问题

    五: 事务问题

    一:spring 的事务是怎么执行处理的,多个service 层的话,事务会同时回滚吗?如果会回滚怎么保证 不想被回滚的service 层不被回滚, 为什么会回滚

    事务特性(4种):
    原子性 (atomicity):强调事务的不可分割.
    一致性 (consistency):事务的执行的前后数据的完整性保持一致.
    隔离性 (isolation):一个事务执行的过程中,不应该受到其他事务的干扰
    持久性(durability) :事务一旦结束,数据就持久到数据库
    如果不考虑隔离性引发安全性问题:
    脏读 :一个事务读到了另一个事务的未提交的数据
    不可重复读 :一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致.
    虚幻读 :一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致.
    
    
    
    解决读问题: 设置事务隔离级别(5种)
    DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
    未提交读(read uncommited) :脏读,不可重复读,虚读都有可能发生
    已提交读 (read commited):避免脏读。但是不可重复读和虚读有可能发生
    可重复读 (repeatable read) :避免脏读和不可重复读.但是虚读有可能发生.
    串行化的 (serializable) :避免以上所有读问题.
    Mysql 默认:可重复读
    Oracle 默认:读已提交
    
    
    
    
    
    read uncommited:是最低的事务隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。
    read commited:保证一个事物提交后才能被另外一个事务读取。另外一个事务不能读取该事物未提交的数据。
    repeatable read:这种事务隔离级别可以防止脏读,不可重复读。但是可能会出现幻象读。它除了保证一个事务不能被另外一个事务读取未提交的数据之外还避免了以下情况产生(不可重复读)。
    serializable:这是花费最高代价但最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读之外,还避免了幻象读(避免三种)。
    
    二: spring 事务的传播方式
    * 保证同一个事务中 propagion_required: 支持当前事务,如果不存在 就新建一个(默认) propagion_supports: 支持当前事务,如果不存在,就不使用事务 propagion_mandatory: 支持当前事务,如果不存在,抛出异常 * 保证没有在同一个事务中 propagion_requires_new: 如果有事务存在,挂起当前事务,创建一个新的事务 propagion_not_supported: 以非事务方式运行,如果有事务存在,挂起当前事务 propagion_never: 以非事务方式运行,如果有事务存在,抛出异常 propagion_nested: 如果当前事务存在,则嵌套事务执行

    数据库是怎么保证在断电的情况下,保持消息一致性的

    六:微服务

    1: 微服务的时候怎么进行服务之间的调用,用什么技术来处理的。

          使用Feign  A服务调用 b 服务的service层,B服务提供接口,使用feign走restful的调用形式

    2: gateway 的流程

    1:当我们的请求到达了gatewat 网关  ,网关先利用断言,来判定这次请求是不是符合某个路由规则,如果符合了就按这个路由贵州给他路由到指定地方,去这些指定地方就要经过一系列的filter 来指定

    难点就是 如何制定路由规则,这些断言如何判断失败

    3: apollo

     apollo 是如何实现配置回滚的

    1:apollo 没吃发布都会在release 库里面生成一个版本,每次回退的是 覆盖表的版本,回退到上一个版本

    七: 分布式  

        7.1:分布式事务

         

           1:分布式的事务怎么实现

            2:什么是分布式事务,保证了什么:

               就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分         布式事务就是为了保证不同数据库的数据一致性。

            cap 原则与定理

            base 理论:我们无法做到强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性

            解决方案:

             1: 基于XA 协议的两阶段提交

                  XA 是一个分布式 事务协议,大致分为两个部分,事务管理器以及本地资源管理器

                   本地资源管理器: 右数据实现,比如Oracle ,DB2这些商业数据库都实现了XA 接口。

                   事务管理器:作为了全局的调度者,负责各个本地资源的提交与回滚。

            实现思路:

               总的来说,XA协议比较简单,而且一旦商业数据库实现了XA协议,使用分布式事务的成本也比较低。但是,XA也有致命的缺点,那就是性能不理想,特别是在交易下单链路,往往             并发量很高,XA无法满足高并发场景。XA目前在商业数据库支持的比较理想,在mysql数据库中支持的不太理想,mysql的XA实现,没有记录prepare阶段日志,主备切换回导致主              库与备库数据不一致。许多nosql也没有支持XA,这让XA的应用场景变得非常狭隘。

              2:tcc编程模式

              3:seata 框架

                 https://www.cnblogs.com/workstation-nigoudongma/p/9546801.html

        7.2: 分布式锁

        7.3: 分布式调度
           
    7.3.1:布式调度,我4 个定时器,有两个任务,怎么只让一个服务进行定时

        7.4:分布式的情况下可以 开启多个webscoket 的,开启多个webscoket  报啥错

    8:mybatist

    1:mybatist 中 resultType 与resultMap 的区别






    八 :数据结构的问题

    1: hashMap 1.7 与1.8 之后的区别,1.8 是什么时候扩容 以及底层实现的逻辑

    说下hashMap 的底层实现

    Hash Map采用的是散列表来记录数据,可以把散列表想象成table[]数组,每个下标下标保存一个链表的head,用链表解决hash值冲突的问题,每次添加调用put(key , value),先得到key的hash值然后用hash & (table的长度)来得到这个Node<key,value>应该存放的位置index,为什么不同hash % (table的长度),这里就不详细说明了,得到index后就会查看这个table[index]存不存在数据,如果不存在直接把table[index]指向Node<key,value>,如果存在就会有哈希冲突,就会遍历这个table[index]指向的链表,如果已经存在这个key值就会更新该Node<key, value>中的value值,如果不存在就添加到table[index]指向链表的尾节点。

    HashMap 多线程操作导致死循环问题,这是1.7 的问题,

    在多线程下,进行 put 操作会导致 HashMap 死循环,原因在于 HashMap 的扩容 resize()方法。由于扩容是新建一个数组,复制原数据到数组。由于数组下标挂有链表,所以需要复制链表,但是多线程操作有可能导致环形链表。复制链表过程如下: 以下模拟2个线程同时扩容。假设,当前 HashMap 的空间为2(临界值为1),hashcode 分别为 0 和 1,在散列地址 0 处有元素 A 和 B,这时候要添加元素 C,C 经过 hash 运算,得到散列地址为 1,这时候由于超过了临界值,空间不够,需要调用 resize 方法进行扩容,那么在多线程条件下,会出现条件竞争,

    1.8 已经解决了HashMap 多线程导致死循环问题 ,解决的方法是 通过尾插法解决的,没有进行什么锁操作。

    2:concurrentHashMap  如何实现线程安全与hashTable 的区别

    3: 创建线程安全的hashMap 方式有几种

    1. 使用Collections.synchronizedMap(Map)创建线程安全的map集合;

    2:hashTable

     public synchronized V get(Object key) {
            Entry<?,?> tab[] = table;
            int hash = key.hashCode();
            int index = (hash & 0x7FFFFFFF) % tab.length;
            for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
                if ((e.hash == hash) && e.key.equals(key)) {
                    return (V)e.value;
                }
            }
            return null;
        }

    可以看到,Hashtable是用在synchronized修饰方法。
    这个和synchronizedMap(Map)一样,效率不高。

     https://blog.csdn.net/qq_45036591/article/details/105470901

    3:concurrentHashMap 

    实现方式其实 与 hashMap 是一样的只是加入了锁机制

    1.7 与1.8 也不一样

    1.7 实现使用 ReentrantLock  与volatile 来解决线程安全

    1.8 实现使用 了 CAS + synchronized 来保证并发安全性

    九: springboot 的面试

    1:springboot aplication 的运行机制

    2: 条件注解,用到过没

    你在项目中都遇到过哪些问题怎么解决的了

    1:

    问题:并发注册问题
    我们在做完功能之后,对首页上所有功能做了并发性能测试,结果测出在做注册功能时会碰到同一个用户名或者手机号在并发量高的情况下会出现多次注册的问题。

    我们的需求要求每个手机号或用户名只能被注册一次,在用户注册填写用户名手机号时会通过ajax去后台异步校验是否有重复记录,在并发情况下,会出现多个注册用户同时去后台校验一个未被注册的用户名时,都会成功通过,从而导致注册的用户名或者手机号重复。
    解决方案:利用redis来解决,用户输入用户名去后台校验一旦成功,首先去redis中查看是否有这条用户名,如果有,则视为此用户名被别的用户抢占了,如果没,就放进去,然后返回校验成功。在别的用户去redis找这条数据只能排队去查时都能查到,视为用户名被抢占了,返回用户名校验不通过。

    2:大量的使用了缓存,那么就存在缓存的过期时间控制以及缓存击穿以及缓存雪崩等问题

     十: jvm 的这块

       1: jvm 如何调优

    十一: 锁机制这块的面试

       

     1: aqs 的实现方式,由aqs 实现的锁有哪些

     2 :  reentrantLock 上锁释放锁

     3:  juc 下的锁

      4:cas 自旋的优化方式

     

  • 相关阅读:
    QT槽和信号机制介绍
    J2EE面试题之二
    .net 面试题系列文章一(附答案)
    SUN JAVA面试笔试题
    用友在清华的笔试题
    Java面试笔试题整理
    雅虎公司C#笔试题(之一)
    Oracle面试题及答案整理
    一些著名的大公司JAVA面试题目
    百度技术研发笔试题目1
  • 原文地址:https://www.cnblogs.com/sunliyuan/p/14758329.html
Copyright © 2011-2022 走看看