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

最新文章

  1. webapi - 模型验证
  2. MFC如何读取XML
  3. ZOJ 1958. Friends
  4. Button模板,样式
  5. 6、java中的构造代码块
  6. eclipse项目编码问题
  7. THE ONE THING PEOPLE WILL MASSIVELY OVERPAY FOR (有一个东西人们是愿意出高价购买的)
  8. 让你的Git水平更上一层楼的10个小贴士
  9. LeetCode OJ 33. Search in Rotated Sorted Array
  10. 201521123071 《JAVA程序设计》第九周学习总结
  11. 转:【web前端开发】浏览器兼容性处理大全
  12. Ubuntu16.04搭建OpenVPN
  13. C#-IniFiles文件配置连接数据库
  14. linux dns域名缓存
  15. HDU4560 二分最大流
  16. 大量界面刷新时手动Dispose也是有必要的
  17. linux安装tomcat9
  18. linux磁盘用满的两种情况
  19. 传智播客.NET视频学习课件
  20. 数学&amp;搜索:博弈论之极大极小搜索与alpha-beta减枝

热门文章

  1. 【PAT】B1007 素数对猜想
  2. DVWA v1.9 新手指南
  3. [WeChall] Training: Encodings I (Training, Encoding)
  4. D. Diverse Garland Codeforces Round #535 (Div. 3) 暴力枚举+贪心
  5. MySQL高级知识(十五)——主从复制
  6. ElasticSearch(一):CentOS7 安装 ElasticSearch6.4.0
  7. linux 下的启动项
  8. 转://Oracle PL/SQL 优化与调整 -- Bulk 说明
  9. springmvc组件--ViewResolver
  10. sqlalchemy和flask-sqlalchemy的几种分页方法