解决使用redisTemplate-set方法保存出现x00问题

在项目有个需求要保存一个字符串到redis,并设置一个过期时间。这个需求一看非常简单,使用redisTemplate一行代码搞定,代码如下 redisTemplate.opsForValue().set("userKey", data, 10000); 但保存后,查看redis发现value的前缀多出了 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x一开始以为是redis的序列化问题,于是就修改了redisTemplate的序列化方式,终于还是没能解决问题。那问题出在哪里?翻看源码,发现redisTemplate.opsForValue().set()有重载方法,一个是 void set(K key, V value, long offset) 另外一个是 void set(K key, V value, long timeout, TimeUnit unit)调用set(K key, V value, long offset)这个方法,其底层调用的是redis的setrange命令,这个命令看官网介绍 Overwrites part of the string stored at key, starting at the specified offset, for the entire length of value. If the offset is larger than the current length of the string at key, the string is padded with zero-bytes to make offset fit. Non-existing keys are considered as empty strings, so this command will make sure it holds a string large enough to be able to set value at offset其含义是从指定的偏移量开始,覆盖整个值范围内从key存储的字符串的一部分。如果偏移量大于key处字符串的当前长度,则该字符串将填充零字节以使偏移量适合。不存在的键被视为空字符串,因此此命令将确保它包含足够大的字符串以能够将值设置为offset。 ...

June 18, 2020 · 1 min · jiezi

英雄之旅行走在开源领域的一个自叙故事

作者介绍潘娟,京东数科高级DBA&Apache ShardingSphere PMC,主要负责京东数科分布式数据库开发、数据库运维自动化平台开发等工作。曾负责京东数科数据库自动化平台设计与开发,现专注于Apache ShardingSphere分布式数据库中间件平台的开发。主要在分布式数据库、开源、分布式架构等相关领域进行探索。多次受邀参加数据库&架构领域的相关会议并进行分享交流。 前序《英雄之旅》是由美国神话学家约瑟夫·坎贝尔提出的。好莱坞很多经典IP巨作即是把《英雄之旅》的套路搬上了巨幕。 最近在读一些心理学书籍,随即发现我们每个人的一生都是一场英雄之旅。从被使命召唤、踏上艰辛的考验之旅、接收他人恩赐、发现自我、到达胜利顶点、回归自我。然而,很多人可能一生都行走在发现自我的路上,若是有幸,则能到达顶点,回归自我。 这篇分享以”英雄之旅“为开始,是希望把自上篇文章-程序媛成长纪:从DBA到研发工程师以来到现在的经历,提取出经验点,与所有行走在英雄之旅的朋友交流,碰撞火花。毕竟我们每个人面对工作、生活、家庭、自我都有着太多冲撞和思考,需要被他人理解和照亮。:-) 由点及面上篇的自叙文谈到我从运维DBA转成了Java开发工程师。准确的说,应该是开源分布式数据库开发工程师。因为在过去一年半多的时间里,我更多地是在分布式数据库中间件平台、分布式事务框架、分布式治理等领域做相关的研发工作。主要从事的项目是Apache分布式数据库中间件平台Apache ShardingSphere, 和京东数科主导的分布式事务平台JDTX(未开源)。 之所以说”由点及面”,是因为工作的内容开始从最初新手关注的一个点,开始渗透到整个项目的各个领域。从最初做的metaData初始化加载模块到现在Apache ShardingSphere的11个一级模块中,有8个模块都是深耕接触过,此外还有公司内部的分布式事务平台JDTX。从这里可以看出一个新手开始逐渐变成了”老司机“。这让我突然想到之前很多人问过的一个问题— 类似像ShardingSphere这样的大型项目,参与的正确姿势是什么?有人选择通读文档,有人选择把模块间架构关系梳理清楚……不过在我看来,从一个点入手,由浅入深,由点及面是参与大型开源项目相对容易的方式。因为一上来就啃一本厚书,很容易厌倦和恐惧,停留在表面,最后兴趣被各种事情冲淡,最后不了了之。而从社区一个很小的任务入手,不仅可以渐渐熟悉项目、获得成就感,更能够积累社区的信赖感,树立自我品牌,最终一览众山小。而在这个过程中,你也会发现自己的知识、技能、人际关系都在崎岖的路上不断上升! 由深入广这个小节用来讨论大家争执已久的一个问题:究竟是先进行深度学习,还是先进行广度学习。标准答案似乎是:同时进行。但是从实践的角度讲,我们的精力、学习阶段、难易程度等因素都会让这个做法变得不太容易进展、很耗时、短期内没有产出。每个人从事的工作阶段、内容都有所不同,自然看法各异。从我个人角度来看,我更倾向于先深度后广度,同时尽可能兼顾彼此。 先深度,是为了帮助我们打下坚实的基础。试想一座空中楼阁,每次风吹雨打都会引发你的惊慌,又如何风轻云淡地向四周望去?正是由于有了扎实的地基,才让你觉得能够更容易理解别的高楼的建筑风格和特色,即在同一个交流层次能帮助我们快速了解他人的核心要点和提出自己的见解。在我刚入行的时候,我很不理解为什么要去听其他人的分享?我自己的一亩三分地还没有耕作完,日日新增的工作还不够我操心,我真的有时间再关注他人吗?当时,我的思想和视野都是狭窄的,我的更多精力是聚焦在了基石的打造,从GitHub提交记录可以看到我疯狂地学习和贡献,此时我没有多余的精力,也没有欲望去关注别人,于是我的视野也很有限。而当我不断熟悉了这个项目的架构与细节,这个领域的知识体系之后,突然发现我可以抽出一部分时间和精力去了解整个行业,而不仅仅是整个项目。而且此刻,我特别有欲望想看看别的楼阁是怎么搭建的、别人的项目是什么情况,我们和别人的异同在哪里。这增大我的视野,也意味着我开始转向对广度的寻求。 其实最好的做法,还是在深耕的同时,关注广度,了解别人在做什么。这样可以有效帮助我们在世界的大地图里,知道自己在哪个位置、自己的水准如何。不过,建议是建议,实践是实践。最好的方式还是问问自己,想不想,要做不做。因为,我选择,我自由,我存在。 由内向外作为开源分布式数据库开发工程师,开源是赋予这个工作岗位的神奇力量。因为在开源的世界里,有开放、自由、平等、自我提升、品牌打造,也有竞争和资本的力量。这让我发现,我不是固步自封,我能感受到来自其他城市、不同国家的新鲜气息。在与同行朋友交流的过程中,你会发现这个行业的立体面,每个人不同的想法都非常有意思。当然,冲撞必不可少,成长的代价和痛苦也一定会非常给力地到位。迷茫和挣扎也一定会伴其左右,因为这就是一场典型的英雄之旅。但我在这个领域除了收获技能和知识,还收获了良师新友和分享的机会和能力。我并不想带来太多负面情绪给大家,我希望阅读文章的朋友能获得新的想法和力量。 过去一年半走过了深圳、上海、北京、南京,参加过中国系统架构师大会、COSCON中国开源年会、OSCHINA中国开源峰会、PstgreSQL中国技术大会、全国互联网架构峰会、ITPUB在线分享等各种会议。在机场写代码,在会场交流,在深夜写PPT。而这一系列的锻炼也磨练出了我的耐心、清晰的逻辑能力、良好的口语表达、自我的认识。我记得最开始,我编写PPT和准备分享都要提前2~3周准备,每天都抽空看看,现在已经变成提前1周准备,随后临场发挥。最近几期的音频和视频分享可以在公众号ALC Beijing 和B站收听和收看,欢迎关注。^_^ 后序篇幅所限,未能展开叙述。在文章最后,还是有些”鸡汤”想和大家分享。例如:与其病态地熬时间地做事情,不如多费心在身体锻炼和思考如何高效集中工作。作为过来人,觉得非常重要。此外,在你的英雄之旅中,找寻本我,释放压抑的情绪,活出自己。每一字一句,是我斟酌良久,给出的建议。因为在高节奏的生活和工作中,我逐渐发现自己人云亦云,被快餐手机消费,压抑自己的情绪,活着像个机器人,追寻所谓的“你好,我好,大家好”。 而现在,愿我,与你都能拥有力量,在不伤害他人的前提下,释放自己的能量,成为我自己,勇敢而执着地踏上英雄之旅!

June 16, 2020 · 1 min · jiezi

英雄之旅行走在开源领域的一个自叙故事

作者介绍潘娟,京东数科高级DBA&Apache ShardingSphere PMC,主要负责京东数科分布式数据库开发、数据库运维自动化平台开发等工作。曾负责京东数科数据库自动化平台设计与开发,现专注于Apache ShardingSphere分布式数据库中间件平台的开发。主要在分布式数据库、开源、分布式架构等相关领域进行探索。多次受邀参加数据库&架构领域的相关会议并进行分享交流。 前序《英雄之旅》是由美国神话学家约瑟夫·坎贝尔提出的。好莱坞很多经典IP巨作即是把《英雄之旅》的套路搬上了巨幕。 最近在读一些心理学书籍,随即发现我们每个人的一生都是一场英雄之旅。从被使命召唤、踏上艰辛的考验之旅、接收他人恩赐、发现自我、到达胜利顶点、回归自我。然而,很多人可能一生都行走在发现自我的路上,若是有幸,则能到达顶点,回归自我。 这篇分享以”英雄之旅“为开始,是希望把自上篇文章-程序媛成长纪:从DBA到研发工程师以来到现在的经历,提取出经验点,与所有行走在英雄之旅的朋友交流,碰撞火花。毕竟我们每个人面对工作、生活、家庭、自我都有着太多冲撞和思考,需要被他人理解和照亮。:-) 由点及面上篇的自叙文谈到我从运维DBA转成了Java开发工程师。准确的说,应该是开源分布式数据库开发工程师。因为在过去一年半多的时间里,我更多地是在分布式数据库中间件平台、分布式事务框架、分布式治理等领域做相关的研发工作。主要从事的项目是Apache分布式数据库中间件平台Apache ShardingSphere, 和京东数科主导的分布式事务平台JDTX(未开源)。 之所以说”由点及面”,是因为工作的内容开始从最初新手关注的一个点,开始渗透到整个项目的各个领域。从最初做的metaData初始化加载模块到现在Apache ShardingSphere的11个一级模块中,有8个模块都是深耕接触过,此外还有公司内部的分布式事务平台JDTX。从这里可以看出一个新手开始逐渐变成了”老司机“。这让我突然想到之前很多人问过的一个问题— 类似像ShardingSphere这样的大型项目,参与的正确姿势是什么?有人选择通读文档,有人选择把模块间架构关系梳理清楚……不过在我看来,从一个点入手,由浅入深,由点及面是参与大型开源项目相对容易的方式。因为一上来就啃一本厚书,很容易厌倦和恐惧,停留在表面,最后兴趣被各种事情冲淡,最后不了了之。而从社区一个很小的任务入手,不仅可以渐渐熟悉项目、获得成就感,更能够积累社区的信赖感,树立自我品牌,最终一览众山小。而在这个过程中,你也会发现自己的知识、技能、人际关系都在崎岖的路上不断上升! 由深入广这个小节用来讨论大家争执已久的一个问题:究竟是先进行深度学习,还是先进行广度学习。标准答案似乎是:同时进行。但是从实践的角度讲,我们的精力、学习阶段、难易程度等因素都会让这个做法变得不太容易进展、很耗时、短期内没有产出。每个人从事的工作阶段、内容都有所不同,自然看法各异。从我个人角度来看,我更倾向于先深度后广度,同时尽可能兼顾彼此。 先深度,是为了帮助我们打下坚实的基础。试想一座空中楼阁,每次风吹雨打都会引发你的惊慌,又如何风轻云淡地向四周望去?正是由于有了扎实的地基,才让你觉得能够更容易理解别的高楼的建筑风格和特色,即在同一个交流层次能帮助我们快速了解他人的核心要点和提出自己的见解。在我刚入行的时候,我很不理解为什么要去听其他人的分享?我自己的一亩三分地还没有耕作完,日日新增的工作还不够我操心,我真的有时间再关注他人吗?当时,我的思想和视野都是狭窄的,我的更多精力是聚焦在了基石的打造,从GitHub提交记录可以看到我疯狂地学习和贡献,此时我没有多余的精力,也没有欲望去关注别人,于是我的视野也很有限。而当我不断熟悉了这个项目的架构与细节,这个领域的知识体系之后,突然发现我可以抽出一部分时间和精力去了解整个行业,而不仅仅是整个项目。而且此刻,我特别有欲望想看看别的楼阁是怎么搭建的、别人的项目是什么情况,我们和别人的异同在哪里。这增大我的视野,也意味着我开始转向对广度的寻求。 其实最好的做法,还是在深耕的同时,关注广度,了解别人在做什么。这样可以有效帮助我们在世界的大地图里,知道自己在哪个位置、自己的水准如何。不过,建议是建议,实践是实践。最好的方式还是问问自己,想不想,要做不做。因为,我选择,我自由,我存在。 由内向外作为开源分布式数据库开发工程师,开源是赋予这个工作岗位的神奇力量。因为在开源的世界里,有开放、自由、平等、自我提升、品牌打造,也有竞争和资本的力量。这让我发现,我不是固步自封,我能感受到来自其他城市、不同国家的新鲜气息。在与同行朋友交流的过程中,你会发现这个行业的立体面,每个人不同的想法都非常有意思。当然,冲撞必不可少,成长的代价和痛苦也一定会非常给力地到位。迷茫和挣扎也一定会伴其左右,因为这就是一场典型的英雄之旅。但我在这个领域除了收获技能和知识,还收获了良师新友和分享的机会和能力。我并不想带来太多负面情绪给大家,我希望阅读文章的朋友能获得新的想法和力量。 过去一年半走过了深圳、上海、北京、南京,参加过中国系统架构师大会、COSCON中国开源年会、OSCHINA中国开源峰会、PstgreSQL中国技术大会、全国互联网架构峰会、ITPUB在线分享等各种会议。在机场写代码,在会场交流,在深夜写PPT。而这一系列的锻炼也磨练出了我的耐心、清晰的逻辑能力、良好的口语表达、自我的认识。我记得最开始,我编写PPT和准备分享都要提前2~3周准备,每天都抽空看看,现在已经变成提前1周准备,随后临场发挥。最近几期的音频和视频分享可以在公众号ALC Beijing 和B站收听和收看,欢迎关注。^_^ 后序篇幅所限,未能展开叙述。在文章最后,还是有些”鸡汤”想和大家分享。例如:与其病态地熬时间地做事情,不如多费心在身体锻炼和思考如何高效集中工作。作为过来人,觉得非常重要。此外,在你的英雄之旅中,找寻本我,释放压抑的情绪,活出自己。每一字一句,是我斟酌良久,给出的建议。因为在高节奏的生活和工作中,我逐渐发现自己人云亦云,被快餐手机消费,压抑自己的情绪,活着像个机器人,追寻所谓的“你好,我好,大家好”。 而现在,愿我,与你都能拥有力量,在不伤害他人的前提下,释放自己的能量,成为我自己,勇敢而执着地踏上英雄之旅!

June 16, 2020 · 1 min · jiezi

Redis-set类型hash类型Zset有序集合常用命令

setsadd myset "str"--插入数据smenbers myset--查看所有数据sismenber myset "str"--查看str是否属于myset,是返回1,否返回0scard myset--返回myset中的元素个数srandmenber myset--随机返回myset中的一个元素srandmenber myset n--随机返回n个元素spop随机删除myset中的一个元素smove myset myset "str"--将myset中的str元素移动到myset2中sdiff myset myset2 --返回两个集合中不同的元素sinter myset myste2 --返回两个集合中相同的元素sunion myset myset2 --返回两个集合合并后的总元素Hash格式:key-field-value hset myhash field value1 --添加一个数据hget myhash field --获取该字段的值hmset myhash field1 value1 field2 value2 --批量插入数据hmget mthash field1 field2 --批量获取数据hgetall myhash --获取所有field1和valuehdel myhash field1 --删除指定hash的字段hlen myhash -返回hash中有多少个值hexists myhash field1 --判断myhash中的field1是否存在hkeys myhash --返回所有的fieldhvals myhash --返回所有的valuehincrby myshash field1 1--field1自增1hdecrby myhash field1 1 --field1 自减1hsetnx myshash field1 va1 --如果field1不存在则添加,存在则无法添加 ...

June 16, 2020 · 1 min · jiezi

Go语言之-Redis

Redis驱动 推荐包https://github.com/astaxie/go...安装go get -u github.com/astaxie/goredis 上述驱动的源码地址,源码是最好的文档! 很香~~~https://github.com/astaxie/goredis/blob/master/redis.go实例代码 package main import ( "fmt" "github.com/astaxie/goredis")func main () { var client goredis.Client client.Addr="127.0.0.1:6379" err:=client.Set("test",[]byte("hello world")) if err!=nil { panic(err) }else { fmt.Println("设置成功") } res,err:=client.Get("test") if err!=nil { panic(err) }else { fmt.Println("%T",res) fmt.Println(string(res)) } ts,err:=client.Setnx("test01",[]byte("lamp")) if err !=nil { panic(err) }else { fmt.Println(ts) } f:=make(map[string]interface{}) f["name"]="zhangsan" f["age"]=23 f["sex"]="nam" err=client.Hmset("test_hash",f) if err!=nil { panic(err) }else { fmt.Println("hash数据设置成功") } name,err:=client.Hget("test_hash","name") if err!=nil { panic(err) }else { fmt.Printf("%T\n",name) // []uint8 字节型(字符类型):byte(uint8别名) fmt.Println("hash_name:",string(name)) }}

June 10, 2020 · 1 min · jiezi

Redis单线程为什么快

为啥这么快:1.redis是基于内存的,内存的读写速度非常快; 2.redis是单线程的,省去了很多上下文切换线程的时间; 3.redis使用多路复用技术,可以处理并发的连接; 简单解释下第二条:上下文切换就是cpu在多线程之间进行轮流执行(抢占cpu资源),而redis单线程的,因此避免了繁琐的多线程上下文切换。 重点解释下多路复用: 多路-指的是多个socket连接,复用-指的是复用一个线程。 目前,多路复用主要有三种技术:select,poll,epoll。它们出现的顺序是按时间先后的,越排后的技术改正了之前技术的缺点。epoll是最新的也是目前最好的多路复用技术。 举个例子:一个酒吧服务员,前面有很多醉汉,epoll这种方式相当于一个醉汉吼了一声要酒,服务员听见之后就去给他倒酒,而在这些醉汉没有要求的时候服务员可以玩玩手机干点别的。但是select和poll技术是这样的场景:服务员轮流着问各个醉汉要不要倒酒,没有空闲的时间。io多路复用的意思就是多个醉汉共用一个服务员。 select: 1.会修改传入的参数,对于多个调用的函数来说非常不友好; 2.要是sock(io流出现了数据),select只能轮询这去找数据,对于大量的sock来说开销很大; 3.不是线程安全的,很恐怖; 4.只能监视1024个连接;poll: 1.还不是线程安全的... 2.去掉了1024个连接的限制; 3.不修改传入的参数了;epoll: 1.线程安全了; 2.epoll不仅能告诉你sock有数据,还能告诉你哪个sock有数据,不用轮询了; 3.however,只支持linux系统;

June 9, 2020 · 1 min · jiezi

Redis实战-读书分享2

第二章 使用Redis构建web应用(案例分析)2.1 登录和cookie缓存业务分析登录时验证token令牌用户每次浏览页面,保存用户浏览时间用户浏览商品页,将商品保存到最近浏览,并限额25个定期清理token令牌,最大保存1000万个(守护进程触发,超过能移除最多100个最旧令牌,并从散列中删除令牌对应的用户信息,最近浏览商品也进行存储,未超过休眠1s)数据构建设计hash 登录token(token、userID)zset 最近登录用户(token、浏览页面的时间戳)zset 最近浏览商品(商品ID、浏览商品的时间戳) 代码实现 python# 尝试获取并返回令牌对应的用户,这里有漏洞,应该判断token是否合法,并不能仅仅判断Redis中是否有无def check_token(conn,token): return conn.hget('login:',token)# 更新token,并保持最近浏览时间,和最近浏览商品 def update_token(conn,token,user,item=None): timestamp = time.time() conn.hset('login:',token,user) conn.zadd('recent:',token,timestamp) if item : conn.zadd('viewed:' + token,item,timestamp) conn.zremrangebyrank('viewed:' + token,0,-26)# 循环清理超数量令牌QUIT = FalseLIMIT = 10000000def clean_sessions(conn): while not QUIT: size = conn.zcard('recent:') if size < LIMIT time.sleep(1) continue # 获取删除的个数,没到100,就选size-LIMIT,超过100就选100 end_index = min(size - LIMIT,100) tokens = conn.zrange('recent:',0,end_index-1) session_keys = [] for token in tokens: session_keys.append('viewed:' + 'token') # 删除最近浏览商品 conn.delete(*session_keys) # 删除登录token conn.hdel('login:',*token) # 删除最近浏览页面记录 conn.zrem('recent:',*token) 2.2 网页缓存(静态化)数据结构设计 : 存储在string中代码实现 Python# callback-对于不能被缓存的数据,可直接调用回调函数def cache_request(conn,request,callback): if not can_cache(conn,request): return callback(request) # 将request请求转换成字符串,方便查找 page_key = 'cache:' + hash_request(request) # 尝试查找被缓存页面, content = conn.get(page_key) if not content : content = callback(request) # 将新生成页面放在缓存中,并设置5分钟过期 conn.setx(page_key,content,300) return content

June 9, 2020 · 1 min · jiezi

Redis实战读书分享1

目前啊,公司有些动荡,程序员??真是不容易呀。自己趁着空余的时间,将原来看过的书和知识点再捋一遍。ps: 纯手打,希望大家多多关注和点赞,后续陆续更新,希望大家一起进步! 图片使用的是processOn画的,有兴趣的小伙伴可以去试一下 如果同学需要电子书,可以评论区留言 吐槽processon,非会员文件最多9个,坑! 第一部分 入门第一章 初识 redis1.1 Redis简介Redis 概念Redis是一个速度很快的非关系型数据库,可以存储key-value之间的映射,可以将存储在内存中的键值对数据持久化到硬盘,可以使用复制特性来扩展读性能,可以使用客户端分片来扩展写性能Redis与其他数据库对比数据库名称 类型 数据存储 查询类型 附件功能 Redis 使用内存存储(in-memory)非关系型数据库 字符串、列表、集合、散列、有序集合 每种数据类型都有自己的专属命令,另外还有批量操作和不完成的事务支持 发布订阅、主从复制、持久化、脚本 memcached 使用内存存储的键值缓存 键值对之间的映射 创建、读取、更新、删除等命令 为提升性能而设的多线程服务器 MySQL 关系型数据库 数据库-表-行 结构 CURD相关函数 支持ACID特性、主从复制、主主复制 postgresql 关系型数据库 同上 同上 同上 MongoDB 使用硬盘存储(on-disk)的非关系文档存储 数据库-表-BSON文档 结构 创建、读取、更新、删除等命令 支持map-reduce操作、主从复制、分片、空间索引 附加特性RDB 和AOF 两种持久化方式支持主从复制①执行复制的从服务器1.2 Redis数据结构 字符串 stringset hello world get hello del hello列表 listrpush list-key item lpush list-key item2 lrange list-key 0 -1 lindex list-key 1 lpop list-key rpop list-key集合 set列表可以存储多个相同字符串,集合存储的字符串各不相同 sadd set-key item 添加成功返回1,已经存在返回0 smembers set-key sismember set-key item 已经存在返回1,不存在返回0 srem set-key item散列 hash可以将hash看做关系型数据库的行 hset hash-key sub-key1 value1 hgetall hash-key hdel hash-key sub-key1 hget hash-key sub-key1有序集合 zset有序集合和散列,都可以存储键值对有序集合中,键:成员,值:分值,分值必须为浮点数Redis中唯一一个,既可以根据成员访问元素,又可以根据分值以及分值的排列顺序访问元素的结构 zadd zset-key 123 member1 zrange zset-key 0 -1 withscores zrangeby zset-key 0 800 withscores 根据分值的范围查找 zrem zset-key member11.3 Redis案列分析(类stackoverflow)1.3.1 对文章进行投票业务分析可以对文章进行点赞文章评分:得票数 * 常量 + 文章发布时间每人每篇只能投一次,只能投一周数据构建设计hash 文章信息(标题、网址、发布用户、发布时间、投票数)zset 文章发布时间(文章ID、发布时间)-可以通过发布时间排序zset 文章评分(文章ID、评分)-可以通过评分排序set 文章已投用户列表(key-文章ID、value-已投用户ID)-一周后就可删除 实现逻辑当用户尝试对一篇文章投票,先去文章发布时间的zset中(zscore命令)检查文章是否超过一周如果文章仍然可以投票,zadd将用户添加到文章已投用户列表set中如果添加成功,则表示该用户第一次对该文章投票,并(zincrby命令)为文章评分zset添加400(设置的常量),并(hincrby命令)为文章信息hash中投票数+1代码展示 python’‘’ 这里应该使用Redis事务,后续章节再添加进来‘’‘ONE_WEEK_IN_SECONDS = 7 * 86400VOTE_SCORE = 400def article_vote(conn,uer,article): cutoff = time.time() - ONE_WEEK_IN_SECONDS if conn.zscore('time:'+ article)< cutoff return # -1的好处是无论前面添加了栏目,ID的索引-1 article_id = article.partition(':')[-1] if conn.sadd('voted:' + article_id,user) conn.zincrby('score:',article,VOTE_SCORE) conn.hincrby(article,'votes',1)1.3.2 发布文章实现逻辑首先创建一个文章ID,可以通过计数器(INCR命令)将文章作者ID添加(SADD命令)到文章已投用户列表,本人默认已经投了自己的文章为文章已投用户列表的set设置(EXPIRE命令)过期时间,1周后自动删除存储(HMSET)文章相关信息将初始评分和发布时间分别添加(ZADD)到对应的有序集合中代码展示 Pythondef post_article(conn,user,title,link): article_id = str(conn.incr('article:')) voted = 'voted:' + article_id conn.sadd(voted,user) conn.expire(voted,ONE_WEEK_IN_SECONDS) now = time.time() article = 'article:' + article_id conn.hmset(article,{ 'title':title, 'link':link, 'poster':user, 'time':now, 'votes':1 }) conn.zadd('time:',article,now) conn.zadd('score:',article,now + VOTE_SCORE)1.3.3 获取文章(评分最高的文章、最新发布的文章)实现逻辑先使用ZREVRANGE(倒序范围取值)在zset中取出多个文章ID然后在hash中对每篇文章ID执行HGETALL取出文章详细信息代码实现 PythonARTICLES_PER_PAGE = 25def get_articles(conn,page,order='score:'): start = (page-1) * ARTICLES_PER_PAGE end = start + ARTICLES_PER_PAGE -1 ids = conn.zrevrange(order,start,end) articles = [] for id in ids: article_data = conn.hgetall(id) # 给源数据添加ID article_data['id'] = id articles.append(article_data) return articles1.3.3 对文章进行分组(分类,标签等类似功能),并取出分组中评分最高或时间最新文章实现逻辑分组可使用集合set将分组集合set、评分有序集合zset(或者时间的有序集合zset),进行交集(ZINTERSTORE命令)计算,存储到一个有序集合然后从有序集合中获取排序的文章信息,为了减少Redis计算量,将交集结果缓存60秒 代码实现 Pythondef get_group_articles(conn,group,page,order='score:'): #交集的key key = order + group if not conn.exists(key): conn.zinterstore(key,['group:'+group,order],aggregate='max') conn.expire(key,60) #调用原有方法获取文章排序 return get_articles(conn,page,key)

June 8, 2020 · 2 min · jiezi

初识Redis一

前言今天来讲讲redis以下知识点,如有不当请多指教! Redis持久化主从复制Sentinel机制Redis ClusterRedis持久化redis是基于内存的,如果不想办法将数据保存在硬盘上,一旦redis重启(退出/故障),内存的数据将会全部丢失。 Redis提供了两种持久化方法: RDB(基于快照),将某一时刻的所有数据保存到一个RDB文件中。 AOF(append-only-file),当Redis服务器执行写命令的时候,将执行的写命令保存到AOF文件中。 RDB保存某个时间点的全量数据快照 手动触发SAVE:阻塞Redis的服务器进程,知道RDB文件被创建完毕 BGSAVE:Fork出一个子进程来创建RDB文件,不阻塞服务器进程,使用lastsave指令可以查看最近的备份时间 自动触发根据redis.conf配置里的save m n定时触发(用的是BGSAVE) 主从复制时,主节点自动触发 执行Debug Relaod 执行Shutdown且没有开启AOF持久化 注意:Redis服务器在启动的时候,如果发现有RDB文件,就会自动载入RDB文件(不需要人工干预) RDB的优缺点优点: RDB是一个紧凑压缩的二进制文件,代表Redis在某个时间点上的数据快照,适合备份,全量复制等场景。 且加载RDB恢复数据远远快于AOF的方式。 缺点: 没办法做到实时持久化/秒级持久化,因为bgsave每次运行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本过高。 RDB的相关配置//在n秒内修改m条数据时创建RDB文件save 900 1save 300 10save 60 10000stop-writes-on-bgsave-error yes //bgsave出错时停止写入rdbcompression yes //压缩RDB文件rdbchecksum yes //校验文件是否损坏AOF与RDB不一样的是,AOF记录的是命令,而不是数据。 如何开启AOF? 只需在配置文件中将appendonly设置为yes即可。 AOF的工作流程:1、所有的写入命令追加到aof_buf缓冲区中。 2、AOF会根据对应的策略向磁盘做同步操作。刷盘策略由appendfsync参数决定。 3、定期对AOF文件进行重写。重写策略由auto-aof-rewrite-percentage,auto-aof-rewrite-min-size两个参数决定。 appendfsync参数有如下取值: appendfsync always # 每次有数据修改发生时都会写入AOF文件。appendfsync everysec # 每秒钟同步一次,该策略为AOF的默认策略。appendfsync no # 从不同步。高效但是数据不会被持久化。AOF重写为什么要重写? 重写后可以加快节点启动时的加载时间 重写后的文件为什么可以变小? 进程内超时的数据不用再写入到AOF文件中 多条写命令可以合并为一个 重写条件1、手动触发      直接调用bgrewriteaof命令 2、自动触发 先来看看有关参数: auto-aof-rewrite-min-size:执行AOF重写时,文件的最小体积,默认值为64MB。 auto-aof-rewrite-percentage:执行AOF重写时,当前AOF大小(即aof_current_size)和上一次重写时AOF大小(aof_base_size)的比值。 只有当auto-aof-rewrite-min-size和auto-aof-rewrite-percentage两个参数同时满足时,才会自动触发AOF重写。 后台重写Redis将AOF重写程序放到子进程里执行(BGREWRITEAOF命令),像BGSAVE命令一样fork出一个子进程来完成重写AOF的操作,从而不会影响到主进程。 AOF后台重写是不会阻塞主进程接收请求的,新的写命令请求可能会导致当前数据库和重写后的AOF文件的数据不一致! 为了解决数据不一致的问题,Redis服务器设置了一个AOF重写缓冲区,当子进程完成重写后会发送信号让父进程将AOF重写缓冲区的数据写到新的AOF文件。 ...

June 8, 2020 · 1 min · jiezi

别让HR再质问我我费劲招的人你用缓存问废了不能简单点

概念缓存穿透 在高并发下,查询一个不存在的值时,缓存不会被命中,导致大量请求直接落到数据库上,如活动系统里面查询一个不存在的活动。 缓存击穿 在高并发下,对一个特定的值进行查询,但是这个时候缓存正好过期了,缓存没有命中,导致大量请求直接落到数据库上,如活动系统里面查询活动信息,但是在活动进行过程中活动缓存突然过期了。 缓存雪崩 在高并发下,大量的缓存key在同一时间失效,导致大量的请求落到数据库上,如活动系统里面同时进行着非常多的活动,但是在某个时间点所有的活动缓存全部过期。 常见解决方案直接缓存NULL值限流缓存预热分级缓存缓存永远不过期layering-cache实践在layering-cache里面结合了缓存NULL值,缓存预热,限流、分级缓存和间接的实现"永不过期"等几种方案来应对缓存穿透、击穿和雪崩问题。 直接缓存NULL值 应对缓存穿透最有效的方法是直接缓存NULL值,但是缓存NULL的时间不能太长,否则NULL数据长时间得不到更新,也不能太短,否则达不到防止缓存击穿的效果。 我在layering-cache对NULL值进行了特殊处理,一级缓存不允许存NULL值,二级缓存可以配置缓存是否允许存NULL值,如果配置可以允许存NULL值,框架还支持配置缓存非空值和NULL值之间的过期时间倍率,这使得我们能精准的控制每一个缓存的NULL值过期时间,控制粒度非常细。当NULL缓存过期我还可以使用限流,缓存预热等手段来防止穿透。 示例: @Cacheable(value = "people", key = "#person.id", depict = "用户信息缓存", firstCache = @FirstCache(expireTime = 10, timeUnit = TimeUnit.MINUTES), secondaryCache = @SecondaryCache(expireTime = 10, timeUnit = TimeUnit.HOURS, isAllowNullValue = true, magnification = 10))public Person findOne(Person person) { Person p = personRepository.findOne(Example.of(person)); logger.info("为id、key为:" + p.getId() + "数据做了缓存"); return p;}在这个例子里面isAllowNullValue = true表示允许缓存NULL值,magnification = 10表示NULL值和非NULL值之间的时间倍率是10,也就是说当缓存值为NULL时,二级缓存的有效时间将是1个小时。 限流 应对缓存穿透的常用方法之一是限流,常见的限流算法有滑动窗口,令牌桶算法和漏桶算法,或者直接使用队列、加锁等,在layering-cache里面我主要使用分布式锁来做限流。 layering-cache数据读取流程: 下面是读取数据的核心代码: ...

June 5, 2020 · 2 min · jiezi

自定义RedisCacheManager

自定义RedisCacheManager 在项目的Redis配置类RedisConfig中,按照上一步分析的定制方法自定义名为cacheManager的Bean组件 java @Bean public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { // 分别创建String和JSON格式序列化对象,对缓存数据key和value进行转换 RedisSerializer<String> strSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class); // 解决查询缓存转换异常的问题 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jacksonSeial.setObjectMapper(om); // 定制缓存数据序列化方式及时效 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofDays(1)) .serializeKeysWith(RedisSerializationContext.SerializationPair .fromSerializer(strSerializer)) .serializeValuesWith(RedisSerializationContext.SerializationPair .fromSerializer(jacksonSeial)) .disableCachingNullValues(); RedisCacheManager cacheManager = RedisCacheManager .builder(redisConnectionFactory).cacheDefaults(config).build(); return cacheManager; } 上述代码中,在RedisConfig配置类中使用@Bean注解注入了一个默认名称为方法名的cacheManager组件。在定义的Bean组件中,通过RedisCacheConfiguration对缓存数据的key和value分别进行了序列化方式的定制,其中缓存数据的key定制为StringRedisSerializer(即String格式),而value定制为了Jackson2JsonRedisSerializer(即JSON格式),同时还使用entryTtl(Duration.ofDays(1))方法将缓存数据有效期设置为1天 完成基于注解的Redis缓存管理器RedisCacheManager定制后,可以对该缓存管理器的效果进行测试(使用自定义序列化机制的RedisCacheManager测试时,实体类可以不用实现序列化接口) 学习让人快乐,学习更让人觉得无知!学了1个多月的《Java工程师高薪训练营》,才发现自己对每个技术点的认知都很肤浅,根本深不下去,立个Flag:每天坚持学习一小时,一周回答网上3个技术问题,把自己知道都分享出来。

June 5, 2020 · 1 min · jiezi

Redis注解默认序列化机制

Redis注解默认序列化机制 打开Spring Boot整合Redis组件提供的缓存自动配置类RedisCacheConfiguration(org.springframework.boot.autoconfigure.cache包下的),查看该类的源码信息,其核心代码如下 java @Configuration class RedisCacheConfiguration { @Bean public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory,ResourceLoader resourceLoader) { RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory) .cacheDefaults(this.determineConfiguration(resourceLoader.getClassLoader())); List<String> cacheNames = this.cacheProperties.getCacheNames(); if(!cacheNames.isEmpty()) { builder.initialCacheNames(new LinkedHashSet(cacheNames)); } return (RedisCacheManager)this.customizerInvoker.customize(builder.build()); } private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration(ClassLoader classLoader){ if(this.redisCacheConfiguration != null) { return this.redisCacheConfiguration; } else { Redis redisProperties = this.cacheProperties.getRedis(); org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig(); config = config.serializeValuesWith(SerializationPair.fromSerializer( new JdkSerializationRedisSerializer(classLoader))); ... return config; } } } 从上述核心源码中可以看出,同RedisTemplate核心源码类似,RedisCacheConfiguration内部同样通过Redis连接工厂RedisConnectionFactory定义了一个缓存管理器RedisCacheManager;同时定制RedisCacheManager时,也默认使用了JdkSerializationRedisSerializer序列化方式。 如果想要使用自定义序列化方式的RedisCacheManager进行数据缓存操作,可以参考上述核心代码创建一个名为cacheManager的Bean组件,并在该组件中设置对应的序列化方式即可 * 注意,在Spring Boot 2.X版本中,RedisCacheManager是单独进行构建的。因此,在Spring Boot 2.X版本中,对RedisTemplate进行自定义序列化机制构建后,仍然无法对RedisCacheManager内部默认序列化机制进行覆盖(这也就解释了基 于注解的Redis缓存实现仍然会使用JDK默认序列化机制的原因),想要基于注解的Redis缓存实现也使用自定义序列化机制,需要自定义RedisCacheManager. ...

June 5, 2020 · 1 min · jiezi

redis-实现搜索热词统计

核心需求一个项目中,遇到了搜索热词统计的需求,我使用了 Redis 的五大数据类型之一 Sorted Set 实现。目前有两项数据需要统计:“当日搜索热词 top10”和“当周搜索热词 top10”。 关于这两项数据的统计方法,目前想到了两种实现方法: 两个 Redis 的 Sorted Set 实现,一个 Sorted Set A 统计当天,0 点 top10 记录进 MySQL,Sorted Set 清零。一个 Sorted Set B 统计当周,每周日 top10 记录进 MySQL,Sorted Set B 清零。只使用用一个 Sorted Set 记录当天搜索热词,0 点 top10 记录进 MySQL,Sorted Set 清零。到周日时,会有 7 10 行记录。把这 7 10 行遍历,每次便利都记录进 Sorted Set,全部遍历结束后,再从 Sorted Set 中取出 top10 记录进 MySQL 的周热词统计表中。Sorted Set 是 Redis 的数据结构,方法 1 会占用两份内存,一份当天的,一份当周的。方法 2 会提高系统的复杂度,并且在统计周表时,可能会出现短时间内大量的计算(当然可以使用定时任务,把周表的统计放到凌晨进行)。 ...

June 3, 2020 · 2 min · jiezi

redis-哨兵模式集群配置

都是在本地虚拟机作为例子如果是生产环境修改对应的ip即可1、master 配置 /home/redis/redis-5.0.8/redis.conf bind 127.0.0.1port 6379tcp-backlog 511timeout 0tcp-keepalive 300daemonize nosupervised nopidfile /var/run/redis_6379.pidloglevel noticelogfile "6379.log"databases 16always-show-logo yessave 900 1save 300 10save 60 10000rdbcompression yesdbfilename dump.rdbdir /usr/local/redis/redis-6379/replica-serve-stale-data yesreplica-read-only yesrepl-diskless-sync norepl-diskless-sync-delay 5lazyfree-lazy-eviction nolazyfree-lazy-expire nolazyfree-lazy-server-del noreplica-lazy-flush noappendonly nono-appendfsync-on-rewrite noaof-load-truncated yesaof-use-rdb-preamble yeslua-time-limit 5000slowlog-max-len 128latency-monitor-threshold 0list-max-ziplist-size -2list-compress-depth 0zset-max-ziplist-entries 128zset-max-ziplist-value 64hll-sparse-max-bytes 3000stream-node-max-bytes 4096stream-node-max-entries 100activerehashing yesclient-output-buffer-limit normal 0 0 0client-output-buffer-limit replica 256mb 64mb 60client-output-buffer-limit pubsub 32mb 8mb 60hz 10dynamic-hz yesaof-rewrite-incremental-fsync yesrdb-save-incremental-fsync yesslave-6380 bind 127.0.0.1port 6380tcp-backlog 511timeout 0tcp-keepalive 300daemonize nosupervised nopidfile /var/run/redis_6380.pidloglevel noticelogfile "6380.log"databases 16always-show-logo yessave 900 1save 300 10save 60 10000rdbcompression yesdbfilename dump.rdbdir /usr/local/redis/redis-6380/replica-serve-stale-data yesreplica-read-only yesrepl-diskless-sync norepl-diskless-sync-delay 5lazyfree-lazy-eviction nolazyfree-lazy-expire nolazyfree-lazy-server-del noreplica-lazy-flush noappendonly nono-appendfsync-on-rewrite noaof-load-truncated yesaof-use-rdb-preamble yeslua-time-limit 5000slowlog-max-len 128latency-monitor-threshold 0list-max-ziplist-size -2list-compress-depth 0zset-max-ziplist-entries 128zset-max-ziplist-value 64hll-sparse-max-bytes 3000stream-node-max-bytes 4096stream-node-max-entries 100activerehashing yesclient-output-buffer-limit normal 0 0 0client-output-buffer-limit replica 256mb 64mb 60client-output-buffer-limit pubsub 32mb 8mb 60hz 10dynamic-hz yesaof-rewrite-incremental-fsync yesrdb-save-incremental-fsync yes#replicaof 127.0.0.1 6379slave-6381 ...

May 31, 2020 · 2 min · jiezi

redis-安装

1.新建redis文件夹mkdir /home/redis2.进入redis目录cd /home/redis3.下载 redis-5.0.8 wget http://download.redis.io/rele...4.解压redistar zxvf redis-5.0.8.tar.gz5.进入 redis-5.0.8cd /home/reids/redis-5.0.8/src6.编译(编译前确定依据安装了gcc,如果没有安装则yum install gcc)make7.配置redis8.设置redis为开机启动 新建开机启动脚本 vi /etc/init.d/redis 输入开机脚本: #chkconfig: 2345 10 90# description: Start and Stop redis# Simple Redis init.d script conceived to work on Linux systems# as it does use of the /proc filesystem.REDISPORT=6379EXEC=/home/redis/redis-5.0.8/src/redis-serverCLIEXEC=/home/redis/redis-5.0.8/src/redis-cliPIDFILE=/var/lib/redis/redis_${REDISPORT}.pid#CONF="/etc/redis/${REDISPORT}.conf"CONF="/home/redis/redis-5.0.8/redis.conf"case "$1" in start) if [ -f $PIDFILE ] then echo "$PIDFILE exists, process is already running or crashed" else echo "Starting Redis server..." $EXEC $CONF & fi ;; stop) if [ ! -f $PIDFILE ] then echo "$PIDFILE does not exist, process is not running" else PID=$(cat $PIDFILE) echo "Stopping ..." $CLIEXEC -p $REDISPORT shutdown while [ -x /proc/${PID} ] do echo "Waiting for Redis to shutdown ..." sleep 1 done echo "Redis stopped" fi ;; restart) "$0" stop sleep 3 "$0" start ;; *) echo "Please use start or stop or restart as first argument" ;;esac9.添加redis服务chkconfig --add redis10.设置为开机启动 chkconfig redis on 11.启动服务 nohup service redis start ...

May 31, 2020 · 1 min · jiezi

Redis操作配置信息详细

CMD操作CONFIG 命令查看或设置配置项。CONFIG get * 查看所有配置CONFIG get XXXCONFIG set XXX YYY (设置XXX = YYY)所有配置信息**提示:第一行为key 第二行为value**1. "dbfilename" //指定本地数据库文件名,默认值为dump.rdb 2. "dump.rdb" 3. "requirepass" 4. //设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH <password>命令提供密码,默认关闭 5. //在登录的时候的时候输入密码: 6. // redis-cli -p 6379 -a 密码(a =auth) 7. 4) "" 8. 5) "masterauth" 9. // 当master服务设置了密码保护时,slav服务连接master的密码 这个就是权限验证 10. 6) "" 11. 7) "unixsocket" 12. 8) "" 13. 9) "logfile" 14. //日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出 15. 10) "/var/log/redis/redis-server.log" 16. 11) "pidfile" 17. 12) "/var/run/redis/redis-server.pid" 18. 13) "maxmemory" 19. // 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中, 20. //达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后, 21. //仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。 22. //Redis新的vm机制,会把Key存放内存,Value会存放在swap区 23. 14) "0" 24. 15) "maxmemory-samples" 25. 16) "3" 26. 17) "timeout" 27. //当 客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能 28. 18) "0" 29. 19) "tcp-keepalive" 30. 20) "0" 31. 21) "auto-aof-rewrite-percentage" 32. 22) "100" 33. 23) "auto-aof-rewrite-min-size" 34. 24) "67108864" 35. 25) "hash-max-ziplist-entries" 36. 26) "512" 37. 27) "hash-max-ziplist-value" 38. 28) "64" 39. 29) "list-max-ziplist-entries" 40. 30) "512" 41. 31) "list-max-ziplist-value" 42. 32) "64" 43. 33) "set-max-intset-entries" 44. 34) "512" 45. 35) "zset-max-ziplist-entries" 46. 36) "128" 47. 37) "zset-max-ziplist-value" 48. 38) "64" 49. 39) "lua-time-limit" 50. 40) "5000" 51. 41) "slowlog-log-slower-than" 52. 42) "10000" 53. 43) "slowlog-max-len" 54. 44) "128" 55. 45) "port" //端口号 56. 46) "6379" 57. 47) "databases" //设置数据库的数量,默认数据库为0 58. 48) "16" 59. 49) "repl-ping-slave-period" 60. 50) "10" 61. 51) "repl-timeout" 62. 52) "60" 63. 53) "repl-backlog-size" 64. 54) "1048576" 65. 55) "repl-backlog-ttl" 66. 56) "3600" 67. 57) "maxclients" 68. //设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为 69. //Redis进程可以打开的最大文件描述符数,如果设 置 maxclients 0,表示不作限制。 70. //当客户端连接数到达限制时, 71. //Redis会关闭新的连接并向客户端返回max number of clients reached错误信息 72. 58) "3984" 73. 59) "watchdog-period" 74. 60) "0" 75. 61) "slave-priority" 76. 62) "100" 77. 63) "min-slaves-to-write" 78. 64) "0" 79. 65) "min-slaves-max-lag" 80. 66) "10" 81. 67) "hz" 82. 68) "10" 83. 69) "no-appendfsync-on-rewrite" 84. 70) "no" 85. 71) "slave-serve-stale-data" 86. 72) "yes" 87. 73) "slave-read-only" 88. 74) "yes" 89. 75) "stop-writes-on-bgsave-error" 90. 76) "yes" 91. 77) "daemonize" //以守护进程的方式运行 92. 78) "yes" 93. 79) "rdbcompression" 94. //指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩, 95. //如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大 96. 80) "yes" 97. 81) "rdbchecksum" 98. 82) "yes" 100. 83) "activerehashing" 101. // 指定是否激活重置哈希,默认为开启 102. 84) "yes" 104. 85) "repl-disable-tcp-nodelay" 105. 86) "no" 106. 87) "aof-rewrite-incremental-fsync" 107. 88) "yes" 108. 89) "appendonly" 109. //. 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘, 110. //如果不开启,可能会在断电时导致一段时间内//的数据丢失。 111. //因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no 112. // 这个和save 保存同步有关系 113. 90) "no" 114. 91) "dir" //指定本地数据库存放目录 115. 92) "/var/lib/redis" 117. 93) "maxmemory-policy" 118. 94) "volatile-lru" 120. 95) "appendfsync" 121. //之前的那个是否记录日志,这里表示记录日志的类型 122. // 指定更新日志条件,共有3个可选值: 123. //no:表示等操作系统进行数据缓存同步到磁盘(快) 124. //always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全) 125. //everysec:表示每秒同步一次(折衷,默认值) 126. 96) "everysec" 128. 97) "save" 129. //指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合 (让数据一致性,内存的数据和磁盘的数据) 130. 98) "900 1 300 10 60 10000" 131. // 分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。 133. 99) "loglevel" 134. //日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning 135. 100) "notice" 137. 101) "client-output-buffer-limit" 138. 102) "normal 0 0 0 slave 268435456 67108864 60 pubsub 33554432 8388608 60" 139. 103) "unixsocketperm" 140. 104) "0" 142. 105) "slaveof" 143. //slave 奴隶主要指从数据库 主从数据库就是集群环境中使用的 144. //设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步 145. 106) "" 146. 107) "notify-keyspace-events" 147. 108) "" 148. 109) "bind" //绑定的主机的ip 149. 110) "0.0.0.0" `

May 31, 2020 · 3 min · jiezi

Redis-AOF一篇即懂

序章除了RDB持久化功能以外,Redis还提供了AOF(Append Only File)持久化功能。与RDB持久化通过保存数据库中的键值对来记录数据库状态不同,AOF持久化是通过保存Redis所执行的写命令来记录数据库状态的。 AOF如何打开redis默认情况是关闭AOF的,所以要使用就要先通过以下方式打开:第一种方式:打开 redis.conf  修改以下参数: appendonly  yes        (默认no,关闭)表示是否开启AOF持久化:  appendfilename “appendonly.aof”   AOF持久化配置文件的名称:** 默认情况下redis安装目录会生成 appendonly.aof文件,如果没有则执行以下方式第二种方式:在cmd通过redis-cli连接到服务器的命令界面里输入config set appendonly yes config set save “”(可选) 执行的第一条命令开启了 AOF 功能: Redis 会阻塞直到初始 AOF 文件创建完成为止, 之后 Redis 会继续处理命令请求, 并开始将写入命令追加到 AOF 文件末尾。 执行的第二条命令用于关闭 RDB 功能。 这一步是可选的, 如果你愿意的话, 也可以同时使用 RDB 和 AOF 这两种持久化功能。(如果RDB和AOF同时开启,则AOF优先加载) AOF如何实现持久化AOF持久化功能的实现可以分为命令追加、文件写入、文件同步三个步骤。 命令追加: 当AOF持久化功能打开时,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾。 AOF文件的写入与同步: 每当服务器常规任务函数被执行、 或者事件处理器被执行时, aof.c/flushAppendOnlyFile 函数都会被调用, 这个函数执行以下两个工作: WRITE:根据条件,将 aof_buf 中的缓存写入到 AOF 文件。 SAVE:根据条件,调用 fsync 或 fdatasync 函数,将 AOF 文件保存到磁盘中。 两个步骤都需要根据一定的条件来执行, 而这些条件由 AOF 所使用的保存模式来决定, 以下小节就来介绍 AOF 所使用的三种保存模式, 以及在这些模式下, 步骤 WRITE 和 SAVE 的调用条件。 ...

May 31, 2020 · 2 min · jiezi

Redis协议规范RESP一篇即懂

序章Redis 即REmoteDictionaryServer (远程字典服务); 而Redis的协议规范是 Redis Serialization Protocol (Redis序列化协议) 该协议是用于与Redis服务器通信的,用的较多的是Redis-cli通过pipe与Redis服务器联系; 协议如下: 客户端以规定格式的形式发送命令给服务器; 服务器在执行最后一条命令后,返回结果。 特点1、实现简单2、快速解析3、可读性好 客户端发送命令规定格式(类型):5种类型提示:间隔符号,在Linux下是\r\n,在Windows下是\n1、简单字符串 Simple Strings, 以 "+"加号 开头 格式:+ 字符串 \r\n 字符串不能包含 CR或者 LF(不允许换行) eg: "+OK\r\n" 注意:为了发送二进制安全的字符串,一般推荐使用后面的 Bulk Strings类型 2、错误 Errors, 以"-"减号 开头 格式:- 错误前缀 错误信息 \r\n 错误信息不能包含 CR或者 LF(不允许换行),Errors与Simple Strings很相似,不同的是Erros会被当作异常来看待 eg: "-Error unknow command 'foobar'\r\n" 3、整数型 Integer, 以 ":" 冒号开头 格式:: 数字 \r\n eg: ":1000\r\n" 4、大字符串类型 Bulk Strings, 以 "$"美元符号开头,长度限制512M 格式:$ 字符串的长度 \r\n 字符串 \r\n ...

May 31, 2020 · 1 min · jiezi