最近因为做Chatbot项目需要对于NoSQL数据库进行研究,调研范围包括MongoDB和Redis。本文将介绍Redis在Windows环境的安装及如何利用python来操作Redis数据库。
Redis基础
redis是Key Value nosql数据库,数据存储在内存中,单进程,自己实现了一套异步事件处理,虽然单进程但是数据库处理很快,异步持久化。
Redis有5种数据类型:
- string,最基本的数据类型,也是其他四种数据类型的基础,能存储任何形式的字符创。适用:存储信息对象序列化JSON格式。get/set操作
- hash,哈希类型是一个字符串类型的字段和字段值的映射表,将一个对象存成hash类型占用更少的内存,并且可以更方便的存取整个对象。适用:经常被并发请求的小数据查询,如:最近五日的超高返商品数据,存储在Hash中,field=商品ID,value=商品信息(对象序列化JSON格式)。hmset/hgetall操作。
- list,链表类型可以存储一个有序的字符串列表,用链表类型的LPUSH和LPOP或者RPUSH和RPOP实现栈的功能,用LPUSH和RPOP或者RPUSH和LPOP实现队列的功能。适用:作为信息队列使用,不断的Lpush数据到List中,rpop数据出来入库,或者处理。列表的最大长度为 232 - 1 个元素(4294967295,每个列表的元素超过四十亿)。lpush list_name list_element/ lrange list_name start_index end_index
- set,集合类型。集合元素是唯一的,无序的。集合间可以进行交并差操作。sadd/smembers
- zset,有序集合类型,在set的基础上多了一个有序。适用:搜索关键字排名。zadd/zrangebyscore
Redis优点
- 异常快速 : Redis是非常快的,每秒可以执行大约110000设置操作,81000个/每秒的读取操作。
- 支持丰富的数据类型 : Redis支持最大多数开发人员已经知道如列表,集合,可排序集合,哈希等数据类型。这使得在应用中很容易解决的各种问题,因为我们知道哪些问题处理使用哪种数据类型更好解决。
- 支持pub/sub消息订阅机制,可以用来进行消息订阅与通知。
- 支持持久化操作,可以进行aof及rdb数据持久化到磁盘,从而进行数据备份或数据恢复等操作,较好的防止数据丢失的手段。
*操作都是原子的 : 所有 Redis 的操作都是原子,从而确保当两个客户同时访问 Redis 服务器得到的是更新后的值(最新值)。
Redis缺点
- Redis只能使用单线程,性能受限于CPU性能,故单实例CPU最高才可能达到5-6wQPS每秒
- Redis在string类型上会消耗较多内存,可以使用dict(hash表)压缩存储以降低内存耗用。
Redis注意事项:
-
Redis的键命名必须按照"object-type:id:field(表:主键:列)"的方式
具体的命名规范包括:1)内存数据库,键名长度影响有限内存空间,所以命名应该控制长度,简短易懂;2)大小写规范;3)根据业务命名,相同业务统一的Key前缀
数据库的主要功能是储存数据,但是对于开发者来说,因为应用程序需求或者数据使用方法的改变,忽略存储在数据库中的某些数据是非常正常的,在Redis中同样如此。你可能忽视期满某些键,也可能因为应用程序的某个模块弃用而忘掉这些数据。无论哪种情况,Redis都存储了一些不再使用的数据,平白无故的占用了一些空间。Redis的弱结构数据模式让集中储存的内容很难被弄清,除非你为键使用一套非常成熟的命名法则。使用合适的命名方法会简化你的数据库管理,当你通过你的应用程序或者服务做键的命名空间时(通常情况下是使用冒号来划分键名),你就可以在数据迁移、转换或者删除时轻松的识别。Redis另一个常见用例是作为热数据项作的第二数据存储,大部分的数据被保存在其他的数据库中,比如PostgreSQL或MongoDB。在这些用例中,当数据从主存储移除时,开发者经常会忘记删除Redis中对应的数据。这种存在跨数据存储的情况下,通常需要做级联删除,这种情况下,可以通过在Redis配置保存特定数据项的所有识别符来实现,从而保证数据在主数据库被删除后,系统会调用一个清理程序来删除所有相关副本和信息。 -
使用合适的数据结构
不管是内存使用或者是性能,有的时候数据结构将产生很大的影响,下面是一些可以参考的最佳实践:
取代将数据存储为数千(或者数百万)独立的字符串,可以考虑使用哈希数据结构将相关数据进行分组。哈希表是非常有效率的,并且可以减少你的内存使用;同时,哈希还更有益于细节抽象和代码可读。合适时候,使用list代替set。如果你不需要使用set特性,List在使用更少内存的情况下可以提供比set更快的速度。Sorted sets是最昂贵的数据结构,不管是内存消耗还是基本操作的复杂性。如果你只是需要一个查询记录的途径,并不在意排序这样的属性,那么轻建议使用哈希表。文章Redis键值设计以实际的业务需求为例介绍如何使用Redis的数据结构,可以作为参考。
Redis中一个经常被忽视的功能就是bitmaps或者bitsets(V2.2之后)。Bitsets允许你在Redis值上执行多个bit-level操作,比如一些轻量级的分析。 -
控制Redis的内存
Redis内存不足的原因包括三个方面:1)数据不断累加,无效数据未清理,缓存未设置过期时间;2)存储数据中包含未使用到字段,整个对象序列化到redis中;3)冷数据,或者根本不会再去使用的无效数据没有清理。
解决方法:1)数据区分无效时间,设置过期时间,使无效数据过期;(如:通过日期后缀命名Key);2)区分冷数据,清理掉冷数据;缓存数据从简,redis key命名从简,数据字段命名从简,无效字段不添加在缓存中。
Redis和MongoDB的区别:
- Redis不适用于长期累加的数据(比如大数据),这些数据应该考虑hbase或者mongodb
- Redis的读写速度比MongoDB表现好,尤其是数据集较大的情况下。
- MongoDB的特点:(1)面向文档(2)高性能(3)高可用(4)易扩展(5)丰富的查询语言,mongoDB适合大数据量的存储,依赖操作系统VM做内存管理,吃内存也比较厉害,服务不要和别的服务在一起。MongoDB:主要解决海量数据的访问效率问题,Redis:数据量较小的更性能操作和运算上。
Windows安装Redis
因为开发环境在Windows下,因此还是选择在windwos环境下安装Redis。Redis官方并没有给出官网安装包,但有一个开源项目时跟进的,可以在其Github主页 上下载对应的安装包。
我下载的是3.0.53的包,新建目录“c:\redis”,解压缩安装包放在这个目录中。
然后输入命令就可以看到启动界面了:
c:\redis>redis-server.exe redis.windows.conf
为了避免避免反复输入命令麻烦,可以直接注册成为windows服务:
c:\redis>redis-server --service-install redis.windows.conf --loglevel verbose
c:\redis>net start Redis
安装完毕,再下载安装Redis Desktop Manager压压惊。
python操作Redis
python操作Redis的方法非常多,也很好用,建议大家按照自己的需要查API进行使用。这里推荐一些教程:
下面我写了一个基于redis的封装接口,方便项目调用。
from __future__ import division, absolute_import
from myutils import configs, const, const_values
from myutils.check import check_func
import redis
import types
class RedisHelper(object):
__classname = "RedisHelper"
@check_func(__file__, __classname)
def __init__(self, **kwargs):
"""
这里做了一个外壳来包装redis,好处:
1.提供多重配置参数的输入,包括配置文件config读取等
2.方便Singleton的调用。这样速度可以保证内存永远有一个redis接口提供调用,更快。
:param kwargs:
"""
if "filename" in kwargs:
with configs.ConfigWrapper(kwargs.get("filename"), "read") as config:
sections = config.get_sections()
if kwargs.get("section", "NOTHING FOUND") not in sections:
raise Exception("Section not found: %s" % kwargs.get("section"))
para_dict = config.get_option_dict(kwargs.get("section"))
else:
para_dict = kwargs
_host="localhost" if "host" not in para_dict else para_dict.get("host")
_port = 6379 if "port" not in para_dict else int(para_dict.get("port"))
_db = 0 if "database" not in para_dict else int(para_dict.get("database"))
_pw = None if "password" not in para_dict else para_dict.get("password")
self.__cursor=redis.StrictRedis(host=_host,port=_port,db=_db,password=_pw)
@check_func(__file__,__classname)
def redis(self):
"""
返回reids接口
:return:
"""
return self.__cursor
@check_func(__file__, __classname)
def close(self):
"""
关闭,其实没有什么效果,redis本身支持线程池调度,连接的启动关闭有线程池管理,python接口无需关心。
The connection_pool object has a disconnect method to force
an immediate disconnect of all connections in the pool if necessary
:return:
"""
del self.__cursor # 删除引用,等待垃圾回收
网友评论