Redis点滴
最近试验在产品中使用Redis来完成以前MongoDB做的一些工作,发现在大量消息采集的场景下(咱们这次不谈查询什么的),redis比mongoDB表现更好──这里主要是指编程更简便、逻辑更清晰。下面我举一些小例子说说Redis都为我们解决了什么问题,技术上下文关键字
最近试验在产品中使用Redis来完成以前MongoDB做的一些工作,发现在大量消息采集的场景下(咱们这次不谈查询什么的),redis比mongoDB表现更好──这里主要是指编程更简便、逻辑更清晰。下面我举一些小例子说说Redis都为我们解决了什么问题,技术上下文关键字:高并发、分布式。
插入与更新操作的无差别性
Redis的所有SET(包括MSET,HMSET)操作都是:存在则更新,不存在则插入,即insert if not exists。所以在编程的时候开发人员不需要关心所做的操作属于更新还是插入,减免了判断,因此也避免了判断操作可能带来的锁定。
MongoDB也有同样的操作,update操作的upsert参数调为True即可,不过经过测试,MongoDB为查询条件为了索引后使用update with upsert来代替insert操作,效率比光insert要低5倍以上,而redis的HMSET操作的效率要胜出。
GETSET的妙用
上一个经验虽说可以解决这条数据该“插入还是更新”的问题,但需要知道当前操作是否针对某数据的首次操作的需求还不少。例如我的程序会在不同时间接收到同一条消息的不同分片信息包,我需要在收到该消息的首个信息包(发送是无序的)时做些特殊处理。
早些时候的做法是为消息在MongoDB维护一个状态对象,有信息包来的时候就走“上锁->检查消息状态->根据状态决定做不做特殊操作->解锁” 这个流程,虽然同事已经把锁的粒度控制得非常细了,但有锁的程序遇上多实例部署就歇了。
Redis的GETSET是解决这个问题的终极武器,只需要把当前信息包的唯一标识对指定的状态属性进行一次GETSET操作,再判断返回值是否为空则知道是否首次操作。GETSET替我们把两次读写的操作封装成了原子操作,V5啊。
山寨版数据过期策略
我曾经想过要写服务器端的脚本来扩展redis,试图要拿到数据过期的事件,用来做一些回调来处理过期数据,但很快我发现这个不现实。于是我选择通过使用排序集合(SORTEDSET)来实现一个山寨的数据过期策略:需要定时过期的数据,统一添加到一个排序集合:ZADD expiringKey timestamp data。在这里我使用了时间值(毫秒为单位的长整型)作为数据的分数,那么很自然的,早期的数据总会排在集合前面;然后我写一个程序会定时地过来打理这些过期的数据就好了。
存储结构化数据
例如有“通讯录”这样的数据,包含有”name”,”city”,”gender”等8个属性,使用mongoDB保存就很简单,创建一个Document,设置属性后存储即可,而Redis本身并非Document型的DB而是Key Value DB,要存储这种数据,还得在Key上面花一点功夫:使用contact:id:name,contact:id:city,contact:id:gender之类的Key来存储其对应的值。当然,这只是使用redis存储结构化数据最原始的办法,更建议的办法是使用Hash存储,如 hmset contact:id name jeff contact xx@gmail.com gender male。相对set操作而言,hmset既节省了存储空间又提高了存储效率。
使用MongoDB来存储这些数据是小菜一碟,但鉴于第一点经验,我还是愿意使用Redis。
比较可惜的是,目前Redis的Hash存储仅支持字符类型的值,不支持其他数据结构,我非常期待它日后会支持其他数据结构,甚至支持Hash的嵌套。关于这点,@wuvist 同学认为十分有可能。
小结
上面这些Case都只是Redis牛刀小用,但实际上给程序带来的便利是非常明显的,最明显的就是可以把原来的程序上使用的锁都抛弃掉,甚至直接支持分布式运行和水平扩展了。
顺便在此小结一点高并发分布式应用程序编写的一些推荐的注意事项吧,当然这是我的个人偏好并结合了一些特定业务领域的性质:
1. 程序对资源最好是只读或只写,明确分工。不要在一个程序里同时对资源进行读写,除非是原子操作,如GETSET。
2. 写操作中,插入与更新最好是无差别的,避免程序对此进行行判断,破坏操作的原子性。
3. 更新过程中尽最不要对更新值和原值进行比较,还是关乎操作的原子性,如果真要进行比较,有两种方案供参考。
1). 更新时,为字段追加新数据,使用集合(如果是数值使用排序集合更好)来存储;比较的逻辑交给读取的程序处理。
2). 使用CAS,类似乐观锁,实现多进程数据安全控制。如果目标资源的服务器支持最佳。
4. 还是那一句,避免在程序里面使用锁。逼不得已就用分布式锁吧。
5. 多线程是万恶之源,要慎用,一条线程能把CPU跑满才是真牛,多核、扩容时可考虑多进程。
原文地址:Redis点滴, 感谢原作者分享。

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

Redis集群模式通过分片将Redis实例部署到多个服务器,提高可扩展性和可用性。搭建步骤如下:创建奇数个Redis实例,端口不同;创建3个sentinel实例,监控Redis实例并进行故障转移;配置sentinel配置文件,添加监控Redis实例信息和故障转移设置;配置Redis实例配置文件,启用集群模式并指定集群信息文件路径;创建nodes.conf文件,包含各Redis实例的信息;启动集群,执行create命令创建集群并指定副本数量;登录集群执行CLUSTER INFO命令验证集群状态;使

Redis 使用哈希表存储数据,支持字符串、列表、哈希表、集合和有序集合等数据结构。Redis 通过快照 (RDB) 和追加只写 (AOF) 机制持久化数据。Redis 使用主从复制来提高数据可用性。Redis 使用单线程事件循环处理连接和命令,保证数据原子性和一致性。Redis 为键设置过期时间,并使用 lazy 删除机制删除过期键。

要查看 Redis 中的所有键,共有三种方法:使用 KEYS 命令返回所有匹配指定模式的键;使用 SCAN 命令迭代键并返回一组键;使用 INFO 命令获取键的总数。

解决redis-server找不到问题的步骤:检查安装,确保已正确安装Redis;设置环境变量REDIS_HOST和REDIS_PORT;启动Redis服务器redis-server;检查服务器是否运行redis-cli ping。

Redis 有序集合(ZSet)用于存储有序元素集合,并按关联分数进行排序。ZSet 的用法步骤包括:1. 创建 ZSet;2. 添加成员;3. 获取成员分数;4. 获取排名;5. 获取排名范围的成员;6. 删除成员;7. 获取元素个数;8. 获取分数范围内的成员个数。

要查看 Redis 版本号,可以使用以下三种方法:(1) 输入 INFO 命令,(2) 使用 --version 选项启动服务器,(3) 查看配置文件。

Redis 计数器提供了存储和操作计数器的数据结构。具体步骤包括:创建计数器:使用 INCR 命令向现有键添加 1。获取计数器值:使用 GET 命令获取当前值。递增计数器:使用 INCRBY 命令,后面跟要递增的金额。递减计数器:使用 DECR 或 DECRBY 命令,递减 1 或指定金额。重置计数器:使用 SET 命令将其值设置为 0。此外,计数器还可以用于限制速率、会话跟踪和创建投票系统。

Redis采用五种策略确保键的唯一性:1. 名称空间分隔;2. HASH数据结构;3. SET数据结构;4. 字符串键的特殊字符;5. Lua脚本验证。具体策略的选择取决于数据组织、性能和扩展性需求。
