首页 > 编程知识 正文

redis scan 效率太慢,redis默认过期策略

时间:2023-05-03 10:45:20 阅读:18715 作者:1572

另一方面,通过发现问题jedis向sortedset添加成员,并且设定双精度型分数时,精度存在问题

测试代码如下。

@ testpublicvoidzadd ((jedis.zadd ),13.36,mb1 ); 只要使用jedis的api取得score就一切正常

@ testpublicvoidzscore ((system.out.println ) Jedis.zscore ) ) test:CLI )、(mb1 ) ); }输出结果:

13.36但是,如果用redis-cli去查的时候,精度有问题:

181.137.128.153:7002

181.137.128.15:7002 zrangetest : CLI0-1with scores

1 )“mb1”

2 ) " 13.359999999999999 "

181.137.128.153:7002

二、源代码搜索如果不想看源代码,可以跳过这里直接看第四节的结论哦~

1、zadd

首先,看看是否是数据插入时的精度问题

@ testpublicvoidzadd ((jedis.zadd ),13.36,mb1 ); 单击zadd方法

@ overridepubliclongzadd (final string key,final double score, final String member ) returnnewjedisclustercommandlong ) conneccecand max attempts (@ overridepubliclongexecute (je disconection }.run(key ); 继续单击zadd方法

publiclongzadd(finalstringkey,final double score,final String member ) { checkIsInMultiOrPipeline; client.zadd(key,score,member ); return client.getIntegerReply (; 继续单击zadd方法

公共void zadd (final string key,final double score,final String member ) zadd (safe encoder.encode ) key,score,safeeer zadd

publicvoidzadd(finalbyte[]key,final double score,final byte[] member )//将数据转换为byte[]后,单击Redisserversendcommand

好的~

2、zscore

接下来,让我们看看从redis server检索数据时是否存在精度问题

@ testpublicvoidzscore ((system.out.println ) Jedis.zscore ) ) test:CLI )、(mb1 ) ); zscore (单击方法

@ overridepublicdoublezscore (final string key,final String member ) returnnewjedisclustercommandouble ) connectionhandler, max attempts (@ overridepublicdoubleexecute (je disconnection ) ) returnconnection.zscore ) key,member ); }.run(key ); zscore (单击方法

publicdoublezscore (final string key,final String member ) { checkIsInMultiOrPipeline ); client.zscore(key,member ); //该方法先返回字符串类型的数据finalstringscore=client.getbulkreply (; //以及双精度型返回(score!=null? 新双精度(score ) : null ); 单击getBulkReply ()

方法

public String getBulkReply() { //server 返回的是 byte[] final byte[] result = getBinaryBulkReply(); if (null != result) { return SafeEncoder.encode(result); } else { return null; }}

!!!
发现 server 返回给 client 的就是精度有问题的!震惊!

三、再度探究

细心的同学可能会发现,诶,之前用 jedis api 获取时都是没有精度问题的,怎么会出现这种情况呢?
我们可以运行下面的程序看看就知道了:

@Testpublic void zdouble(){ String score = "13.359999999999999"; System.out.println(new Double(score));}

输出结果是:

13.36

值是正确但问题是,redis server居然给 client 返回的是精度有问题的!!

于是我猜测是 Redis 内部精度把控有问题。
请看下面的验证(redis-cli):

181.137.128.153:7002> keys *
(empty list or set)
181.137.128.153:7002> zadd test:key 13.36 mb1
(integer) 1
181.137.128.153:7002> zrange test:key 0 -1 WITHSCORES
1) “mb1”
2) “13.359999999999999”
181.137.128.153:7002>
181.137.128.153:7002>
181.137.128.153:7002> zadd test:key 13.35 mb2
(integer) 1
181.137.128.153:7002> zrange test:key 0 -1 WITHSCORES
1) “mb2”
2) “13.35”
3) “mb1”
4) “13.359999999999999”
181.137.128.153:7002>
181.137.128.153:7002> zscore test:key mb1
“13.359999999999999”
181.137.128.153:7002>
181.137.128.153:7002>

发现,就是 Redis 内部精度的问题!!

下面我们来看一下 redis 中自动帮我们累加 score 的 zincrby() 方法会不会也有精度问题:

public static void main(String[] args) throws Exception { JedisCluster jedis = JedisClusterUtil.getJedisCluster(); //每次添加的值 double addValue = 13.03; String key = "test:cli:1"; String member = "mb1"; //score设置为 405887.59 jedis.zadd(key, 405887.59, member); /** * 对 member 成员不断累加值,累计后获得最新值,如果前后的差值不等于 addValue 则退出 */ while (true){ Double k1 = jedis.zscore(key, member); //让程序自动帮我们累加 jedis.zincrby(key, addValue, member); Double k2 = jedis.zscore(key, member); /** * 如果redis api内部帮我们累加的值不等于 addValue 则退出 * 注意用 BigDecimal进行操作 */ if (cha(k2, k1) != addValue){ System.out.println("k1 = " + k1); System.out.println("k2 = " + k2); break; } } } /** * 求差值 * 注意,用BigDecimal类来进行double的运算 * @param d1 * @param d2 * @return d1 - d2 */ public static Double cha(double d1, double d2){ Double cha = new BigDecimal(String.valueOf(d1)).subtract(new BigDecimal(String.valueOf(d2))).doubleValue(); System.out.println("cha = "+cha); return cha; }}

输出为:

cha = 13.03000000005k1 = 405887.59k2 = 405900.62000000005

发现,如果让程序内部自动帮我们累加 Double,那精度也会出现问题

四、解决办法 建议 将 Double 类型转换成 Long 类型后再保存到 Redis,然后获取值时再通过 BigDecimal 将值乘以 0.01 : 这样不管是 zadd 或者是 zincrby,都没有精度问题如果硬是要用 Double 类型的话,不要用 redis 提供的 increase 方法,有精度问题如果不把 Double 转换成 Long 类型的话,那么我们自己用BigDecimal类来操作 score,然后调用 zadd() 方法。

注:上面的代码都是基于 redis 的集群模式来测试的,且 jedis 的版本是2.9.0。关于 jedis 的获取可以查看我的另一篇文章哈~

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。