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脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++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 数据:使用 FLUSHALL 命令清除所有键值。使用 FLUSHDB 命令清除当前选定数据库的键值。使用 SELECT 切换数据库,再使用 FLUSHDB 清除多个数据库。使用 DEL 命令删除特定键。使用 redis-cli 工具清空数据。

要从 Redis 读取队列,需要获取队列名称、使用 LPOP 命令读取元素,并处理空队列。具体步骤如下:获取队列名称:以 "queue:" 前缀命名,如 "queue:my-queue"。使用 LPOP 命令:从队列头部弹出元素并返回其值,如 LPOP queue:my-queue。处理空队列:如果队列为空,LPOP 返回 nil,可先检查队列是否存在再读取元素。

在CentOS系统上,您可以通过修改Redis配置文件或使用Redis命令来限制Lua脚本的执行时间,从而防止恶意脚本占用过多资源。方法一:修改Redis配置文件定位Redis配置文件:Redis配置文件通常位于/etc/redis/redis.conf。编辑配置文件:使用文本编辑器(例如vi或nano)打开配置文件:sudovi/etc/redis/redis.conf设置Lua脚本执行时间限制:在配置文件中添加或修改以下行,设置Lua脚本的最大执行时间(单位:毫秒)

使用 Redis 命令行工具 (redis-cli) 可通过以下步骤管理和操作 Redis:连接到服务器,指定地址和端口。使用命令名称和参数向服务器发送命令。使用 HELP 命令查看特定命令的帮助信息。使用 QUIT 命令退出命令行工具。

Redis计数器是一种使用Redis键值对存储来实现计数操作的机制,包含以下步骤:创建计数器键、增加计数、减少计数、重置计数和获取计数。Redis计数器的优势包括速度快、高并发、持久性和简单易用。它可用于用户访问计数、实时指标跟踪、游戏分数和排名以及订单处理计数等场景。

Redis数据过期策略有两种:定期删除:定期扫描删除过期键,可通过 expired-time-cap-remove-count、expired-time-cap-remove-delay 参数设置。惰性删除:仅在读取或写入键时检查删除过期键,可通过 lazyfree-lazy-eviction、lazyfree-lazy-expire、lazyfree-lazy-user-del 参数设置。

在Debian系统中,readdir系统调用用于读取目录内容。如果其性能表现不佳,可尝试以下优化策略:精简目录文件数量:尽可能将大型目录拆分成多个小型目录,降低每次readdir调用处理的项目数量。启用目录内容缓存:构建缓存机制,定期或在目录内容变更时更新缓存,减少对readdir的频繁调用。内存缓存(如Memcached或Redis)或本地缓存(如文件或数据库)均可考虑。采用高效数据结构:如果自行实现目录遍历,选择更高效的数据结构(例如哈希表而非线性搜索)存储和访问目录信
