缓存

 


 
一、memcached(value只能是str):
  • 关键字:
    • 旁路代理:
      • 缓存中若无数据,app自行从db获取,至于获取后是否更新缓存,由代码自行决定
    • 分布式:
      • 各个节点彼此无视,分布式功能完全依赖于app或调度器实现(haproxy)
    • 缓存清理:
      • memcache不会主动清理过期数据,只会在系统给memcache分配的存储空间使用完毕后,根据LUR算法,数据更新时对不活跃数据进行覆盖
    • 集群实现:
      • 通过app自身,搞笑,雪崩了谁背锅
      • 通过haproxy,正解!只有haproxy调度器有一致性hash算法
  • 安装:
    • server:
      • 1、yum install memcached ;
      • 2、memadmin.tar.gz 管理控制台,php实现的web版本
    • client:
      • 1、安装API:python-memcache  # --trusted-host=pypi.douban.com
  • 使用:
    • 连接:
      • import memcache
      • server = memcache.Client( [('1.1.1.1:11211', 1), ('1.1.1.2:11211', 2)] )
      • 解释:
        • 该API模块支持权重,即其内部维护一个主机列表,权重为几,则该节点在列表中出现几次
        • 如上则:1.1.1.1  1.1.1.2  1.1.1.2 
        • 插入数据时,将Key先进行hash取数值,再将数值与列表长度取模,余数为几则数据存储到第几个个节点
    • add/replace:
        • server.add('key1', value1) # 添加一条键值对,若key已经存在,则操作异常
        • server.replace('key1', '11111') # 修改某个key的值,若key不存在,则异常
    • set/set_nulti
      • server.set('key1', 'value1') # 设置一个键值对,key不存在则创建;key存在则修改
      • server.set_nulti( {'key1':'value1', 'key2':'value2'} ) # 设置多个键值对,key不存在则创建,key存在则修改
    • delete/delete_nulti
      • server.delet('key1') # 删除一个键值对
      • server.delete_nulti(['key1', 'key2']) # 删除多个键值对
    • get/get_nulti
      • ret = server.get( 'key1' ) # 获取一个键值对
      • ret_dic = server.get_multi( ['key1', 'key2'] )  # 获取多个键值对
    • append/prepend
      • server.append('key', 'after')  # 在指定key值后,追加内容
      • server.prepend('key', 'before')  # 在指定key值前,插入内容
    • incr/decr
      • server.incr('key1')  # 将某一个值自增N ,N默认为1, key的值自增了1
      • server.incr('key1', 10 ) # 将某一个值自减N, N默认为1, key的值自增了10
      • server.decr('key1') # key的值自减1
      • server.decr('key1', 10) # key的值自减10
    • gets/cas
      • 场景:若商品剩余数为100,A B 同时购买1个,则本应为98,但是,A和B均会在本地运算得到99 ,再写入memcahce中
      • ret = server.gets('product_count') # 每个 client 通过 gets 获取数据的同时,会获取该key的一个自增的数字,
      • server.cas('product_count', 99)  # 修改数据前,对比之前获取的数字是否相同,不同则表示有人也获取了数据,可能已经被别人在本地修改,即抛出异常

 
二、redis:
 
1、概述
  • 安装:
    • server: yum install redis ; sed -i 's/127.0.0.1/0.0.0.0/g' /etc/redis.conf
    • client:安装API :redis # --trusted-host=pypi.douban.com

  • import redis
    • redis-py 提供了两个类:Redis, StrictRedis 用于实现redis的命令,
      • StrictRedis用于实现大部分官方的语法和命令,
      • Redis 是strictredis的子类,用于向前兼容旧版本的redis-py
  • 连接方式:
    • 直接连接:conn = redis.Redis(host='1.1.1.1', port=6379)
    • 连接池:
pool = redis.ConnectionPool(host='1.1.1.1', port=6379)
conn = redis.Redis(connection_pool=pool)
conn.set('key1', 'value1')

2、基本数据类型
  • string 操作 (name -- key 一一对应):
    • set/mset
set( name, value, ex=None, px=None, nx=False, xx=False )
ex 过期时间,秒
px 过期时间,毫秒
nx 若为True,则表示只有该key不存在,才执行set
xx 若为True,则表示只有该key存在,才执行set

setns(name, value)   # 当name不存在时,创建一个键值对
setex(name, value, time) # 创建一个键值对,并指定过期时间
mset(* args, **kwargs) # 批量设置,比如 mset( k1='v1', k2='v2' )
    • get(name) / mget(keys, *args)
get('key1')
mget('key1', 'key2') # 批量获取
    • 自增、自减、追加
incr(self, name, amount=1) # 当name不存在,则创建name=amount,否则其值自增1
infcbyfloat(self, name, amount=1.0) # 同上,只不过自增可浮点数
decr(self, name, amount=1) # 自减name对应的值,当name不存在则创建name=amount
append(key, value) # 在指定key后面追加内容
    • 其他:
getset(name, value) # 设置一个新值,并获取原先的值
getrange(name, start, end) # 切片,获取指定key的值,并进行切片
strlen(name) # 获取指定key的字节长度 
  • hash 操作(一个name对应一个字典)
    • 创建
hset(name, key, value) # 为指定name关联一个键值对,不存在则创建;存在则修改
hmset(name, mapping) # 批量设置键值对,mapping为字典,比如dic1 , dic2
    • 获取指定字典中指定key值
hget(name, key) # 在name对应的dict中获取指定key
hmget(name, keys, lst) # 在name对应的hash中获取多个key值,lst中为各key名称
    • 获取指定字典中所有key值
hgetall(name) # 获取name对应的所有键值
hlen(name) # 获取name对应的所有键值个数
    • 获取指定字典中所有key,或value
hkeys(name) # 获取name对应的hash中所有的key名称
hvals(name) # 获取name对应的hash中所有的value的值
    • 判断:
hexists(name, key) # 检测name对应的hash中是否存在指定key
    • 删除:
hdel(name, *keys) # 将name对应的hash中指定key键值对删除, *keys可为列表或元组
    • 自增、自减:
hincrby(name, key, amount=1) # 自增指定name中的指定key值,不存在,则创建key=amount
hincrbyfloat(name, key, amount=1.0) # 同上,只不过可以浮点

    • 迭代获取:
--------------- hscan
hscan(name, cursor=0, match=None, coiunt=None) # 迭代式获取键值对
cursor1, data = server.hscan(name, cursor=0, match=None, count=None)
cursor2, data = server.hscan(name, cursor=cursor1, match=None, count=None)
# cursor表示游标指针,当cusor为0,则表示已经获取完成
-------------- hscan_iter
# 利用yield封装hscan创建生成器,实现分批获取数据
for item in server.hscan_iter(name)
print(item)
  • list 操作(每个name对应一个lst)
    • 添加:
lpush(name, value) # 在name对应的list中添加元素,每个新的元素都添加到列表的最左边
server.lpush('name1', 11,22,33)  # 保存顺序为33,22,11
    • 列表长度:
llen(name) # 返回对应list的元素个数
    • 插入:
linsert(name, where, refvalue, value) # 在指定值前后插入数据
name: 名称
where: BEFORE 或 AFTER
refvalue: 标杆值,即在该值前后插入数据
value: 要插入的数据
    • 删除:
lrem(name, value, num) # 在name对应的list中删除指定的值
name::列表名称
value:要删除的值
num:正数,从前到后删N个,负数,从后到前删N个
    • pop弹出:
lpop(name) # 从列表左侧弹出一个元素并移除,
rpop(name) # 从右侧弹出
    • 切片、索引:
lset(name, index,value) # 在索引处重新赋值
lindex(name , index) # 在列表中根据索引获取列表元素
lrange(name, start, end) # 切片获取数据
ltrim(name, start, end) # 切片移除
    • 迭代:
redis的列表没有提供迭代功能,因此需要自定义增量迭代
# 定义迭代器
def list_iter(name):
list_count = server.llen(name)
for index in range(list_count):
yield server.lindex(name, index)
# 使用
for item in list_iter('name'):
print(item)
    • 集合、有序集合
3、管道:
    • redis-py 默认在执行每次请求时,都会创建(连接池获取链接)和断开(释放链接),
    • 若想在一次请求中完成多个指令,则可以使用pipline,默认情况下,一次pipline是个原子操作

import redis
pool = redis.ConnectionPool(host='1.1.1.1', port=6379)
server = redis.Redis(connection_pool=pool)

pipe = server.pipline(transaction=True) # 下面的指令会缓存到cmd buffer中
server.set('name', 'qiao')
server.set('role', 'kk')
pipe.execute() # 发送并执行cmd buffer中指令
4、发布订阅:
    • 自定义公共类
import redis

class RedisHelper:
def __init__(self):
self.__conn = redis.Redis(host='61.129.46.111', port=6379)
self.chan_sub = 'xxx'

def public(self, msg):  # 发布消息
self.__conn.publish(self.chan_sub, msg)
return True

def subscribe(self):
pub = self.__conn.pubsub() # 返回一个发布订阅对象
pub.subscribe(self.chan_sub) # 订阅一个频道
pub.parse_response() # 订阅频道的时候也会有响应,需要解析
return pub # 返回该订阅了频道的“发布/订阅”对象
    • client端(订阅者)
obj = RedisHelper() # 实例化一个自定义类
redis_sub = obj.subscribe()  # 获取一个已经订阅了频道的“发布/订阅”对象

while True:
msg = redis_sub.parse_response()  # 响应为列表结构,且元素为字节,[b'message', b'xxx', b'test1'] <class 'list'>
data = msg[2].decode()
print(msg, type(msg), data, type(data))
    • server 端(发布者)
obj = RedisHelper() # 实例化一个自定义类
obj.public('test1') # 发布消息








 

posted on 2016-09-15 21:09  台灯不太亮  阅读(207)  评论(0编辑  收藏  举报

导航