当前位置: 首页 > 科技观察

Redis在大数据中的使用技巧

时间:2023-03-12 13:37:06 科技观察

今天和大家一起探讨一些Redis在大数据中的使用技巧,包括一些Redis的使用技巧等内容。一、Redis封装架构说明其实NewLife.Redis是对Redis协议功能的完整实现,但是Redis的核心功能并不在其中,而是在NewLife.Core中。在这里你可以打开它看看。NewLife.Core中有一个NewLife.Caching命名空间,里面有一个Redis类,实现了Redis的基本功能;另一个类是RedisClient,它是Redis的客户端。Redis的核心功能就是由这两个类实现的。RedisClient表示Redis客户端和服务器之间的连接。在实际使用Redis的时候,有一个Redis连接池,里面存放着很多RedisClient对象。所以我们的Redis包有两层,一层是NewLife.Core中的Redis和RedisClient;另一个是NewLife.Redis。这里的FullRedis为Redis实现了Redis的所有高级功能。这里也可以认为NewLife.Redis是Redis的扩展。二、测试实例讲解Redis的基本使用1、打开Program.cs,查看实例中的代码:这里是XTrace.UseConsole();就是将日志输出到控制台,方便调试和查看结果。接下来我们来看第一个例子Test1。我已经在代码中评论了细节。可以看一下:设置的时候,如果是字符串或者字符数据,Redis会直接保存(字符串内部机制也是Savebinary),如果是其他类型,默认会json序列化,然后保存。获取时,如果是字符串或者字符数据,则直接获取,如果是其他类型,则反序列化成json。Set的第三个参数以秒为单位过期。VS调试提示,按F5或者直接工具栏“Start”编译整个解决方案会很慢(VS默认),可以选择项目右键菜单选择Debug->Startanewinstance,只会编译将要使用的项目,这样调试起来会快很多。运行调试器后,可以看到控制台输出的内容:右箭头=》是ic.Log=XTrace.Log输出的日志。字典的使用:对于对象,需要把json全部取出来,转成对象,对于字典,直接取某个字段即可。队列由List结构实现。当上游数据过多,下游无法处理时,可以使用这个队列。上游数据发送到队列,然后下游慢慢消费。另一种应用,跨语言协同工作,比如用其他语言实现的程序将数据塞入队列,再由另一种语言进行消费处理。这种方法类似于MQ的概念。虽然有点low,但是也很好用。Set更常用于需要精确判断的去重功能。像我们每天有3000万单,这3000万单是可以重复的。这时候,我想统计订单总数。这时候直接按数据库分组是不可能的,因为数据库中有十几张表。这里有一个实践经验:取回物品,但取回前,网点并不知道自己有多少货。这时候我们做了一个功能,就是订单会发到我们公司。我们会构建一个time_sitekeyset,set本身有去重的功能,我们可以通过set.Count函数轻松统计数量。当物品被收集时,我们将在后台Lose中从集合中移除该物品。然后这组中还有出口尚未接受的作品。这时候通过Count就可以知道outlet今天有多少件没有接受了。在实际使用中,这个数字比较大,因为网点有几万个。Redis中的布隆过滤器,去重,面试的时候问的比较多。小经验分享:数据库中的非法时间处理:判断时间中的年份是否大于2000,小于2000则认为非法;习惯了大于小于等号,可以处理很多意想不到的数据;设置的时候最好指定过期时间,防止我们忘记删除一些需要删除的数据;尽量不要异步使用Redis,因为Redis本身延迟很小,大概100us-200us,另外一个是Redis本身是单线程的,异步任务切换的时间消耗比网络大;List用法:当物联网上传的数据比较大的时候,我们可以先把数据放在RedisList中,比如每秒10000条,然后批量取出,批量插入到数据库中。这时候需要设置key,可以prefix+time,可以移除处理过的List。2.压力测试接下来我们来看第四个例子。我们直接做压力测试吧。代码如下:运行结果如下图所示:测试是进行get、setremove、accumulation等操作。可以看到在我本机轻松达到了60万,多线程的时候甚至达到了百万以上。为什么它能获得如此高的Ops?给大家介绍一下:Bench会根据线程数分成多个组进行增删改查的压力测试;rand参数,是否随机生成key/value;batchsize,批量执行读写操作,使用GetAll/SetAll进行优化。3、NB在Redis中提升性能的功能。如果大家掌握了上面的操作,基本上就是对Redis的入门,然后进阶了。如果你能完全理解它,你几乎会比别人更好。GetAll()和SetAll()GetAll:比如我想得到十个key,这时候可以用getall。这时,Redis执行了一条命令。比如我要取10个key,用get就需要取10次,用getall就需要取1次。1次getall的时间是get的几倍左右,10次getall的时间是10倍。这笔账你应该能算出来吧?我们强烈推荐大家使用getall。setall和getall类似,都是批量设置K-V。setall和getall的性能很糟糕。官方公布的Ops只有10万左右。为什么我们的测试很容易达到50万甚至上百万?因为我们只是使用setall和getall。如果get、set超过两次,建议使用getall、setall。比如Redis管道Pipeline执行10条命令,就会打包成一个包,发到群里执行。这里的实现方式是以StartPipeline()开始,以StopPipeline()结束。中间的代码会以流水线的形式执行。这里推荐使用更强的利器,AutoPipeline自动流水线属性。当流水线操作达到一定数量时,会自动提交,默认为0。有了AutoPipeline,就不需要StartPipeline,StopPipeline指定了流水线的起点和终点。AddandReplaceAdd:如果Redis中没有这个Key则添加,有??则不添加,返回false;replace:有则替换,返回原值,否则不做任何操作。Add和Replace是实现Redis分布式锁的关键。3、Redis的使用技巧和经验分享在项目的Readme中,摘录如下:1、特点广泛应用于中通大数据实时计算。200多个Redis实例稳定工作一年多,每天处理近亿包数据,平均调用次数80亿次;低延迟,Get/Set操作平均耗时200~600us(包括往返网络通信);吞吐量大,内置连接池,最高1000并发;高性能,支持二进制序列化(默认json,json效率很低,转换成二进制性能会提高很多)。2、Redis经验分享在Linux上部署在多个实例上。实例数等于处理器数。每个实例的最大内存直接为机器的物理内存,避免单个实例的内存爆表(比如使用8核处理器,则Deploy8个实例)。根据keyhash(Crc16/Crc32)在多个实例上存储海量数据(10亿+),读写性能呈指数级增长。使用二进制序列化,而不是常见的Json序列化。合理设计每对Key的Value大小,包括但不限于使用批量获取。原理是控制每个网络包在1.4k字节左右,减少通信次数(实际体验几十k,几百k也没问题)。Redis客户端的Get/Set操作平均耗时200~600us(包括往返网络通信),以此作为评估网络环境和Redis客户端组件的参考(如果达不到,检查网络、序列化方法等)。使用Pipeline组合一批命令。Redis的主要性能瓶颈是序列化、网络带宽和内存大小,处理器在滥用时也会达到瓶颈。可以检查其他优化技术。以上经验来源于4T及以上空间300多个实例一年以上稳定工作经验,并按重要性排序,可根据场景需要酌情采用。3、缓存Redis的兄弟Redis实现了ICache接口,它的孪生兄弟MemoryCache,内存缓存,最大化吞吐量。强烈建议每个应用使用ICache接口编码设计,小数据使用MemoryCache;数据增加后(10万条),在不修改业务代码的情况下,使用Redis实现。4.部分问题解答这部分我们将谈谈在大数据中使用Redis的心得:Q1:一条数据如何设置多个key比较合理?A1:如果对性能要求不是很高,直接使用json序列化实体就可以了,不需要用字典来存储。Q2:队列和列表有什么区别?左进右出用列表好还是队列好?A2:队列其实是用列表来实现的,也是基于列表的封装。如果从左边进,从右边出,直接排队就可以了。Redis的List结构比较有意思。可以左进右出,也可以右进左出。所以它既可以实现链表结构,又可以实现队列,也可以实现栈。Q3:存储多个字段的类是否具有相同的性能?A3:大部分场景不会有偏差,大公司数据量大的场景可能会有偏差。Q4:大数据写入数据库后,比如数据达到1亿以上,能否分享一些统计分析和查询的经验?A4:把表和数据库分成1000万以内。Q5:为什么CPU会暴涨?A5:程序员最好的想法——CPU达到最佳,然后性能达到最佳,尽量不要浪费。我最讨厌的是——如果CPU小于***,性能就提不上去,说明代码有问题。Redis虽然人人都会用,但是我们平时可能不会有这样的大数据使用场景。希望这篇文章能给大家一些值得借鉴的经验。