八股文五(Redis、Nginx、Docker)

Redis篇

常用术语有哪些

UA   客户ip
PV   浏览量
DAU  日活跃用户量
MAU  月活跃用户量

Redis的基本类型有哪些 *

字符串、List、Hash、Set、ZSet、bitmap(用于位图)、HyperLogLog、GEO(地图)、Stream(消息队列)、Redis位域
-----------
字符串使用场景:(对某文章进行点赞,取消点赞)
INCR [key]  对某key+1  
DECR [key]  对某key-1
-----------
Hash使用场景:(小型购物车,不适合高并发)
创建key:用户id  商品id 数量  例子:该用户的 某个商品id,数量1
-----------
List使用场景:(订阅公众号,公众号发文章会进行推送)
该key:用户id 文章id 文章id2 文章id3
-----------
Set使用场景:
它有这些方法:
添加元素、删除元素、获取全部元素、判断元素是否在集合中、获取集合中个数、从集合中弹出一个元素,并不删除、从集合中弹出一个元素,并删除
集合运算:差集 A集合-B集合、交集、并集
场景1:微信抽奖 - 从集合中弹出一个元素,并删除
场景2:朋友圈看自己的点赞数 - key集合:点赞用户1 点赞用户2 点赞用户3
场景3:求共同好友 - 两个集合求并集
-----------
Zset使用场景:(定义商品的排行榜)
创建key  商品id 銷量  商品id2 銷量2 (每个商品的销量排序)

Redis除了做缓存,还可以用来做什么

GEO地图、ZSet适合做排行榜、分布式事务、消息队列(Stream流)、基数统计(HyperLogLog)

缓存预热、缓存雪崩、缓存穿透、缓存击穿是什么 *

缓存预热:程序上线后,将一些mysql的数据,加载到缓存中,避免上线后,客户大量访问mysql,造成服务器压力;
缓存雪崩:可能是Redis服务挂了或者Redis中的key大量同时失效
解决:Redis部署集群、或者哨兵模式、Redis中的key过期时间分散过期处理、增加本地缓存(ehcache)+Redis缓存、服务降级、限流;
缓存穿透:就是客户端查询大量不存在的数据,大量的请求会造成服务器压力;
解决:先查询Redis,Redis中没有话话,查询Mysql,mysql如果没有,把没有的值更新到Redis中,下次查询直接走Redis,不会到Mysql层;	如果有恶心攻击也会有问题,需要使用过滤器进行过滤,比如:布隆过滤器Guava,进行白名单过滤。
缓存击穿:大量请求的过程中,其中一个key过期,造成大量查询数据库,压力过大,一般这种情况都是热点;
解决:key设置永不过期、在查询到过程,使用双重检测,只有一条请求查询数据库,其他都在自选等待、
使用差异失效时间,有2块缓存,A缓存和B缓存,更新B缓存再更新A缓存,查询先查A缓存,没有再查B缓存。

如何保证缓存和数据库的一致性 *

缓存同步策略:
1 设置过期时间段key,到期后,会查询最新数据库同步到缓存中。
2 同步双写,缓存和数据强一致,数据一致性得到保障,缺点:大量查询命中缓存会很低。
3 异步通知,监控数据库,一旦数据库的数据发生改变,同步到缓存中,如Canal

过程会产生的问题:
就是当key失效,大量的请求查询数据,此时判断有没有缓存,都会判断没有缓存,会大量查询数据库,造成数据库压力
解决:采用双检加锁策略
更新或者删除操作,对缓存进行延迟双删:
先删除缓存key,更新数据库,再删除缓存到key
延迟双删的目的:A线程查询(查询缓存,如果缓存不存在,查询数据库),B删除更新(先删除缓存)
然后,修改操作,先更新数据库后删除缓存
肯能存在更新失败,可以采用延时删除。但由于读比写快,发生这一情况概率较小。
但是无论哪种策略,都可能存在删除失败的问题,解决方案是用中间件canal订阅binlog日志提取需要删除的key,然后另写一段非业务代码去获取key并尝试删除,若删除失败就把删除失败的key发送到消息队列,然后进行删除重试

什么是布隆过滤器

它是一个bit数组,然后多次hash,用来判断集合中是否存在该元素。
底层利用hash函数,2个对象hash值相等,两个对象可能是一样的,hash值不相等肯定不是同一个对象。
优点:存储空间小,快读判断该元素存不存在
缺点:因为它底层是利用hash,初始数组是固定的,不容易扩容或者删除元素,如整体结构变化,需要重构数组。

Redis为什么快 *

1 因为Redis是基于内存的数据库,操作内存速到更快,像Mysql数据最终存在磁盘中,从磁盘读取,而Redis是直接从内存读取
2 Redis是单线程,这样就也解决了并发线程安全问题,单线程的好处,避免了CPU频繁切换上下文,它的单线程也是工作命令的单线程
3 Redis的数据接口,都是基于键值对形式,根据key立马找到对应的value
4 还有IO多路复用,这个跟Nginx一样,它使用一个线程去处理多个输入、输出流,避免多线程的CPU上下文切换
就是Redis的瓶颈不是CPU,而是内存

IO多路复用是什么

它是用一个线程进行监听多个输入、输出流,谁有数据去处理谁,它并不是为每个输入、输出流创建独立的线程,去处理任务,一个线程可以监听多个描述符(socket)。
例子:老师收学生们的作业
同步阻塞情况:老师收A学生作业、再收B学生作业,如果C学生不交作业,会阻塞,D学生就等待
同步非阻塞情况:老师收A学生作业、再收B学生作业,如果C学生不交作业,进行跳过,收D学生的作业,缺点:如果每个学生都不交,老师走一圈白走
select/poll:老师收作业,学生会举手,老师会问每个学生有没有做完,做完进行收,没有做完不处理,缺点:老师需要询问一遍
epoll:学生举手,谁举手老师去收谁的作业

什么是Redis持久化

就是将Redis里的数据存到磁盘中,进行持久化操作

Redis有哪几种持久化方式 *

AOF:它是以操作日志的方式记录,
优点:数据丢失概率小,适合做紧急恢复数据,缺点:恢复数据慢、数据大小大于RDB
RDB:它是制定时间间隔,将数据进行备份,也就是快照,会生成rdb后缀的文件,也是默认的方式
优点:比AOF快,适合大规模数据恢复,缺点:并不是实时的,会存在数据丢失
RDB - AOF混合持久化
rdb做存量,aof做当量;

Redis有哪几种淘汰策略 *

默认的内存是没有限制,默认的策略是不删除,生产环境内存是物理内存的4分之3,避免OOM
淘汰策略有8种
1 不删除(默认)
2 随机删除key
3 随机删除设置过期的key
4 马上删除过期的key
5 对所有的key进行LRU算法进行删除(推荐,默认优先删除不经常使用的key)
6 对设置过期的key进行LRU算法进行删除
7 对所有的key进行LFU算法进行删除
8 对设置过期的key进行LFU算法进行删除
...
对过期的key删除,一般我会使用惰性删除+定期删除
马上删除(马上进行删除,占CPU)
惰性删除(什么时候访问该key,什么时候判断是否过期,是否要删除,占内存)
定期删除(定期抽查进行删除,会存在漏删)

如果一个键是过期的,它到了过期时间,是马上从内存删除吗

不是马上,默认情况使用定期删除,这样对CPU比较友好

什么是LRU算法,LFU算法

LRU:就是最长时间没有被使用的(最长时间)
LFU:就是一段时间内,使用次数最少的(最少的次)

实现LRU算法

/**
 * lru 算法
 */
public class Lru<K,V> extends LinkedHashMap<K,V> {

    // 坑位
    private int capacity;

    public Lru(int capacity) {
        // true 代表,如果重复会刷新,会在队列最右端,最后一个出, 如果是false,保持不变
        super(capacity, 0.75f, true);
        this.capacity = capacity;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return super.size() > capacity;
    }

    public static void main(String[] args) {
        Lru l = new Lru(3);
        l.put(1, "aa");
        l.put(2, "bb");
        l.put(3, "cc");
        System.out.println(l.keySet()); //[1, 2, 3]
        l.put(4, "dd");
        l.put(5, "ee");
        l.put(5, "ee");
        System.out.println(l.keySet()); //[3, 4, 5]
        l.put(6, "ff");
        System.out.println(l.keySet()); //[4, 5, 6]
        l.put(5, "ee");
        l.put(5, "ee");
        System.out.println(l.keySet()); //[4, 6, 5]
        l.put(7, "gg");
        System.out.println(l.keySet()); //[6, 5, 7]
    }

Redis 集群方案应该怎么做 *

1.哨兵模式:
一般哨兵至少需要3台机器(1台主机,2台从机)如果有主机挂了,会重新选举出新的主机
注意事项:需要配置主从复制、缺点:就是重新选举的时候,会存在丢数据
2.集群配置
一般需要3台主机,3台从机,一个客户端请求会根据槽位定位算法,得出去访问哪台Redis上
(根据哈希槽分区,将一些数据存在不同的Redis主机上,方便扩容)

什么情况会导致集群不可用

例:A、B、C Redis主机,其中B主机挂了,B主机会少一些槽点,某些请求访问不到Redis数据,
默认情况,集群不完整,是不会对外进行访问,可以通过配置文件改。

MySQL里有2000w 数据,redis中只存20w的数据,如何保证 redis 中的数据都是热点数据

可以使用Redis的淘汰策略,不经常使用带key,优先删除掉。

使用过Redis分布式锁么,它是怎么实现的 *

redis中有setnx 它就是分布式锁,它的底层思想是,判断key键值是否存在,不存在给一个定值,如果存在,不执行任何操作,返回1(成功),0(失败)
这个可以在中小项目中使用,这里是有缺陷的
比如:
1 没有加过期时间,如果服务A加锁,后服务挂了,锁一致保持,其他线程肯定进不来,(加过期时间可解决,并且只能删除自己的锁,其它线程删除不了)
2 还有问题,因为加锁和删除,2个指令不是原子性命令,所以需要lua脚本,来保证原子性
3 还有问题,比如我们本地锁,Lock、synchronized他们都是可重入锁,Redis的setnx肯定不支持可重入的概念,需要改成(加锁,解锁需要原子性,可重入锁、看门狗机制,自动续期)可以使用Redisson解决,也可以解决Redis集群模式造成锁丢失

Redis 哈希槽的概念

它是一个数组,它增加了一层哈希槽,一个集群有16384个槽,这些槽会分配给集群中的所有主节点

Redis 集群会有写操作丢失吗?

会丢失,因为Redis 并不能保证数据的强一致性,并且数据复制是异步复制
例子:A、B、C主机,B挂了,此时,C主机有写操作,然后重新选举进行分槽,此时C主机挂了,刚才C主机刚才写操作会丢。

Redis 中的管道有什么用

管道是一次性将多条指令发送服务端,适合做批量的操作

怎么理解 Redis 事务

Redis的单线程,一个命令执行完再执行下一个命令,所以具有原子性,不用担心,我更改一个值,同时间有其他线程也更改了值。
然后它的事务,就是相当于序列化,变成一组命令,当一组命令执行完,代表该事务完成。(保证那么这组命令都成功,或者都失败,不会一部分成功,一部分失败)
但Redis没有回滚,只能保证成功或者失败

常用的 Redis 优化手段有哪些

1 合理利用Redis的数据结构进行存数据,将string类型控制在10kb、hash、list、set、zset个数不超过5000
2 限制 Redis 内存大小,避免出现OOM,使用适当的淘汰策略
3 不要与CPU密集型应用部署在一起
4 避免大量数据同时失效
5 生产环境禁止使用 keys 命令,避免查询大key
  当key很庞大的时候,进行使用key * 命令,使用其他命令,如游标
6 有删除操作,使用异步删除的方式,避免阻塞主线程,配置文件可以配置,为非阻塞删除

Nginx篇

什么是Nginx

它是高性能的反向代理Web服务器,可以实现动静分离、负载均衡、web缓存、节省宽带:支持GZIP压缩,可以添加浏览器本地缓存
优点:它稳定性好,很少宕机、并发能力强(官网检测可支持5万个并发连接数)

为什么Nginx性能这么高 *

1 异步非阻塞
它跟Redis一样,使用I/O多路复用,它分为一个主进程,多个工作进程,每个工作进程可以处理多个请求,每进来一个请求,会有一个worker进程去处理,属于网络io密集型。异步非阻塞事件处理机制:运用了epoll模型,可处理2-3万并发连接数;
用一个线程进行监听,谁有请求,就处理谁的回调方法,这样也避免了多线程直接上下文切换。
之前,客户端和服务端进行连接,一个连接就是一个socket,会创建一个线程,客户端请求,然后该线程处理,处理完返回给该客户端,Apache就是这样多线程,进行分配线程。
它是用一个线程进行监听多个输入、输出流,谁有数据去处理谁,它并不是为每个输入、输出流创建独立的线程,去处理任务,一个线程可以监听多个描述符(socket)。
例子:老师收学生们的作业
同步阻塞情况:老师收A学生作业、再收B学生作业,如果C学生不交作业,会阻塞,D学生就等待
同步非阻塞情况:老师收A学生作业、再收B学生作业,如果C学生不交作业,进行跳过,收D学生的作业,缺点:如果每个学生都不交,老师走一圈白走
select/poll:老师收作业,学生会举手,老师会问每个学生有没有做完,做完进行收,没有做完不处理,缺点:老师需要询问一遍
epoll:学生举手,谁举手老师去收谁的作业

什么是正向代理和反向代理

正向代理:客户端1发送请求给服务端1,中间没有中介接入
反向代理:客户端1发送请求给Nginx,Nginx内部根据一些规则,发送给服务端1
优点:多一层,也更加安全

location的作用是什么

是根据用户请求的url来执行不同的应用,匹配对应的location模块。
例:
    #优先级1,精确匹配,根路径
    location =/ {
    	return 400;
    }

    #优先级2,以某个字符串开头,以av开头的,优先匹配这里,区分大小写
    location ^~ /av {
       root /data/av/;
    }

    #优先级3,区分大小写的正则匹配,匹配/media*****路径
    location ~ /media {
          alias /data/static/;
    }

为什么要做动静分离

Nginx是当下最热的Web容器,一般前端静态资源都放在Nginx储存,静态的请求静态文件,动态请求后端服务地址。Nginx还可以对一些静态文件进行压缩传输。
之前用户请求 - Nginx - 后端服务器,(返回前端静态文件,现在只有动态会这么走)
现在用户请求 - Nginx (返回前端静态文件)

Nginx负载均衡的算法有哪些

默认是轮询、权重(权重越大访问概率越大)、ip_hash(IP绑定)、url_hash(对所有的url进行hash得出结构分配服务)、least_conn (最小连接数)

Nginx配置高可用性怎么配置

如果生产环境只有一台Nginx,当它挂了,整个服务都不能访问了,需要搭建集群配置
在小项目中,可以一台Nginx转发到多台Nginx机器上,Nginx挂掉概率很小
在大项目中,我们准备2台Nginx,分别安装keepalived服务,进行配置对应的keepalived.conf配置文件,其中一台配置主机,另一台就是备机
我们还需要写一个shell脚本,Nginx服务与keepalived进行绑定。
在keepalived这边,它提供一个虚拟IP(VIP),2台Nginx有真实的IP地址,当其中Nginx挂掉,会在shell脚本这里逻辑,一般都是尝试重启,如果失败,会杀掉当前keepalived的进程,另一台的keepalived,它的把当前的(VIP)切换到当前的Nginx的主机ip上,备机就上位,如果有多台Nginx,会根据keepalived的配置文件配置的选举概率选中其中一台。

Docker篇

什么是 Docker 容器

容器是基于镜像创建的运行实例,如:mysql容器、Redis容器

什么是 DockerFile

Dockerfile 是用来构建Docker镜像文件,是由一条条构建镜像所需的指令构成的脚本。

虚拟化和容器化有什么区别

虚拟化::是一个物理服务器上运行多个操作系统,如VM
容器化: 是提供了一个独立的环境来运行我们的应用程序

Docker虚悬镜像是什么?

仓库名和标签都是空的镜像,就是虚悬镜像,我们需要删除掉。

Dockerfile 中的RUN和CMD的区别:

CMD:可以有多个CMD,但只有最后一个会生效,相当于是在docker run时运行
RUN:可以执行shell的脚本,相当于在docker build时运行,例子:RUN yum -y install vim
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值