ZzRG的小站
type: channel
link: https://www.juziw.cn/
description: ZzRG的小站—一个全栈开发爱好者的博客，博客主要用来记录与分享技术、学习技术知识点。
items: Anaconda环境配置、安装库和.condarc文件设置
items: 关于字体文件跨域访问限制的解决方法
items: Vue3开发中svg-icon图标不能改颜色解决办法
items: gRPC的学习
items: Redis为什么快?高性能设计之epoll和IO多路复用深度解析
items: Redis经典五大类型源码及底层实现
items: Redis的缓存过期淘汰策略
items: Redlock算法和底层源码分析
items: Redis分布式锁（二）
items: Redis分布式锁（一）

Anaconda环境配置、安装库和.condarc文件设置
type: item
date: 2024-09-15T14:41:00+08:00
description: 以下均为win系统下的操作：一、创建虚拟环境（1）base环境下操作conda env list #列出所有环境 conda create -n 环境名 python=3.9 #指定 Python 版本，创建虚拟环境conda create --prefix=安装路径\环境名 python=3.9 #指定 Python 版本与安装路径，创建虚拟环境conda remove -n 环境名 --all #删除名为“环境名”的虚拟环境conda activate 环境名 #进入名为“环境名”的虚拟环境（2）虚拟环境内的操作conda list # 列出当前环境下的所有库pip show 包名 # 查看当前环境下某个库的版本 conda deactivate # 退出虚拟环境 （3）路径切换切换上一级目录：cd..切到指定目录的盘符（需到根盘符才能切换成功）： D:切换指定路径：cd D:\Desktop（4）pip安装及相关pip install 包名 http://pypi.douban.com/simple/ --trusted-host http://pypi.douban.com导入：pip install -r requirements.txt导出：pip freeze > requirements.txt安装库的案例：安装指定第三方库：pip install numpy==1.21.5 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com（注：网络允许的情况下，直接pip install numpy==1.21.5）（5）conda安装及相关：conda install 包名直接创建虚拟环境及环境：conda env create -f environment.ymal导入：conda install -r requirements.txtconda install --yes --file requirements.txt FOR /F "delims=~" %f in (requirements.txt) DO conda install --yes "%f"导出：conda list -e > requirements.txt注：安装pytorch：建议结合自己电脑CUDA版本，官网安装pytorch安装官网：Previous PyTorch Versions | PyTorch二、关键网址Anaconda官网下载: https://www.anaconda.com/download/pycharm官网下载： https://www.jetbrains.com/pycharm/download/?section=windowspypi国内源及使用帮助: https://mirrors.tuna.tsinghua.edu.cn/help/pypi/​ https://www.cnblogs.com/sunnydou/p/5801760.htmlPytorch官方地址: https://pytorch.org/三、关于.condarc文件以阿里源为例：channels: -defaults show_channel_urls: true default_channels: -http://mirrors.aliyun.com/anaconda/pkgs/main -http://mirrors.aliyun.com/anaconda/pkgs/r -http://mirrors.aliyun.com/anaconda/pkgs/msys2 custom_channels: conda-forge: http://mirrors.aliyun.com/anaconda/cloud msys2: http://mirrors.aliyun.com/anaconda/cloud bioconda: http://mirrors.aliyun.com/anaconda/cloud menpo: http://mirrors.aliyun.com/anaconda/cloud pytorch: http://mirrors.aliyun.com/anaconda/cloud simpleitk: http://mirrors.aliyun.com/anaconda/cloud新建.condarc文件后清理一下：conda clean -i 清华channels: - defaults show_channel_urls: true default_channels: - https://mirrors.tuna.tsinghua.edu.cn/anaco…

关于字体文件跨域访问限制的解决方法
type: item
date: 2024-06-20T10:08:00+08:00
description: 什么情况下需要跨域请求字体为什么要请求字体？视觉稿中需要使用特别的字体，在带宽允许的情况下，都会选择加载自定义字体来让页面更美观。Iconfont的应用必须加载自定义字体。关于font icon的介绍——http://fontawesome.io/为什么会跨域？CDN加速。为了减少业务服务器压力和加快页面访问速度，大部分的静态资源都会放在CDN上（包括JS、CSS、字体等）。然而CDN域名往往跟主域名不一致。为什么要跨域？这个是规范要求的。https://www.w3.org/TR/css-fonts-3/#font-fetching-requirements解决方案把字体文件放到自己的服务器上。这样就不存在所谓的跨域问题了。把字体文件编码成base64，连同CSS文件一起放到CDN上。因为CSS、JS不会受到同源政策的限制，所以可以绕过跨域问题。不过这里有些建议：字体文件太大就不要这么做，因为CSS文件体积会很大，然后加载半天不出来。一般只适合Iconfont去使用。服务器（CDN）设置。服务器端，在响应头中加入Access-Control-Allow-Origin: *即可。CDN的话，一般有跨域访问限制的配置，把自己的业务网站域名配上去即可。

Vue3开发中svg-icon图标不能改颜色解决办法
type: item
date: 2023-10-25T23:21:00+08:00
description: 在使用vue3开发的时候 svg-icon图标不能改颜色！首先为什么svg-icon图标不能改颜色 因为在下载图标的时候自己选了颜色里面有一控制颜色的属性：fill 因此我们在外部使用css如：svg{color：red} 就无法改变颜色了！如何解决呢？1、改变svg-icon图片代码中的fill属性的值（常用）直接在fill属性中添加颜色；fill="#fff"；或者：在内部改为fill=currentColor；就可以使用color属性在css代码中，给svg图片改变颜色了2、在svg标签中定义添加一个fill:currentColor，然后添加color:red，就可以修改svg图标的颜色了.svg{ fill:currentColor; color:red; }

gRPC的学习
type: item
date: 2023-09-26T21:57:33+08:00
description: 4. gRPC4.1 gRPC介绍1. gRPC是由google开源的一个高性能的RPC框架。Stubby Google内部的RPC,演化而来的，2015正式开源。云原生时代是一个RPC标准。 2. gRPC核心的设计思路 1．网络通信 --->gRPC自己封装网络通信的部分提供多种语言的网络通信的封装(C Java[Netty] Go) 2．协议---> HTTP2传输数据的时候二进制数据内容。支持双向流(双工）连接的多路复用。 3．序列化--->基本文本JSON基于二进制Java原生序列化方式 Thrift二进制的序列化压缩二级制序列化。 protobuf (Protocol Buffers) google开源一种序列化方式︰时间效率和空间效率是JSON的3---5倍。 IDL语言 4．代理的创建--->让调用者像调用本地方法那样去调用远端的服务方法。 stub 3. gRPC 与ThriftRPC区别 共性:支持异构语言的RPC。 区别: 1．网络通信 Thrift TCP 专属协议 GRPC HTTP2 2．性能角度ThriftRPC 性能高于gRPC 3. gRPC 大厂背书(Google)，云原生时代与其他组件合作的顺利。所以gRPC应用更广泛。 4. gRPC的好处 1．高效的进行进程间通信。 2．支持多种语言原生支持C Go Java实现。C语言版本上扩展C++C# NodeJs Python Ruby PHP.. 3．支持多平台运行 Linux Android IOS Mac0s windows。 4. gPRC序列化方式采用protobuf，效率高。 5．使用Http2协议 6．大厂的背书 4.2 Http2.0协议1. 回顾 Http1.x协议 Http1.0协议 请求响应的模式 短链接协议（无状态协议） 传输数据文本结构 单工 无法实现服务的推送 变相实现推送（客户端轮询的方式） Http1.1协议 请求响应的模式 有限的长连接 升级的方式WebSocket 双工 实现服务器向客户端的推送。 管道网络传输(wei'bei's) 总结Http1.x协议 共性 1. 传输数据文本格式 可读性好 但是效率差。 2. 本质上Http1.x协议无法实现双工通信。 3. 资源的请求。需要发送多次请求，建立多个连接才可以完成。 2. HTTP2.0协议 1. http2.0协议是一个二进制协议，效率高于Http1.x协议，可读性差。 2. 可以实现双工通信 3. 一个请求，一个链接 可以请求多个数据。【多路复用】（如下图） 3. Http2.0协议的三个概念 1. 数据liu stream 2. 消息 message 3. 帧 frame 4. 其他的相关概念 1. 数据流的优先级，可以通过为不同的stream设置权重，来限制不同流的传输顺序。 2. 流控 --client发送的数据太快了，server处理不过来，通知client暂停数据的发送。4.3 Protocol buffers[protobuf]1. protobuf 是一种与变成语言无关【IDL】，与集体的平台无关【OS】。 它定义的中间语言，可以方便的在clinet 与server中进行RPC的数据传输。 2. protobuf 两个版本 proto2 proto3，但是目前主流应用都是proto3. 3. protobuf 主要安装protobuf的编译器，编译器的目的，可以把protobf的IDL语言，转换成具体的某一种语言。4.3.1 protobuf的编译器安装IDE 集成4.3.2 protobuf的语法文件格式xxx.proto UserServce.proto ORderService.proto版本设定syntax = "proto3"； (IDL语言)注释1. 单行注释 // 2. 多行注释 /* */与Java语言相关的语法optin 关键字开头的 可以选择使用语法 # 后续protobuf生成的java代码 一个源文件还是多个源文件 xx.java optin java_multiple_files = false; (true为多个或者false一个) 一般情况为false # 指定protobuf生成的类 放置在哪个包中 optin jva_package= "com.suns"; # 指定protobuf生成的外部类的名字（管理内部类【内部类才是正真开发使用】） optin java_outer_classname = "UserName"; (外部类)逻辑包（了解）# 对于protobuf对于文件内容管理 package xxx；导入UserService.proto OrderService.proto import "x…

Redis为什么快?高性能设计之epoll和IO多路复用深度解析
type: item
date: 2023-06-22T01:28:13+08:00
description: Redis为什么快?高性能设计之epoll和IO多路复用深度解析IO多路复用解决了哪些问题Redis单线程如何处理那么多并发客户端连接，为什么单线程，为什么快Redis的IO多路复用Redis利用epoll来实现IO多路复用，将连接信息和事件放到队列中，一次放到文件事件分派器，事件分派器将事件分发给事件处理器。Redis是跑在单线程中的，所有的操作都是按照额序线性执行的，但是由于读写操作等待用户输入或输出都是阻塞的，所以I/O操作在一般情况下往往不能直接返回，这会导致某一文件的T/O阻塞导致整个进程无法对其它客户提供服务，而I/O多路复用就是为了解决这个问题而出现所谓I/0多路复用机制，就是说通过一种机制，可以监视多个描述符，一旦某个描述符就绪（一般是读就绪或写就绪），能够通知程序进行相应的读写操作。这种机制的使用需要select 、poll、epoll来配合。多个连接共用一个阻塞对象，应用程序只需要在一个阻塞对象上等待，无需阻塞等待所有连接。当某条连接有新的数据可以处理时，操作系统通知应用程序，线程从阻塞状态返回，开始进行业务处理。Redis服务采用Reactor的方式来实现文件事件处理器（每一个网络连接其实都对应一个文件描述符)Redis基于Reactor模式开发了网络事件处理器，这个处理器被称为文件事件处理器。它的组成结构为4部分:多个套接字、IO多路复用程序、文件事件分派器、事件处理器。因为文件事件分派器队列的消费是单线程的，所以Redis才叫单线程模型BIO当用户进程调用了recvfrom这个系统调用，kernel就开始了IO的第一个阶段:准备数据（对于网络IO来说，很多时候数据在一开始还没有到达。比如，还没有收到一个完整的UDP包。这个时候kernel就要等待足够的数据到来）。这个过程需要等待，也就是说数据被拷贝到操作系统内核的缓冲区中是需要一个过程的。而在用户进程这边，整个进程会被阻塞（当然，是进程自己选择的阻塞)。当kernel一直等到数据准备好了，它就会将数据从kernel中拷贝到用户内存，然后kernel返回结果，用户进程才解除block的状态，重新运行起来。所以，BIO的特点就是在TO执行的两个阶段都被block了。accept 阶段会阻塞 等待客户端连接read 读取阶段也会阻塞在阻塞式I/O模型中，应用程序在从调用recvfrom开始到它返回有数据报准备好这段时间是阻塞的，recvfrom返回成功后，应用进程才能开始处理数据报。存在的问题上面的模型存在很大的问题，如果客户端与服务端建立了连接，如果这个连接的客户端迟迟不发数据，程就会一直堵塞在read()方法上，这样其他客户端也不能进行连接，也就是一次只能处理一个客户端，对客户很不友好解决方法只要连接了一个socket，操作系统分配一个线程来处理，这样read()方法堵塞在每个具体线程上而不堵塞主线程，就能操作多个socket了，哪个线程中的socket有数据，就读哪个socket，各取所需，灵活统一。程序服务端只负责监听是否有客户端连接，使用accept()阻塞客户端1连接服务端，就开辟一个线程(thread1）来执行read()方法，程序服务端继续监听客户端2连接服务端，也开辟一个线程〈thread2）来执行read()方法，程序服务端继续监听客户端3连接服务端，也开辟一个线程（thread3）来执行read()方法，程序服务端继续监听任何一个线程上的socket有数据发送过来，read()就能立马读到，cpu就能进行处理。多线程模型存在的问题每来一个客户端，就要开辟一个线程，如果来1万个客户端，那就要开辟1万个线程。在操作系统中用户态不能直接开辟线程，需要调用内核来创建的一个线程，这其中还涉及到用户状态的切换（上下文的切换），十分耗资源。解决方法第一个办法:使用线程池这个在客户端连接少的情况下可以使用，但是用户量大的情况下，你不知道线程池要多大，太大了内存可能不够，也不可行。第二个办法:NIO（非阻塞式IO）方式因为read()方法堵塞了，所有要开辟多个线程，如果什么方法能使read()方法不堵塞，这样就不用开辟多个线程了，这就用到了另一个IO模型，NIO（非阻塞式IO)NIO当用户进程发出read操作时，如果kernel中的数据还没有准备好，那么它并不会block用户进程，而是立刻返回一个error。从用户进程角度讲，它发起一个read操作后，并不需要等待，而是马上就得到了一个结果。用户进程判断结果是一个error时，E就知道数据还没有准备好，于是它可以再次发送read操作。一旦kernel中的数据准备好了，并且又再次收到了用户进程的system call，那么它马上就将数据拷贝到了用户内存，然后返回。所以，NIO特点是用户进程需要不断的主动询…

Redis经典五大类型源码及底层实现
type: item
date: 2023-06-22T01:27:40+08:00
description: Redis经典五大类型源码及底层实现面试常问的Redis对象object.c字符串t_string.c列表t_list.c字典t_hash.c集合及有序集合t_set.c和t_zset.c数据流t_stream.cRedis基本数据结构（骨架）简单动态字符串sds.c整数集合intset.c压缩列表ziplist.c快速链表quicklist.clistpack字典dict.cRedis数据库的实现数据库的底层实现db.c持久化rdb.c和aof.cRedis服务端和客户端事件驱动ae.c和ae_epoll.c网络连接anet.c和networking.c服务端程序server.c客户端程序redis-cli.c其他主从复制replication.c哨兵sentinel.c集群cluster.c其他数据结构，如hyperloglog.c、geo.c等其他功能，如pub/sub、Lua脚本源码分析Redis中每个对象都是一个redisObject结构每个键值对都会有一个digtEntry(源码位置:dict.h)重点:从dictEntry到RedisObjectZ经典5大数据结构解析//edis结构 //*redis6相关的底层模型和结构*string = sDs *set = intset + hashtable *zset = skipList + zipList *list = quickList + zipList *hash = hashtable + zipList * =================================== * *redis7相关的底层模型和结构 *string = SDS *set = intset + hashtable *zset = skipList + listpack紧凑列表 *List = quicklist *Hash = hashtable + Listpack紧凑列表 */ debug 的开启String数据结构介绍SDS简单动态字符串Hash数据结构介绍redis6hash-max-ziplist-entries:使用压缩列表保存时哈希集合中的最大元素个数。hash-max-ziplist-value:使用压缩列表保存时哈希集合中单个元素的最大长度。结论1.哈希对象保存的键值对数量小于512个;2.所有的键值对的健和值的字符串长度都小于等于64byte (一个英文字母一个字节)时用ziplist，反之用hashtableziplist升级到hashtable可以，反过来降级不可以（一旦从压缩列表转为了哈希表，Hash类型就会一直用哈希表进行保存而不会再转回压缩列表了。在节省内存空间方面哈希表就没有压缩列表高效了。）源码分析hset命令解读ziplist.cziplist为了节省内存，采用了紧凑的连续存储。ziplist是一个双向链表，可以在时间复杂度为O(1）下从头部、尾部进行 pop或push。新增或更新元素可能会出现连锁更新现象(致命缺点导致被listpack替换)。不能保存过多的元素，否则查询效率就会降低，数量小和内容小的情况下可以使用。redis7源码明明有ziplist了，为什么出来一个listpack紧凑列表?Ziplsit的连锁更新问题结论：listpack 是Redis 设计用来取代掉ziplist 的数据结构，它通过每个节点记录自己的长度且放在节点的尾部，来彻底解决掉了ziplist存在的连锁更新的问题ziplist内存布局VS listpack内存布局List数据结构介绍Set数据结构介绍ZSet数据结构介绍总结skiplist跳表跳表是可以实现二分查找的有序链表skiplist是一种以空间换取时间的结构。由于链表，无法进行二分查找，因此借鉴数据库索引的思想，提取出链表中关键节点(索引)，先在关键节点上查找，再进入下层链表查找，提取多层关键节点，就形成了跳跃表but由于索引也要占据一定空间的，所以，索引添加的越多，空间占用的越多总结来讲跳表=链表＋多级索引跳表时间+空间复杂度介绍

Redis的缓存过期淘汰策略
type: item
date: 2023-06-22T01:26:06+08:00
description: Redis的缓存过期淘汰策略面试题生产上你们的redis内存设置多少?如何配置、修改redis的内存大小如果内存满了你怎么办redis默认内存多少?在哪里查看?如何设置修改?内存满了会报 oom往redis里面写的数据是怎么没了的？它是如何删除的？redis过期键的删除策略如果一个键是过期的，那它到了过期时间之后是不是马上就从内存中被被删除呢? ?如果回答yes，立即删除，你自己走还是面试官送你走?如果不是，那过期后到底什么时候被删除呢?﹖是个什么操作?三种不同的删除策略立即删除Redis不可能时时刻刻遍历所有被设置了生存时间的key，来检测数据是否已经到达过期时间，然后对它进行删除。立即删除能保证内存中数据的最大新鲜度，因为它保证过期键值会在过期后马上被删除，其所占用的内存也会随之释放。但是立即删除对cpu是最不友好的。因为删除操作会占用cpu的时间，如果刚好碰上了cpu很忙的时候，比如正在做交集或排序等计算的时候，就会给cpu造成额外的压力，让CPU心累，时时需要删除，忙死。这会产生大量的性能消耗，同时也会影响数据的读取操作。总结:对CPU不友好，用处理器性能换取存储空间(拿时间换空间)惰性删除数据到达过期时间，不做处理。等下次访问该数据时，如果未过期，返回数据﹔发现已过期，删除，返回不存在。惰性删除策略的缺点是，它对内存是最不友好的。如果一个键已经过期，而这个键又仍然保留在redis中，那么只要这个过期键不被删除，它所占用的内存就不会释放。在使用惰性删除策略时，如果数据库中有非常多的过期键，而这些过期键又恰好没有被访问到的话，那么它们也许永远也不会被删除(除非用户手动执行FLUSHDB)，我们甚至可以将这种情况看作是一种内存泄漏–无用的垃圾数据占用了大量的内存，而服务器却不会自己去释放它们，这对于运行状态非常依赖于内存的Redis服务器来说,肯定不是一个好消息总结:对memory不友好，用存储空间换取处理器性能（拿空间换时间)开启惰性淘汰，lazyfree-lazy-eviction=yes以上两种都很极端---定期删除定期删除策略是前两种策略的折中:定期删除策略每隔一段时间执行一次删除过期键操作并通过限制删除操作执行时长和频率来减少删除操作对CPU时间的影响。周期性轮询redis库中的时效性数据，采用随机抽取的策略，利用过期数据占比的方式控制删除频度特点1:CPU性能占用设置有峰值，检测频度可自定义设置特点2:内存压力不是很大，长期占用内存的冷数据会被持续清理总结:周期性抽查存储空间（随机抽查，重点抽查)还会有漏洞1定期删除时，从来没有被抽查到2惰性删除时，也从来没有被点中使用过上述两个步骤======>大量过期的key堆积在内存中，导致redis内存空间紧张或者很快耗尽redis缓存淘汰策略往下看！！！！配置文件redis清理内存的方式?定期删除和惰性删除了解过吗redis缓存淘汰策略有哪些?分别是什么?你用那个?2个维度-----过期键中筛选,所有键中筛选4个方面-----LRU,LFU,random,ttl平时使用在所有的 key都是最近最经常使用，那么就需要选择allkeys-Iru进行置换最近最不经常使用的key，如果你不确定使用哪种策略，那么推荐使用allkeys-lru如果所有的 key的访问概率都是差不多的，那么可以选用allkeys-random 策略去置换数据如果对数据有足够的了解，能够为key 指定 hint(通过expire/ttl指定)，那么可以选择volatile-ttl进行置换如何配置、修改---直接用config命令---直接redis.conf配置文件redis缓存淘汰策略配置性能建议避免仔储bigkey开启惰性淘汰，lazyfree-lazy-eviction=yesredis的LRU了解过吗?请手写LRU----算法手写code见阳哥大厂第3季视频lru和lfu算法的区别是什么区别LRU:最近最少使用页面置换算法，淘汰最长时间未被使用的页面，看页面最后一次被使用到发生调度的时间长短，首先淘汰最长时间未被使用的页面。LFU:最近最不常用页面置换算法，淘汰一定时期内被访问次数最少的页，看一定时间段内页面被使用的频率，淘汰一定时期内被访问次数最少的页举个栗子某次时期Time为10分钟,如果每分钟进行一次调页,主存块为3,若所需页面走向为21212 34假设到页面4时会发生缺页中断若按LRU算法,应换页面1(1页面最久未被使用)，但按LFU算法应换页面3(十分钟内,页面3只使用了一次)可见LRU关键是看页面最后一次被使用到发生调度的时间长短,而LFU关键是看一定时间段内页面被使用的频率!

Redlock算法和底层源码分析
type: item
date: 2023-06-22T01:25:32+08:00
description: Redlock算法和底层源码分析当前代码用v8.0的Redis分布式锁-Redlock红锁算法Distributed locks with Redis产生原因----- 单点故障：redis之父提出了Redlock算法解决这个问题Redis也提供了Redlock算法，用来实现基于多个实例的分布式锁。锁变量由多个实例维护，即使有实例发生了故障，锁变量仍然是存在的，客户端还是可以完成锁操作。Redlock算法是实现高可靠分布式锁的一种有效解决方案，可以在实际开发中使用。设计理念该方案为了解决数据不一致的问题，直接舍弃了异步复制只使用master节点，同时由于舍弃了slave，为了保证可用性，引入了N个节点，官方建议是5。演示用3台实例来做说明。客户端只有在满足下面的这两个条件时，才能认为是加锁成功。条件1:客户端从超过半数(大于等于N/2+1）的Redis实例上成功获取到了锁;条件2:客户端获取锁的总耗时没有超过锁的有效时间。redisson实现pom <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.13.4</version> </dependency>RedisConfigpackage com.zzrg.redislock.config; import org.redisson.Redisson; import org.redisson.config.Config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; /** * @Author ZzRG * @Date 2023/6/14 0:39 * @Version 1.0 */ @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); // 配置具体的序列化方式 redisTemplate.setConnectionFactory(lettuceConnectionFactory); // 设置key的序列话方式String redisTemplate.setKeySerializer(new StringRedisSerializer()); // 设置value的序列化方式JSON redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } @Bean public Redisson redisson(){ Config config = new Config(); config.useSingleServer().setAddress("redis://192.168.126.130:6379").setDatabase(0).setPassword(""); return (Redisson) Rediss…

Redis分布式锁（二）
type: item
date: 2023-06-22T01:24:00+08:00
description: 1、初始化版本简单添加2、nginx分布式微服务架构3、redis分布式锁 v3.04、宕机与过期+防止死锁 v4.05、防止误删除key的问题 v5.06、Lua保证原子性 v6.0InventoryControllerpackage com.zzrg.redislock.controller; import com.zzrg.redislock.service.InventoryService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @Author ZzRG * @Date 2023/6/14 1:14 * @Version 1.0 */ @RestController @Api(tags = "redis分布式锁测试") public class InventoryController { @Autowired private InventoryService inventoryService; @ApiOperation("扣减库存sale，一次卖一个") @GetMapping(value = "/inventory/sale") public String sale() { return inventoryService.sale(); } }InventoryServicepackage com.zzrg.redislock.service; /** * @Author ZzRG * @Date 2023/6/14 1:09 * @Version 1.0 */ public interface InventoryService { String sale(); }InventoryServiceImpl：package com.zzrg.redislock.service.Impl; import cn.hutool.core.util.IdUtil; import com.zzrg.redislock.service.InventoryService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.stereotype.Service; import java.sql.Time; import java.util.Arrays; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Author ZzRG * @Date 2023/6/14 1:09 * @Version 1.0 */ @Service @Slf4j public class InventoryServiceImpl implements InventoryService { @Autowired private StringRedisTemplate stringRedisTemplate; @Value("${service.port}") private String port; /** * v6.0 Lua脚本的redis分布式锁调用，必须保证原子性 * 但是基本 v6.0 版本已经够用 * @return */ @Override publi…

Redis分布式锁（一）
type: item
date: 2023-06-22T01:24:00+08:00
description: 面试题Redis除了拿来做缓存，你还见过基于Redis的什么用法?数据共享，分布式Session分布式锁全局ID计算器、点赞位统计购物车轻量级消息队列---list、stream抽奖点赞、签到、打卡差集交集并集，用户关注、可能认识的人，推荐模型热点新闻、热搜排行榜Redis 做分布式锁的时候有需要注意的问题?你们公司自己实现的分布式锁是否用的setnx命令实现(大厂一定不可以)?这个是最合适的吗?你如何考虑分布式锁的可重入问题?如果是Redis是单点部署的，会带来什么问题?Redis集群模式下，比如主从模式，CAP方面有没有什么问题呢?那你简单的介绍一下Redlock吧?你简历上写redisson，你谈谈Redis分布式锁如何续期?看门狗知道吗?锁的种类单机版同一个JVM虚拟机内，synchronized或者Lock接口分布式多个不同JⅣM虚拟机，单机的线程锁机制不再起作用，资源类在不同的服务器之间共享了。一个靠谱分布式锁需要具备的条件和刚需独占性----OnlyOne，任何时刻只能有且仅有一个线程持有高可用----若redis集群环境下，不能因为某一个节点挂了而出现获取锁和释放锁失败的情况----高并发请求下，依l旧性能OK好使防死锁----杜绝死锁，必须有超时控制机制或者撤销操作，有个兜底终止跳出方案不乱抢----防止张冠李戴，不能私下unlock别人的锁，只能自己加锁自己释放，自己约的锁含着泪也要自己解重入性----同一个节点的同一个线程如果获得锁之后，它也可以再次获取这个锁。分布式锁setnx key valueset key value [EX seconds] [Px milliseconds] [NX|XX]JUC中A锁的规范落地参考+可重入锁考虑+Lua脚本+Redis命令一步步实现分布式锁Lua脚本Lua是—种轻量小巧的脚本语言用标准C语言编写并以源代码形式开放，其设计目的是为了嵌入应用程序中，从而为应用程序提供灵活的扩展和定制功能。Lua是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组于1993年开发的，该小组成员有:Roberto lerusalimschy、waldemar Celes和Luiz Henrique de Figueiredo。设计目的：其设计目的是为了嵌入应用程序中，从而为应用程序提供灵活的扩展和定制功能。Lua特性轻量级:它用标准C语言编写并以源代码形式开放，编译后仅仅一百余K，可以很方便的嵌入别的程序里。可扩展: Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能，Lua可以使用它们，就像是本来就内置的功能一样。Redis调用Lua脚本通过eval命令保证代码执行的原子性，直接用return返回脚本执行后的结果值入门级：reids中 eval luascript numkeys [key [key ...]] [arg [arg ...]] EVAL "return 'hello lua'" 0 ----------------------------------------------------------- set k1 v1 expire k1 30 get k1 EVAL "redis.call('set','k1','v1') redis.call('expire','k1','30') return redis.call('get','k1')" 0 ----------------------------------------------------------- mset k1 v1 k2 v2 EVAL "redis.call('mset','k1','v1','k2','v2')" 0 //动态的 上面案例 后面的0代表 没有传任何参数 EVAL "redis.call('mset',KEYS[1],ARGV[1],KEYS[2],ARGV[2])" 2 k1 k2 v1 v2升级 这个没用到redis中 条件判断：if(布尔条件) then 业务代码 elseif(布尔条件) then 业务代码 else 业务代码 end ------------------------------------------------------------ EVAL "if KEYS[2]>KEYS[2] then return ARGV[1] elseif KEYS[1]<KEYS[2] then return ARGV[2] else ARGV[3] end" 2 5 7 1 2 3 // if(5>7){ return 1 }else if…