Redis使用和部分源码剖析以及Django缓存和redis的关系
0.特点:
a.持久化
b.单进程、单线程
c.5大数据类型
d.用于操作内存的软件。
e.虽然是缓存数据库但是可以做持久化的工作
MySQL是一个软件,帮助开发者对一台机器的硬盘进行操作。
redis是一个软件, 帮助开发者对一台机器的内存进行操作。
1.使用redis.那么现在我的云服务器上安装了redis,并且启动:
启动以后会看到如下的界面:
这里服务器已经启动。
2.redis配置文件初识:
配置文件路径:cd /etc/redis/redis.conf
如果出现redis下次无法启动的问题,找到该进程,关闭即可重新使用redis。
lsof -i:6379
kill pid
root@iZbp17qwke8fau3qzwo15lZ:~# ps -ef |grep redis
redis 4625 1 0 Oct20 ? 00:01:24 /usr/bin/redis-server 0.0.0.0:6379
root 5761 1 0 Oct21 ? 00:00:48 redis-server *:6379
root 6526 6502 0 09:22 pts/1 00:00:00 grep --color=auto redis
root@iZbp17qwke8fau3qzwo15lZ:~# kill -9 4625
3.下面就是使用python连接到redis.
首先
pip3 install redis
在文件中:
import redis conn=redis.Redis(host="47.99.191.149",port=6379,password='xxxxx') #链接到redis
conn.set("x1",'alex') #给redis设置一个值 val=conn.get('x1') #获取x1对应的值
print(val) #alex
第二种方式:
import redis
#推荐使用连接池,链接不断开,不用长期connect
pool=redis.ConnectionPool(host="47.99.191.149",port=6379,password='xxxx',max_connections=1000)
conn=redis.Redis(connection_pool=pool)
conn.set('foo','Bar')
这种都不好,最后墙裂推荐使用单例模式来使用链接池!
1.创建一个单独的文件
import redis
pool = redis.ConnectionPool(host="47.99.191.149", port=6379, password='xxxxx', max_connections=1000)
2.在下面文件中导入这个,就是一个天然的单例连接池。(这也是提升redis性能的一个点)
import redis
from redis_poll import pool
# 创建连接池
while True:
key=input("请输入key:")
val=input("请输入val:")
#去连接池中获取链接
conn = redis.Redis(connection_pool=pool)
#设置值
conn.set(key, val)
连接池的源码分析:
使用连接池。不会夯住,因为使用了IO多路复用
while True:
r,w,e=select.select([sk,sk,sk])
一直在监测
监测到某个sk发来消息,然后处理完返回
三个都来,因为redis是单线程单进程,一个个的来,不用担心效率,内存操作很快。 源码中的连接池这么做!
在set的过程中建立socket对象,发了一个命令过去,发完把这connection从in_use_connection移除,
然后放到可用列表中 self.avaliable_connections.append()进去。
等下次有人想用的时候,直接pop一下把这个对象拿出来继续用。
本质:
本质就是维护一个已经和服务端链接成功的socket.以后再次发送数据直接获取socket,直接send数据,节省了开支,
这就是为什么使用连接池速度快的原因。
最后补充一个小点:
mysql端口号:3306
redis端口 :6379
接着昨天的内容继续写:
首先介绍的就是redis的五大数据类型:
redis ={
k1:'', #字符串
k2:[1,2,3,4,4,2,1], #列表
k3:{1,2,3,4}, #集合
k4:{name:123,age:666},#字典
k5:{('alex',60),('eva',80),('yuan',70)} #有序集合
}
操作字典:
import redis
pool=redis.ConnectionPool(host='47.99.191.149',port=6379,password="cyy520",max_connections=1000)
conn=redis.Redis(connection_pool=pool) #字典操作:
conn.hset('k4','username','alex')
conn.hset('k4','age',18)
'''
上面的设置相当于下面这种结构
redis={
k4:{
username:alex,
age:18
}
}
'''
val=conn.hget('k4','username') #获取字典内username的值
print(val) #b'alex'
vals=conn.hgetall('k4') #获取字典内所有的键值
print(vals) #{b'username': b'alex', b'age': b'18'}
第二种多种设置方式:
conn.hmset('k5',{'username': 'alex', 'age': ''}) #直接给k5设置键值对,不用像上面一个个的设置
val2=conn.hmget('k5','username','age') #获取多个值。
print(val2) #[b'alex', b'19']
计数器:
原来的数据都写在数据库,每次做更新压力会大。现在不写在数据库,这一天都在redis里写,每天0点只往数据库更新一次,减少数据库的压力。
#计数器:
print(conn.hget('k4','age')) #b'18'
conn.hincrby('k4','age',amount=1) #每次增加1,amount为负时则自减
print(conn.hget('k4','age')) #b'19'
现在抛出了一个问题:
#如果reids的k4对应的字典中假设有1000W条数据,请打印所有的数据 # result=conn.hgetall('k4')
# print(result) #不可取,数据太多内存无法承受,爆栈
如果数据非常的多怎么把呢?通过hgetall取出全部的话,瞬间内存爆栈!
推荐通过下面方法取:
ret=conn.hscan_iter('k4',count=100) #100个100个的取
for item in ret:
print(item)
这个就是做成一个生成器,一个一个的迭代取。
源码中是这么写的:
def hscan_iter(self, name, match=None, count=None):
"""
Make an iterator using the HSCAN command so that the client doesn't
need to remember the cursor position. ``match`` allows for filtering the keys by pattern ``count`` allows for hint the minimum number of returns
"""
cursor = ''
while cursor != 0:
#起始位置:0
cursor, data = self.hscan(name, cursor=cursor,
match=match, count=count)
#corsor=100,data=数据
for item in data.items():
yield item #在此yield住
注意事项:
-拿到的数据是bytes.
-redis操作时,只有第一层的value支持:list,dict...
redis={
k3:[1,2,3], #只支持第一层的列表
k4:{
id:1,
title:"xxx",
price_list:[
{id:1,title:"xx"},
{id:2,title:"oo"},
{id:3,title:"qq"},
{id:4,title:"aa"},
]
#把列表json.dumps一下变成字符串
#取回来的时候bytes转成字符串,然后json.loads回来即可
}
}
Redis操作列表:
1.列表左插入
import redis
conn=redis.Redis(host="47.99.191.149",port=,password='cyy520') #列表左插入
# conn.lpush('k1',)
# conn.lpush('k1',)
2.列表右插入
#列表右插入
# conn.rpush('k1',33)
3.左获取
# 左获取
# val=conn.lpop('k1')
# print(val)
# val=conn.blpop('k1',timeout=3)
# print(val) #去取k1的数据,没有数据就夯住,可以加超时时间,过时返回None
4.右获取
#右获取
# val=conn.rpop('k1')
# print(val)
# val=conn.brpop('k1',timeout=3)
# print(val) #去取k1的数据,没有数据就夯住,可以加超时时间,过时返回None
这里在以前业务中使用到这里的一个点:
'''
在这里把爬虫的URL放到一个队列中,爬虫每次去取URL爬取,我们在这边往里面放地址,
放到redis,使用分布式爬取,2台机器共享一个队列,然后每次都brpop一下。
'''
最后就是redis的其他类型都有上面提到的生成器逐步取数据,只有列表没有提供方法,那么需要我们自己来用生成器配合看过源码来照猫画虎做一个。
#通过yield创造一个生成器,一点点的获取数据,灵感源于字典生成器源码
def list_iter(key,count=2):
index=0
while True:
data_list=conn.lrange(key, index, index+count-1)
if not data_list:
return
index+=count for item in data_list:
yield item
利用这个方法就可以通过调用List_iter方法逐步取数据了。
for item in list_iter('k1',count=3):
print(item)
Redis支持事务操作:
import redis
'''
redis={
k1:[1,2,3,4,5]
}
''' conn=redis.Redis(host="47.99.191.149",port=6379,password='cyy520') pipe=conn.pipeline(transaction=True) #创建一个pipe,事务为True
pipe.multi() pipe.set('k2',123)
pipe.hset('k3','n1',666)
pipe.lpush('k4','oldboy') pipe.execute() #一次发送三个命令,要成功都成功,要失败都失败。
4.Django使用redis
1.手动操作redis
想要在django程序中使用redis需要先安装一个模块:
pip3 install django-redis
然后在django的配置文件中设置一下。
#redis配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://47.99.191.149:6379", #redis服务器地址
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100}, #最大连接池100
"PASSWORD": "cyy520",
}
}
}
这样在视图中就可以导入使用redis了。
import redis
from django.shortcuts import render,HttpResponse
from django_redis import get_redis_connection #导入连接池 def index(request):
conn=get_redis_connection('default') #拿到defalut这个redis连接池
conn.set("name","egon") #设置值
return HttpResponse("设置成功!") def order(request):
conn=get_redis_connection('default')
name=conn.get("name")
return HttpResponse(name) #返回值
这样访问order就可以拿到这个对应的值,egon.
2.全站缓存
'django.middleware.cache.UpdateCacheMiddleware' #最上面
...其他中间件
'django.middleware.cache.FetchFromCacheMiddleware' #最下面
这样全站都缓存上了。
3.视图缓存
只给单视图缓存,把刚才的中间件注释掉。
from django.views.decorators.cache import cache_page @cache_page(60*15) #60为秒
def index(request):
ctime=str(time.time())
return HttpResponse(ctime)
4.局部缓存
应用场景。比如抢购界面的商品简介等等不需要一直加载,可以做缓存,而剩余个数需要实时刷新。
{% load cache %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>商品剩余个数</h1> {% cache 10 缓存key %}
<div>商品简介</div>
{% endcache %} </body>
</html>v
1.首先{% load cache %}
2.然后给需要缓存的地方加上
{% cache 10 缓存key %}
<div>商品简介</div>
{% endcache %}
这样这部分东西就会缓存,cache后面的是失效时间,10s, 后面是在redis里面放的缓存key,下面div里面的是key对应的值。
最后补充一点就是rest-framework的访问频率限制就是放在缓存系统中:
源码:
from rest_framework.throttling import SimpleRateThrottle
这里的cache=default_cache
class SimpleRateThrottle(BaseThrottle):
"""
A simple cache implementation, that only requires `.get_cache_key()`
to be overridden. The rate (requests / seconds) is set by a `rate` attribute on the View
class. The attribute is a string of the form 'number_of_requests/period'. Period should be one of: ('s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day') Previous request information used for throttling is stored in the cache.
"""
cache = default_cache
timer = time.time
cache_format = 'throttle_%(scope)s_%(ident)s'
scope = None
THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES
点进来发现
cache = DefaultCacheProxy()
这个类就是下面的。
class DefaultCacheProxy:
"""
Proxy access to the default Cache object's attributes. This allows the legacy `cache` object to be thread-safe using the new
``caches`` API.
"""
def __getattr__(self, name):
return getattr(caches[DEFAULT_CACHE_ALIAS], name) def __setattr__(self, name, value):
return setattr(caches[DEFAULT_CACHE_ALIAS], name, value) def __delattr__(self, name):
return delattr(caches[DEFAULT_CACHE_ALIAS], name) def __contains__(self, key):
return key in caches[DEFAULT_CACHE_ALIAS] def __eq__(self, other):
return caches[DEFAULT_CACHE_ALIAS] == other
Redis使用和部分源码剖析以及Django缓存和redis的关系的更多相关文章
- 跨站请求伪造(csrf),django的settings源码剖析,django的auth模块
目录 一.跨站请求伪造(csrf) 1. 什么是csrf 2. 钓鱼网站原理 3. 如何解决csrf (1)思路: (2)实现方法 (3)实现的具体代码 3. csrf相关的装饰器 (1)csrf_p ...
- Django对中间件的调用思想、csrf中间件详细介绍、Django settings源码剖析、Django的Auth模块
目录 使用Django对中间件的调用思想完成自己的功能 功能要求 importlib模块介绍 功能的实现 csrf中间件详细介绍 跨站请求伪造 Django csrf中间件 form表单 ajax c ...
- 豌豆夹Redis解决方案Codis源码剖析:Dashboard
豌豆夹Redis解决方案Codis源码剖析:Dashboard 1.不只是Dashboard 虽然名字叫Dashboard,但它在Codis中的作用却不可小觑.它不仅仅是Dashboard管理页面,更 ...
- 豌豆夹Redis解决方案Codis源码剖析:Proxy代理
豌豆夹Redis解决方案Codis源码剖析:Proxy代理 1.预备知识 1.1 Codis Codis就不详细说了,摘抄一下GitHub上的一些项目描述: Codis is a proxy base ...
- Redis源码剖析--源码结构解析
请持续关注我的个人博客:https://zcheng.ren 找工作那会儿,看了黄建宏老师的<Redis设计与实现>,对redis的部分实现有了一个简明的认识.在面试过程中,redis确实 ...
- Redis源码剖析
Redis源码剖析和注释(一)---链表结构 Redis源码剖析和注释(二)--- 简单动态字符串 Redis源码剖析和注释(三)--- Redis 字典结构 Redis源码剖析和注释(四)--- 跳 ...
- Jedis cluster集群初始化源码剖析
Jedis cluster集群初始化源码剖析 环境 jar版本: spring-data-redis-1.8.4-RELEASE.jar.jedis-2.9.0.jar 测试环境: Redis 3.2 ...
- 【Redis】事件驱动框架源码分析(多线程)
IO线程初始化 Redis在6.0版本中引入了多线程,提高IO请求处理效率. 在Redis Server启动函数main(server.c文件)中初始化服务之后,又调用了InitServerLast函 ...
- 【Redis】事件驱动框架源码分析
aeEventLoop初始化 在server.c文件的initServer函数中,对aeEventLoop进行了初始化: 调用aeCreateEventLoop函数创建aeEventLoop结构体,对 ...
随机推荐
- 一次线上问题引发的对于C#中相等判断的思考
线上报来一个问题,说用户的数据丢失了.开发经过紧张的调查.终于找到了原因. if (newData.GetValue(rowIndex) == oldData.GetValue(rowIndex)) ...
- 数据挖掘---Matplotib的学习
什么是matplotlib mat - matrix 矩阵 二维数据 - 二维图表 plot - 画图 lib - libra ...
- LeetCode算法题-Valid Anagram(Java实现)
这是悦乐书的第198次更新,第205篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第61题(顺位题号是242).给定两个字符串s和t,写一个函数来确定t是否是s的anag ...
- LeetCode算法题-Same Tree(Java实现)
这是悦乐书的第162次更新,第164篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第21题(顺位题号是100).给定两个二叉树,编写一个函数来检查它们是否相同.如果两个二 ...
- Python爬虫-02:HTTPS请求与响应,以及抓包工具Fiddler的使用
目录 1. HTTP和HTTPS 1.1. HTTP的请求和响应流程:打开一个网页的过程 1.2. URL 2. 客户端HTTP请求 3. Fiddler抓包工具的使用 3.1. 工作原理 3.2. ...
- AIX查看系统版本
AIX系统版本 1. AIX 主要版本.次要版本.维护级 oslevel -r lslpp -h bos.rte 2. 确定某个特定的 AIX 级别缺少哪些文件集更新 举例,若要确定 ...
- Nginx使用教程(二):Nginx配置性能优化之worker配置
配置Nginx workers <br\>NGINX根据指定的配置运行固定数量的工作进程. 这些工作进程负责处理所有处理. 在下面的章节中,我们将调整NGINX worker参数. 这些参 ...
- F. Graph Without Long Directed Paths Codeforces Round #550 (Div. 3)
F. Graph Without Long Directed Paths time limit per test 2 seconds memory limit per test 256 megabyt ...
- UVA215-Spreadsheet Calculator(模拟+拓扑排序)
Problem UVA215-Spreadsheet Calculator Accept:401 Submit:2013 Time Limit: 3000 mSec Problem Descript ...
- 转://Linux下误删除/home目录的恢复方法
一般情况下,我们在安装Oracle数据库的时候,都会创建一个Oracle用户,用该用户来安装和管理Oracle.Oracle用户的根目录就是/home/oracle. 通常安装Oracle数据库是按照 ...