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的关系的更多相关文章

  1. 跨站请求伪造(csrf),django的settings源码剖析,django的auth模块

    目录 一.跨站请求伪造(csrf) 1. 什么是csrf 2. 钓鱼网站原理 3. 如何解决csrf (1)思路: (2)实现方法 (3)实现的具体代码 3. csrf相关的装饰器 (1)csrf_p ...

  2. Django对中间件的调用思想、csrf中间件详细介绍、Django settings源码剖析、Django的Auth模块

    目录 使用Django对中间件的调用思想完成自己的功能 功能要求 importlib模块介绍 功能的实现 csrf中间件详细介绍 跨站请求伪造 Django csrf中间件 form表单 ajax c ...

  3. 豌豆夹Redis解决方案Codis源码剖析:Dashboard

    豌豆夹Redis解决方案Codis源码剖析:Dashboard 1.不只是Dashboard 虽然名字叫Dashboard,但它在Codis中的作用却不可小觑.它不仅仅是Dashboard管理页面,更 ...

  4. 豌豆夹Redis解决方案Codis源码剖析:Proxy代理

    豌豆夹Redis解决方案Codis源码剖析:Proxy代理 1.预备知识 1.1 Codis Codis就不详细说了,摘抄一下GitHub上的一些项目描述: Codis is a proxy base ...

  5. Redis源码剖析--源码结构解析

    请持续关注我的个人博客:https://zcheng.ren 找工作那会儿,看了黄建宏老师的<Redis设计与实现>,对redis的部分实现有了一个简明的认识.在面试过程中,redis确实 ...

  6. Redis源码剖析

    Redis源码剖析和注释(一)---链表结构 Redis源码剖析和注释(二)--- 简单动态字符串 Redis源码剖析和注释(三)--- Redis 字典结构 Redis源码剖析和注释(四)--- 跳 ...

  7. Jedis cluster集群初始化源码剖析

    Jedis cluster集群初始化源码剖析 环境 jar版本: spring-data-redis-1.8.4-RELEASE.jar.jedis-2.9.0.jar 测试环境: Redis 3.2 ...

  8. 【Redis】事件驱动框架源码分析(多线程)

    IO线程初始化 Redis在6.0版本中引入了多线程,提高IO请求处理效率. 在Redis Server启动函数main(server.c文件)中初始化服务之后,又调用了InitServerLast函 ...

  9. 【Redis】事件驱动框架源码分析

    aeEventLoop初始化 在server.c文件的initServer函数中,对aeEventLoop进行了初始化: 调用aeCreateEventLoop函数创建aeEventLoop结构体,对 ...

随机推荐

  1. Shell编程基础知识(一)

    一.基本的运行Linux程序的3种方法: (1) 使文件具有可执行权限,直接运行文件.eg:  chmod a+x testfile.sh   ./testfile.sh (2) 直接调用命令解释器来 ...

  2. Linux学习之路(一)

    导语: 早前为了方便日常开发,建立跟生产环境类型的环境的时候考虑使用docker作为模拟生产环境,结果没想到给自己的学习挖了一个大坑.其他关于docker容器技术的坑先不在这里赘述,有时间的话在其他文 ...

  3. LeetCode算法题-First Bad Version(Java实现-三种解法)

    这是悦乐书的第200次更新,第210篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第66题(顺位题号是278).您是产品经理,目前领导团队开发新产品.不幸的是,您产品的最 ...

  4. May 26. 2018 Week 21st Saturday

    Do what you say, say what you do. 做你说过的,说你能做的. Be honest to yourself, and be honest to those people ...

  5. 【shell脚本】shell脚本实现的 函数差集查找

    文本地址 点击关注微信公众号 wenyuqinghuai 分享提纲: 1. 问题背景 2. 代码实现 1.问题背景 在做公司的测试的自动化测试时,覆盖了一些开发代码的函数,但是那些还没有做,使用一个函 ...

  6. 序列对象(bytearray, bytes,list, str, tuple)

    列表: L.append(x) # x追加到L尾部 L.count(x) # 返回x在L中出现的次数 L.extend(m) # Iterable m的项追加到L末尾 L += m # 功能同L.ex ...

  7. 【Linux基础】history查看历史命令

    1.history命令 “history”命令就是历史记录.它显示了在终端中所执行过的所有命令的历史. history //显示终端执行过的命令 history //显示最近10条终端执行过的命令 C ...

  8. Docker容器资源管理

    本文作者是Red Hat的软件工程师 - Marek Goldmann,这篇文章详细介绍了Docker容器的资源管理,总共分了三大部分:CPU.内存以及磁盘IO.作者通过实践举例给读者勾勒出一幅清晰明 ...

  9. jsp 或 php 等view之中使用javascript简单处理的使用技巧

    前端人员在jsp,php等后台mvc之的coding之时,前端人员常常需要一些少量的数据处理,直接使用js的方法无疑是开销最小的.使用的方法 使用在标签之中嵌套script标签,使用document. ...

  10. 如何在excel单元格中插入图片批注

    在excel单元格中插入图片批注的方法: 1.选定要插入图片的单元格,然后右键选择插入批注. 2.然后会插入一个批注框,为了不影响图片效果,可以将批注文字都删除.然后鼠标移动到批注框边角再右键. 3. ...