Java知识体系

#MQ

1. 为什么要使用MQ

一般MQ的使用场景有:解耦,异步,削峰

解耦

使用MQ前:在这里插入图片描述
使用MQ后:
在这里插入图片描述
MQ在这个系统中的作用就是解除了A系统与BCD系统的耦合关系。

异步

异步前:

在这里插入图片描述

异步后:
在这里插入图片描述
原本需要30s的处理通过加入MQ变为异步处理后只需要一个请求的时间就解决问题,大大提升效率

削峰

使用前
在这里插入图片描述
由图可见,当大量用户同时来请求系统时,所有的压力都集中在数据库,但是数据库的性能是有限的,这样就可能导致数据库挂掉,即使勉强不挂掉,也会严重影响系统响应速度。

使用mq后
在这里插入图片描述

2. MQ保证高可用

rabbitmq

采用镜像集群模式,创建的queue,无论元数据还是queue里的消息都会存在于多个实例上,然后每次你写消息到queue的时候,都会自动把消息到多个实例的queue里进行消息同步。
优点是解决了高可用问题,缺点也很明显,消息同步所有机器,性能开销和网络开销大。

kafka

kafka基础架构是:多个broker组成,每个broker是一个节点;你创建一个topic,这个topic可以划分为多个partition,每个partition可以存在于不同的broker上,每个partition就放一部分数据。
kafka 0.8以后,提供了HA机制,就是replica副本机制。每个partition的数据都会同步到吉他机器上,形成自己的多个replica副本。然后所有replica会选举一个leader出来,那么生产和消费都跟这个leader打交道,然后其他replica就是follower。写的时候,leader会负责把数据同步到所有follower上去,读的时候就直接读leader上数据即可。只能读写leader?很简单,要是你可以随意读写每个follower,那么就要care数据一致性的问题,系统复杂度太高,很容易出问题。kafka会均匀的将一个partition的所有replica分布在不同的机器上,这样才可以提高容错性。

3. MQ保证消息不被重复消费

MQ是不能自己做到不被重复消费的,需要自己实现。
解决思路如下:
1.消除MQ重复消费的影响其实就是想保证消费的幂等,如果是插入或者update可以使用主键先查在操作。
2.如果是操作Redis就更便捷了,Set天然幂等。
3. 如不是上述场景需要因地制宜的处理,加入全局唯一id等方式处理即可。

4. MQ数据丢失问题

  1. 生产者:可开启rabbitmq事务功能,只要消息发送失败就事务回滚。
  2. rabbitmq :开启rabbitmq的数据持久化,就是把消息写入磁盘,如发生rabbitmq挂掉情况时保证消息不会丢(小概率会遇到消息数据还未持久化就挂掉的情况)。
  3. 消费者: 可使用rabbitmq提供的ack机制,默认关闭rabbitmq自动ack,只需要消费完手动调用ack即告诉rabbitmq你已完成消费。

5. MQ顺序执行问题

原理简单,只需要不同的执行操作对应不同的queue即可,多建几个queue,一个queue但是对应一个consumer。

6. MQ消息积压

  1. 快速处理积压消息, 1)先修复consumer的问题,确保其恢复消费速度,然后将现有cnosumer都停掉
    2)新建一个topic,partition是原来的10倍,临时建立好原先10倍或者20倍的queue数量
    3)然后写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的10倍数量的queue
    4)接着临时征用10倍的机器来部署consumer,每一批consumer消费一个临时queue的数据
    5)这种做法相当于是临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据
    6)等快速消费完积压数据之后,得恢复原先部署架构,重新用原先的consumer机器来消费消息
  2. 消息失效
    没其他办法,只能等晚上用户使用较少时把丢失的数据找回来。

7. es如何实现分布式

核心思想就是在多台机器上启动多个es进程实例,组成了一个es集群。
es的基本单位是索引,类比于MySQL中的表,每个索引拆分成多个shard,每个shard存储部分数据。
每个shard都有多个备份,可以保证机器宕机时保证高可用。
es集群多个节点会自动选举master节点,如主节点宕机,剩下节点再次选举主节点。

8.es优化性能

  1. os cache 操作系统缓存,
    在这里插入图片描述
  2. 缓存预热
    热点数据定时访问一下,把数据放到filessystem cache里面
  3. 冷热分离
    冷门数据与热点数据放到不同的索引,确保热点数据进行缓存预热时不被冷数据刷掉。
  4. es不使用复杂查询,应构建好数据模型后放置es中

9.es生产集群部署

(1)es生产集群我们部署了5台机器,每台机器是6核64G的,集群总内存是320G

(2)我们es集群的日增量数据大概是2000万条,每天日增量数据大概是500MB,每月增量数据大概是6亿,15G。目前系统已经运行了几个月,现在es集群里数据总量大概是100G左右。

(3)目前线上有5个索引(这个结合你们自己业务来,看看自己有哪些数据可以放es的),每个索引的数据量大概是20G,所以这个数据量之内,我们每个索引分配的是8个shard,比默认的5个shard多了3个shard。

10. 缓存如何实现高性能、高并发

在这里插入图片描述

高性能

原理就是第一次查询数据后,把数据放置在缓存里,当下一次查询过来时,就直接从缓存中查找并返回即可

在这里插入图片描述

高并发

实现原理是因为数据库不支持高并发,缓存是可以支持的。

11.Redis单线程为什么支持高并发

Redis线程模型:
在这里插入图片描述
客户端发起请求,Redis进程中建立一个与客户端请求对应的sercer_socket,通过server_socket调用IO多路复用程序将请求放到队列中排队。
高并发原因:非阻塞线程,IO复用,纯内存结构

1.Redis单线程为什么支持高并发

Redis线程模型:
在这里插入图片描述
客户端发起请求,Redis进程中建立一个与客户端请求对应的sercer_socket,通过server_socket调用IO多路复用程序将请求放到队列中排队。
高并发原因:非阻塞线程,IO复用,纯内存结构

2. Redis数据类型

String

KV缓存

hash

这个是类似map的一种结构,这个一般就是可以将结构化的数据,比如一个对象(前提是这个对象没嵌套其他的对象)给缓存在redis里,然后每次读写缓存的时候,可以就操作hash里的某个字段。

key=150

value={
“id”: 150,
“name”: “zhangsan”,
“age”: 20
}

hash类的数据结构,主要是用来存放一些对象,把一些简单的对象给缓存起来,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值

value={
“id”: 150,
“name”: “zhangsan”,
“age”: 21
}

list

有序列表
微博,某个大v的粉丝,就可以以list的格式放在redis里去缓存

key=某大v

value=[zhangsan, lisi, wangwu]

比如可以通过list存储一些列表型的数据结构,类似粉丝列表了、文章的评论列表了之类的东西

比如可以通过lrange命令,就是从某个元素开始读取多少个元素,可以基于list实现分页查询,这个很棒的一个功能,基于redis实现简单的高性能分页,可以做类似微博那种下拉不断分页的东西,性能高,就一页一页走

set

无序集合,自动去重

直接基于set将系统里需要去重的数据扔进去,自动就给去重了,如果你需要对一些数据进行快速的全局去重,你当然也可以基于jvm内存里的HashSet进行去重,但是如果你的某个系统部署在多台机器上呢?

得基于redis进行全局的set去重

可以基于set玩儿交集、并集、差集的操作,比如交集吧,可以把两个人的粉丝列表整一个交集,看看俩人的共同好友是谁?对吧

把两个大v的粉丝都放在两个set中,对两个set做交集

sorted set

排序的set,去重但是可以排序,写进去的时候给一个分数,自动根据分数排序,这个可以玩儿很多的花样,最大的特点是有个分数可以自定义排序规则

比如说你要是想根据时间对数据排序,那么可以写入进去的时候用某个时间作为分数,人家自动给你按照时间排序了

排行榜:将每个用户以及其对应的什么分数写入进去,zadd board score username,接着zrevrange board 0 99,就可以获取排名前100的用户;zrank board username,可以看到用户在排行榜里的排名

zadd board 85 zhangsan
zadd board 72 wangwu
zadd board 96 lisi
zadd board 62 zhaoliu

96 lisi
85 zhangsan
72 wangwu
62 zhaoliu

zrevrange board 0 3

获取排名前3的用户

96 lisi
85 zhangsan
72 wangwu

zrank board zhaoliu

3. Redis过期策略

1. 过期时间

通常操作Redis添加一条缓存记录时,会设置一个过期时间。而对于Redis而言,当缓存记录达到过期时间时,它是通过定期删除和惰性删除组合起来删除的。
定期删除:指的是Redis每隔一段时间,随机抽取一批key,检查是否过期,过期则删除。注意:整个过程,Redis只是随机抽取一部分,而不是内存中的全部key

如果过期key没有被删除怎么办?这里需要惰性删除

这就是说,在你获取某个key的时候,redis会检查一下 ,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。

并不是key到时间就被删除掉,而是你查询这个key的时候,redis再懒惰的检查一下

通过上述两种手段结合起来,保证过期的key一定会被干掉。

内存淘汰

如果定期删除漏掉很多过期的key,而且没有及时去查,未进行惰性删除,占用大量内存空间时怎么办?
使用内存淘汰机制。
1)noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)
3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的key给干掉啊
4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key(这个一般不太合适)
5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key
6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除

Redis如何承载高并发、高可用

读写分离

一般来说缓存都是用来支撑读高并发,写的请求比较少。
架构设计上:采用主从架构,一主多从,主负责写,并将数据同步到其他的从节点,所有读请求都走从节点
主从读写分离架构图
在这里插入图片描述
为保证高可用,master节点必须要做数据持久化,如果Redis宕机,可保证数据不丢失。

·

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值