缓存之Memcache_aoshen9564的博客-程序员秘密

技术标签: memcached  python  数据库  

Memcache

Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。

缺点:只能支持存储键-值对

Memcache的安装及基本使用

Memcache的安装

wget http://memcached.org/latest
tar -zxvf memcached-1.x.x.tar.gz
cd memcached-1.x.x
./configure && make && make test && sudo make install
 
PS:依赖libevent
       yum install libevent-devel
       apt-get install libevent-dev

启动Memcached

  memcached  - - 10     - u root  - 10.211 . 55.4  - 12000  - 256  - / tmp / memcached.pid
 
参数说明:
     - d 是启动一个守护进程
     - m 是分配给Memcache使用的内存数量,单位是MB
     - u 是运行Memcache的用户
     - l 是监听的服务器IP地址
     - p 是设置Memcache监听的端口,最好是 1024 以上的端口
     - c 选项是最大运行的并发连接数,默认是 1024 ,按照你服务器的负载量来设定
     - P 是设置保存Memcache的pid文件

Memcache的命令

存储命令: set/add/replace/append/prepend/cas
获取命令: get/gets
其他命令: delete/stats..

Python操作Memcached

安装API:

python操作Memcached使用Python-memcached模块

下载安装:https://pypi.python.org/pypi/python-memcached

1、第一次操作

import memcache
 
mc = memcache.Client(['10.211.55.4:12000'], debug=True)
mc.set("foo", "bar")
ret = mc.get('foo')
print ret

Ps:debug = True 表示运行出现错误时,现实错误信息,上线后移除该参数。

 2、天生支持集群

python-memcached模块原生支持集群操作,其原理是在内存维护一个主机列表,且集群中主机的权重值和主机在列表中重复出现的次数成正比

主机    权重
    1.1.1.1   1
    1.1.1.2   2
    1.1.1.3   1
 
那么在内存中主机列表为:
    host_list = ["1.1.1.1", "1.1.1.2", "1.1.1.2", "1.1.1.3", ]

如果用户根据如果要在内存中创建一个键值对(如:k1 = "v1"),那么要执行一下步骤:

  • 根据算法将 k1 转换成一个数字
  • 将数字和主机列表长度求余数,得到一个值 N( 0 <= N < 列表长度 )
  • 在主机列表中根据 第2步得到的值为索引获取主机,例如:host_list[N]
  • 连接 将第3步中获取的主机,将 k1 = "v1" 放置在该服务器的内存中

代码实现如下:

mc = memcache.Client([('1.1.1.1:12000', 1), ('1.1.1.2:12000', 2), ('1.1.1.3:12000', 1)], debug=True)
 
mc.set('k1', 'v1')

3、add
添加一条键值对,如果已经存在的 key,重复执行add操作异常

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import memcache
 
mc = memcache.Client(['10.211.55.4:12000'], debug=True)
mc.add('k1', 'v1')
# mc.add('k1', 'v2') # 报错,对已经存在的key重复添加,失败!!!

4、replace
replace 修改某个key的值,如果key不存在,则异常

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import memcache
 
mc = memcache.Client(['10.211.55.4:12000'], debug=True)
# 如果memcache中存在kkkk,则替换成功,否则一场
mc.replace('kkkk','999')

5、set 和 set_multi

set            设置一个键值对,如果key不存在,则创建,如果key存在,则修改
set_multi   设置多个键值对,如果key不存在,则创建,如果key存在,则修改

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import memcache
 
mc = memcache.Client(['10.211.55.4:12000'], debug=True)
 
mc.set('key0', 'wupeiqi')
 
mc.set_multi({
     'key1': 'val1', 'key2': 'val2'})

6、delete 和 delete_multi

delete             在Memcached中删除指定的一个键值对
delete_multi    在Memcached中删除指定的多个键值对

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import memcache
 
mc = memcache.Client(['10.211.55.4:12000'], debug=True)
 
mc.delete('key0')
mc.delete_multi(['key1', 'key2'])

7、get 和 get_multi

get            获取一个键值对
get_multi   获取多一个键值对

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import memcache
 
mc = memcache.Client(['10.211.55.4:12000'], debug=True)
 
val = mc.get('key0')
item_dict = mc.get_multi(["key1", "key2", "key3"])

8、append 和 prepend

append    修改指定key的值,在该值 后面 追加内容
prepend   修改指定key的值,在该值 前面 插入内容

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import memcache
 
mc = memcache.Client(['10.211.55.4:12000'], debug=True)
# k1 = "v1"
 
mc.append('k1', 'after')
# k1 = "v1after"
 
mc.prepend('k1', 'before')
# k1 = "beforev1after"

9、decr 和 incr  

incr  自增,将Memcached中的某一个值增加 N ( N默认为1 )
decr 自减,将Memcached中的某一个值减少 N ( N默认为1 )

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import memcache
 
mc = memcache.Client(['10.211.55.4:12000'], debug=True)
mc.set('k1', '777')
 
mc.incr('k1')
# k1 = 778
 
mc.incr('k1', 10)
# k1 = 788
 
mc.decr('k1')
# k1 = 787
 
mc.decr('k1', 10)
# k1 = 777

10、gets 和 cas

如商城商品剩余个数,假设改值保存在memcache中,product_count = 900
A用户刷新页面从memcache中读取到product_count = 900
B用户刷新页面从memcache中读取到product_count = 900

如果A、B用户均购买商品

A用户修改商品剩余个数 product_count=899
B用户修改商品剩余个数 product_count=899

如此一来缓存内的数据便不在正确,两个用户购买商品后,商品剩余还是 899
如果使用python的set和get来操作以上过程,那么程序就会如上述所示情况!

如果想要避免此情况的发生,只要使用 gets 和 cas 即可,如:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import memcache
mc = memcache.Client(['10.211.55.4:12000'], debug=True, cache_cas=True)
 
v = mc.gets('product_count')
# ...
# 如果有人在gets之后和cas之前修改了product_count,那么,下面的设置将会执行失败,剖出异常,从而避免非正常数据的产生
mc.cas('product_count', "899")

Ps:本质上每次执行gets时,会从memcache中获取一个自增的数字,通过cas去修改gets的值时,会携带之前获取的自增值和memcache中的自增值进行比较,如果相等,则可以提交,如果不想等,那表示在gets和cas执行之间,又有其他人执行了gets(获取了缓冲的指定值), 如此一来有可能出现非正常数据,则不允许修改。

 

转载于:https://www.cnblogs.com/louyifei0824/p/10142127.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/aoshen9564/article/details/101809004

智能推荐

python网络编程报错socket.error: [Errno 9] Bad file descriptor_木子光宅的博客-程序员秘密

想学学python网络编程,按书上写了两个服务器和客户端小程序,结果发现报错:Traceback (most recent call last):  File "./tsTserv.py", line 20, in     data = tcpCliSock.recv(BUFSIZ)  File "/usr/lib/python2.6/socket.py", line 165,

windows下libfreenect2的安装_jiaojialulu的博客-程序员秘密

libfreenect2什么是libfreenect2libfreenect2是一个针对kinect v2的非官方驱动,它是开源的,当我们在官方驱动不能满足需求的时候就可以使用它。支持的功能RGB 彩色图的获取IR 和深度图的获取彩色图和深度图的配准支持多kinect v2 它没有像官方驱动中集成丰富的算法比如骨骼追踪,但是可以支持多个kinect v2同时工作。源码下载github上有

面试题:460道Java后端面试高频题答案版【模块十:SpringMVC】_Java面试大全的博客-程序员秘密

SpringMVC写在前面对于 SpringMVC 并没有太多的学习经验分享给大家,因为我是通过某培训机构的视频学习的 SpringMVC。我个人认为 SpringMVC 的高频面试点有...

openGL 教学素材记录_chenhuakang的博客-程序员秘密

https://github.com/doggycoder/AndroidOpenGLDemo当前内容三角形。等腰直角三角形。彩色三角形。正方形的绘制。正方体的绘制。圆锥的绘制。圆柱的绘制球体的绘制显示图片(纹理贴图初步)图片简单的色彩处理图片模糊放大镜效果平移旋转缩放变换相机GL预览压缩纹理动画FBO使用3D模型《帽子》加载EGL方式后台处理图像示例3D《皮卡丘》模型及纹理加

【GDScript】做一个常用的功能——节点转向到目标位置_张学徒的博客-程序员秘密_gdscript

Godot 3.2.4 beta4主场景中,拖拽 文件系统 中的 icon.png 文件到场景中,在 icon 节点下边添加一个 Node2D 节点,并添加脚本(如下图所示)。然后将下面代码粘贴到 Node2D 节点的脚本里。在这里我做了一个节点旋转到鼠标位置的代码,你也可以稍作修改,改为旋转到其他节点位置等,在 process 方法里#========================================================================# D.

asp.net 导出GridView里的数据到Excel中,全部,当前页,选择行,选中行,所选行,复..._limon758的博客-程序员秘密

按下保存按钮,可以选择保存当前行,当前页和全部记录[code=&quot;c#&quot;]#region 保存/// /// 保存/// protected void btnBC_Click(object sender, EventArgs e){ string save_cblJL = &quot;&quot;; for (int i = 0; i &lt; this.cblJL.Items.Cou...

随便推点

基于httpclient的效率优化_aan5489的博客-程序员秘密

1.背景我们有个业务,会调用其他部门提供的一个基于http的服务,日调用量在千万级别。使用了httpclient来完成业务。之前因为qps上不去,就看了一下业务代码,并做了一些优化,记录在这里。先对比前后:优化之前,平均执行时间是250ms;优化之后,平均执行时间是80ms,降低了三分之二的消耗,容器不再动不动就报警线程耗尽了,清爽~2.分析项目的原实现比较粗略,就是每次...

电影院票务管理系统数据库设计_johnli1989的博客-程序员秘密

这两天听到一道面试题:设计一个电影院票务管理系统的表结构。挺有意思的,我自己也试着做了一做,感觉还是有不少收获的。在本文中我想把做这道题的整个思路重新理一下,也算做个整理了。 现在能得到的需求只有一个:设计一个电影院票务管理系统的表结构。再没有其他信息了,可能真的面试的时候面试官还会给出其他业务需求,但我这里没有。所以我只能猜测可能的业务需求会有哪些。最初想到的:1. 电影院会有多个播放厅,从而在...

Linux-Nginx+rtmp+ffmpeg搭建流媒体服务器_weixin_30338461的博客-程序员秘密

Nginx+rtmp+ffmpeg搭建流媒体服务器说明:  nginx搭建流媒体服务需要用到 nginx-rtmp-module 模块具体操作步骤:安装nginx(1)下载第三方扩展模块nginx-rtmp-module# mkdir module &amp;&amp; cd module   //创建一个存放模块的目录# wget https://g...

ubuntu conda使用报错:An unexpected error has occurred. Conda has prepared the above report._Abibulla的博客-程序员秘密

ubuntu conda使用报错:An unexpected error has occurred. Conda has prepared the above report.非常简单:删除用户目录下的~~.condarc~~ 文件。

Unity 图片序列帧动画的四种方法_奇大可的博客-程序员秘密

using UnityEngine;using System.Collections; /// &amp;lt;summary&amp;gt;/// 图片序列帧播放三种方法 /// GUI.DrawTexture (new Rect (10, 10, 100, 100), TexArray [currentIndex]);每一帧都执行/// currentIndex是控制一定时间后换一下/// &amp;...

180908-Git和Sourcetree的安装与配置_weixin_30908649的博客-程序员秘密

1.下载并安装Git与Sourcetree,完成后在Sourcetree中设置Git为刚装好的Git2.使用 git 客户端生成公私钥:lichengbei(私钥)、lichengbei.pub(公钥)1.设置Git的user name和email:$ git config --global user.name "lichengbei1949"$...