0%

Redis-踩坑记录

记录一些平时遇到的Redis的坑…

1 Bitmap使用踩坑

1.1 引入

最近在做RTA功能,实现精准投放,主要流程是媒体平台将用户加密设备号下发给广告主,广告主根据自有数据,对设备号进行过滤,并返回投放竞价信息, 实现个性化用户筛选(是否参与竞价)及流量实时优选(根据返回信息实现优选).

1.2 问题

  • 媒体平台对RTA接口响应要求高(例如,广点通限制请求响应时间在60ms之内),其中网络耗时已经高达40到50ms,因此,对于我们提供的RTA接口的逻辑处理时间必须限制在10到15ms之内.
  • QPS高达15W,若直接丛数据库查询,将导致数据库实例单机负载高,查询速度降低.
  • 现在用户设备号数量约为2.3亿.

1.3 解决方案

考虑其响应时间限制,使用Redis存储的方案,减少直接的DB访问,提高响应速度。

    • 方案一:使用bitmap方式进行存储
    • 方案二:将设备信息通过key-value方式存储。
1.3.1 使用bitmap方式进行存储

思路: bitmap中bit映射被限制在512M之内,所以最大为32位,即offset最大为‭2^(32)-1 (即4294967295)‬,对于2.3亿多的数据直接通过一个key就能存储。

媒体平台推送过来的设备号是md5加密后的imei或者idfa,是128位(16字节)的散列值。而offset应该为整数,因此需将设备号转换为唯一对应的整型数值。但查询了一堆资料均没有找到方法直接转换。

考虑使用CRC32方式,对设备号进行转换,然后将crc32的结果作为offset,为了减少冲突,将设备号的最后3位拼接在key上,即key的数量为4096个。

问题来了,crc32的结果非常大,导致一个key的内存占用高达几百兆,DBA分配的测试集群一共20G,只写入了73个key,内存就满了。。。

后续是将设备号的最后1位拼接在key上,即key的数量为16个,这样能保证内存占用少(16个key对应的内存占用最大为:8G)。

但是新的问题又来了,由于key的数量减少了,可能导致所有的key都被哈希到一个分片,且还是无法保证其唯一性。另外crc32转换为数字方式仍然有冲突的风险。

1.3.2 使用key-value的方式

之前因为2亿的数据,担心内存占用太大,但在后续测试过程中,发现10000条数据写入占用1.11M,即2亿占用内存大约为20多G,是在能接收的范围,且数据可靠。

1.4 总结:

bitmap的offset需要数字方式或者能转换为数字形式,且offset应该尽可能小!!!!

2 Redis 热键访问

2.1 引入

也是处理RTA逻辑,在公司内部处理逻辑中,需要根据用户设备命中的策略,返回相应的排除竞价的账户id.

2.2 问题

由于QPS过高,直接通过查询数据库,对数据库造成的压力大,DBA同学开始找麻烦了…

2.3 解决

在数据库层之前增加一层缓存层,优先从缓存中获取数据,若数据不存在,再查询数据库,并写入缓存.从而减少数据库压力.账户信息属于变动不频繁的数据, 设置1小时的过期时间,期间的数据不一致,尚且可以接收.

2.4 踩坑

目前公司对接了多个渠道的RTA,例如,头条的穿山甲,腾讯的广点通,华为的Ads等等,每个渠道的账户均不同,因此将账户id写入缓存时是以渠道为key,即一个渠道对应一个key.每个请求过来时均会获取该渠道的账户信息.

此时,在高QPS的下,Redis key分布不均匀,造成一个实例负载非常高,读缓存时长增加,整体响应时间增加,造成大量请求超时的情况.

2.4.1 解决

多设置几个key,使redis分布均匀…

参考资料

一看就懂系列之 详解redis的bitmap在亿级项目中的应用

精准营销系列:RTA投放