Nosql

Redis 秒杀功能为什么不用decr

decr 是原子性的,可以防止“超卖”现象发生,但是要考虑秒杀失败时回滚的问题:库存共3件,10个人同时下单,数量为 -7,3个人通过,此时有一个人的后续步骤失败,需要回滚,但 incr 1 没有用,因为数量已经是 -7 了,变成 -6 显然不能恢复可用状态。

Redis 有哪些持久化方式

● RDB快照

在指定的时间间隔内将内存中的数据写入二进制文件,这种文件就是 RDB 格式快照,RDB 有三种持久化机制:

● save:同步持久化。执行过程对 redis 服务是阻塞的,在新的快照被创建后,如果存在旧快照则会进行原子性替换。

● bgsave:异步持久化。主进程会 fork 一个子进程用来进行持久化操作,快照创建后向主进程发送信号。
优势是:文件经过压缩,适合用来备份;恢复大数据的速度快;每一次都是全量备份。
缺点是:bgsave 生成快照时,主进程仍可修改数据,在两次备份期间修改的数据不会被保存。

● AOF文件

redis 将每一条命令追加写入到文件中,以 AOF 格式保存。利用 bgrewriteaof 命令可以重构 AOF 文件内容,就是将多条命令压缩成高效的批量命令。AOF 有两种持久化机制:

● always:同步持久化。每次数据发生改变就将命令同步写入磁盘

● everysec:异步持久化。每秒进行记录,如果服务崩溃,最多丢失一秒的数据

优势是:比 RDB 更能保证数据不丢失;AOF 格式是人类可读的,可以进行容灾处理和文件修复,比较灵活。
缺点是:AOF 文件体积比 RDB 大;恢复速度一般比 RDB 要慢。

Redis 的故障处理

● 验证持久化文件:redis提供了工具,可以扫描 AOF 文件,发现第一个不完整的命令后,会删除这条命令及之后的所有命令;但损坏的 RDB 快照文件无法修复,最好为快照文件保留多个备份,并通过计算快照的散列值来校验。

● 替换主服务器:当主服务器出现故障时,首先向从服务器发送 SAVE 命令,然后将从服的快照发送到新启动的主服务器,然后在新的主服务器向从服务器发送 SLAVEOF 命令重建主从链。另一种方法是让从服务器升级为主服务器,并为升级后的主服务器创建从服务器。

缓存系统面临的问题

● 缓存穿透:用户不断请求缓存和数据库中都没有的数据(如 id = -1),导致数据库压力过大,解决方案:

● 将数据库查不到的空值也进行缓存,但过期时间远小于正常数据的过期时间。

● 利用布隆过滤器,将数据映射到过滤器中,查询数据库之前先检查数据是否不存在。

● 缓存击穿:大量用户同时请求缓存中没有,但数据库中有的数据(可能是缓存过期了),导致数据库压力过大,解决方案:

● 设置热点数据永不过期。

● 请求数据库之前给查询操作加排他锁,阻塞其他事务的查询。

● 缓存雪崩:缓存中大批数据同时过期,当查询量大时导致数据库瞬间压力过大,解决方案:

● 设置缓存过期时间时,加上一段随机时间,防止缓存同时过期。

● 热点数据可以设置永不过期。

Redis 的数据类型和应用场景

● string

● 分布式锁

● sorted set

● 计数信号量:利用集合的唯一性和分数排序,判断元素是否超出限制数量。

● bitmap

● 用户签到:今天在一年中的天数 a,今年的总天数 n;key 的格式为年份:用户ID,实现为:key = a % n

● 用户在线状态:按用户 ID 设置位状态即可

● Bloom 过滤器:由 redis 模块提供

RabbitMQ 如何保证消息可靠传输

解决生产者消息丢失问题,可以采用事务或 Confirm 模式,其中 Confirm 的性能比事务要高。
解决消息队列消息丢失问题,可以采用消息持久化机制。
解决消费者数据丢失问题,可以采用手动确认消息的方式,在消息处理完毕之后应答即可。因为默认的自动确认机制会在收到消息时立刻回复确认,后续可能导致消息丢失。

项目中引入 RabbitMQ 需要注意什么

rabbitmq 在分布式系统中作为消息中间件存在,是一种全局服务,引入 mq 将增加系统复杂度,需要注意:

● 命名的规范:生产者与 exchange、消费者与 queue 的命名应该具有关联性,最好将命名过程进行封装自动创建,让使用者不需要关心命名问题。

● 消费者的幂等性:网络问题等因素会触发重试机制,所以消费者应该实现幂等。

● 无序性