通过两层拦截器拦截请求第一层拦截器拦截所有请求 判断user是否存在 存在更新token 不存在直接放行,第二层拦截需要登陆的请求做校验 通过order调节优先级 值越小越优先
判断userholder.getuser是否为null 如果为null放行 并更新token时间
魔法值:业务代码中直接出现的常量。这些常量至少要放到全局变量中,或者枚举类中 redis-cli连接redis
1. 数据丢失:redis是内存存储,重启会丢失数据
解决办法:实现redis持久化
2. 并发能力问题:对更高的数据量如618就不够用
解决办法:搭建主从集群,实现读写分离
3. 故障恢复问题:如果redis宕机,服务就不可用了,需要自动恢复故障手段
解决办法:利用redis哨兵,实现健康检测和自动恢复
4. 存储数量问题:基于内存存储,难以满足海量数据要求
解决办法:搭建分片集群,利用插槽机制实现动态扩容
RDB被称作数据快照,将内存中的所有数据记录到磁盘上,当redis故障重启后,从磁盘读取快照文件,恢复数据。
Save保存快照文件s
bgsave后台异步执行 开始时会fork主进程得到子进程,紫禁城共享 主进程的内存数据。完成fork后读取内存数据并写入RDB文件。fork采用的是copy-on-write技术
当主进程进行读操作,访问共享内存
当主进程进行写操作,则拷贝一份数据,执行写操作。
Fork主进程得到子进程,共享内存空间
子进程读取内存数据并写入新的RDB文件
用新RDB文件替换旧的RDB文件 默认在服务停止时执行,save 60 1000含义为:60s内有1000次修改出发RDB
AOF文件不断追加写操作命令一般设置为eyerysec 命令记录会重复 可以通过bgrewriteaof执行重写,可以设置重写触发条件。

一般来讲读操作也就是查询是多于写操作,而单节点redis并发能力有限,所以需要搭建主从集群,实现读写分离。从节点只允许读操作,主节点只允许写操作以此实现读写分离。
命令格式 (slaveof/replicaof) 从ip 主ip

1 从节点执行replicaof命令,建立连接,并向主节点请求数据同步。
2 主节点判断是否是第一次同步。
3 是第一次,返回master的数据版本信息。
4 从节点保存版本信息
5 主节点执行bgsave,生成RDB并向从节点发从RDB,主节点记录在RDB生成期间的所有命令repl_baklog。
6 从节点清空本地数据,加载RDB文件
7 发送repl_baklog中的命令,从节点执行接收到命令
1 从节点请求增量同步
2 master节点判断replid,发现不一致,拒绝增量同步
3 master将完成内存数据生成RDB,发动RDB到slave
4 slave清空本地数据,加载master的RDB
5 master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave
1 从节点psync replid offset
2 主节点判断replid是否一致
3 不是第一次 回复continue
4 去 repl_baklog获取offset后的命令,并发送给从节点offset后的命令,从节点执行命令
1在master中配置repl-diskless-sync yes启用无磁盘复制避免全量同步时的磁盘IO
2 redis单节点内存占用不要太大,防止生成RDB文件时产生大量的磁盘IO
3适当提高repl_baklog的大小,发现slave宕机时尽快实现故障修复,避免全量同步
4限制一个master上的slave节点数量,如果slave节点太多,可以采用主-从-从链式结构,减少master压力
redis提供了哨兵机制Sentinel来实现主从集群的故障恢复。
- 监控:sentinel会不断检查master和slave节点是否按预期工作
- 自动故障恢复:如果master故障,sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
- sentinel充当redis客户端的服务发现来源,当集群发生故障转移时,会将 最新信息推送给redis客户端
sentinel基于心跳机制监测服务状态,没隔1秒向集群的每个实例发送ping命令:
主观下线:如果某sentinel节点发现某实例未在规定时间相应,则认为该实例主观下线
客观下线:如超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过sentinel实例数量的一半
箭头函数 当然,让我为你举几个例子来解释箭头函数 => 的不同用法:
定义匿名函数:
javascript const add = (a, b) => a + b; // 这里定义了一个匿名的箭头函数,用于实现两数相加的功能 作为回调函数传递给其他函数:
javascript const numbers = [1, 2, 3]; const squared = numbers.map(num => num * num); // 这里使用箭头函数作为回调函数,将数组中的每个元素都平方,并返回一个新的数组 在对象字面量中使用箭头函数:
javascript
const person = {
name: 'Alice',
sayHello: () => {
console.log(Hello, my name is ${this.name});
}
};
// 这里箭头函数被用作对象的方法,但要注意箭头函数的 this 与普通函数的 this 行为不同
简化语法:
javascript const numbers = [1, 2, 3]; const sum = numbers.reduce((acc, num) => acc + num, 0); // 箭头函数可以简化回调函数的书写,这里用于计算数组中所有元素的和 改变上下文:
javascript function Counter() { this.count = 0; setInterval(() => { this.count++; console.log(this.count); }, 1000); } // 这里箭头函数继承了外部作用域的 this 值,避免了定时器中常见的 this 指向问题 这些例子展示了箭头函数在不同场景下的用法,包括定义函数、作为回调函数、简化语法以及改变上下文等。希望这些例子能帮助你更好地理解箭头函数的用法。
2024/3/16 17:09:21
// 这里箭头函数被用作对象的方法,但要注意箭头函数的 this 与普通函数的 this 行为不同这个什么意思 还有这个// 这里箭头函数继承了外部作用域的 this 值,避免了定时器中常见的 this 指向问题
2024/3/16 17:09:34
当箭头函数被用作对象的方法时,其中的 this 关键字和普通函数的行为是不同的,这可能会导致一些意想不到的结果。让我解释一下:
箭头函数作为对象方法:
javascript
const person = {
name: 'Alice',
sayHello: () => {
console.log(Hello, my name is ${this.name});
}
};
person.sayHello(); // 输出 "Hello, my name is undefined"
在这个例子中,箭头函数 sayHello 被作为对象 person 的方法。由于箭头函数不会绑定自己的 this 值,而是会继承外部作用域的 this 值(在这里是全局作用域),所以 this.name 实际上是指向了全局对象而不是 person 对象。
箭头函数继承外部作用域的 this 值:
javascript function Counter() { this.count = 0; setInterval(() => { this.count++; console.log(this.count); }, 1000); } const counter = new Counter(); 在这个例子中,箭头函数被用在 setInterval 中,它继承了 Counter 函数作用域中的 this 值,而不是创建自己的 this。这种行为避免了在定时器中常见的 this 指向问题,确保了 this.count 指向的是 Counter 对象的属性。
总的来说,箭头函数的 this 行为和普通函数是有所区别的,特别是在涉及到对象方法或定时器等情况下。对于需要绑定动态 this 值的情况,需要谨慎选择使用箭头函数或普通函数来避免出现意外的结果。希望这能帮助你理解箭头函数中 this 的行为差异。




























































