Python【10】【网络编程】- Memcache、Redis、RabbitMQ、SQLAlchemy

知识参鉴:百度百科Mr.7

Memcached

1、基础认知

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

 

绘图1

2、安装使用

(1)安装

# 安装依赖包
centos:yum install libevent-devel
ubuntu:apt-get install libevent-dev

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

(2)启动&测试连接

## Start memcached

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


## Play with telnet

$ telnet localhost 11211
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get foo
VALUE foo 0 2
hi
END
stats
STAT pid 8861
(etc)

(3)memcached 常用命令

存储的命令格式

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

<command name> <key> <flags> <exptime> <bytes>
<data block>
<command name> set/add/replace
<key> 查找关键字
<flags> 客户机使用它存储关于键值对的额外信息
<exptime> 该数据的存活时间,0表示永远
<bytes> 存储字节数
<data block> 存储的数据块(可直接理解为key-value结构中的value)

3、Python memcached API

(1)安装 python-memcached模块

# 在Python中使用python-memcached 模块操作memcached

# 下载安装
https://pypi.python.org/pypi/python-memcached
tar xf memcached-1.4.25
cd memcached-1.4.25
 ./configure ; make ; make install
# 或
pip install python-memcached

(2)连接操作

#!/usr/bin/env python
# coding:utf-8
__author__ = "King"

import memcache

mc = memcache.Client(['10.0.7.4:22000'], debug=True)     # debug=True会输出bug信息,如果在线上应置为0
mc.set("key", "value")
ret = mc.get("key")
print ret

"""
This should give you a feel for how this module operates::

    import memcache
    mc = memcache.Client(['127.0.0.1:11211'], debug=0)

    mc.set("some_key", "Some value")
    value = mc.get("some_key")

    mc.set("another_key", 3)
    mc.delete("another_key")

    mc.set("key", "1") # note that the key used for incr/decr must be
                       # a string.
    mc.incr("key")
    mc.decr("key")

The standard way to use memcache with a database is like this:

    key = derive_key(obj)
    obj = mc.get(key)
    if not obj:
        obj = backend_api.get(...)
        mc.set(key, obj)

    # we now have obj, and future passes through this code
    # will use the object from the cache.

"""

(3)原生支持集群

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')

(4)add

#!/usr/bin/env python
# coding:utf-8
__author__ = "King"

import memcache

mc = memcache.Client(['10.0.7.4:22000'], debug=True)
mc.add("k1", "v1")
mc.add("k1", "v1")

## MemCached: while expecting 'STORED', got unexpected response 'NOT_STORED'
# 添加一条键值对,如果已经存在,重复添加会失败

(5)replace

#!/usr/bin/env python
# coding:utf-8
__author__ = "King"

import memcache

mc = memcache.Client(['10.0.7.4:22000'], debug=True)
mc.add("k1", "v1")
mc.replace("k1", "vv")
mc.replace("k2", "vv")

## MemCached: while expecting 'STORED', got unexpected response 'NOT_STORED'
# rreplasce 修改不存在的key的值会报错

(6)set & set_multi

#!/usr/bin/env python
# coding:utf-8
__author__ = "King"

import memcache

mc = memcache.Client(['10.0.7.4:22000'], debug=True)
mc.set("xiaoming", 12)
mc.set_multi({"xiaohua": 13, "xiaohong": 14})

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

(7)delete & delete_multi

#!/usr/bin/env python
# coding:utf-8
__author__ = "King"

import memcache

mc = memcache.Client(['10.0.7.4:22000'], debug=True)
mc.delete("xiaoming")
mc.set_multi(["xiaohua", "xiaohong"])

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

(8)get & get_multi

#!/usr/bin/env python
# coding:utf-8
__author__ = "King"

import memcache

mc = memcache.Client(['10.0.7.4:22000'], debug=True)
mc.get("xiaoming")
ret = mc.get_multi(["xiaohua", "xiaohong", "k1"])
print ret

## {'xiaohua': 13, 'xiaohong': 14, 'k1': 'vv'}
"""
get         获取一个键值对
get_multi   获取多一个键值对
"""

(9)append & prepend

#!/usr/bin/env python
# coding:utf-8
__author__ = "King"

import memcache

mc = memcache.Client(['10.0.7.4:22000'], debug=True)
mc.set('k2', '11')
mc.append('k2', 'endend')
mc.prepend('k2', 'afafaf')

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

(10)decr & incr

#!/usr/bin/env python
# coding:utf-8
__author__ = "King"

import memcache

mc = memcache.Client(['10.0.7.4:22000'], debug=True)
mc.set('k2', '11')
mc.incr('k2', 10)   # k2 = 21
mc.decr('k2', 5)    # k2 = 16
mc.incr('k2', )     # k2 = 17
mc.decr('k2',)      # k2 = 16

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

(11)gets & cas

#!/usr/bin/env python
# coding:utf-8
__author__ = "King"

import memcache

mc = memcache.Client(['10.0.7.4:22000'], debug=True, cache_cas=True)
mc.set('k2', '100')

mc.gets('k2')

# 如果有人在gets之后和cas之前修改了product_count,
# 那么,下面的设置将会执行失败,剖出异常,从而避免非正常数据的产生
mc.append('k2', '1')   
 
mc.cas('k2', '80')

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

Memcached 真的过时了吗?

Redis

1、基础认知

    Redis 是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
    Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用,它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便.
    Redis 支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。


1

2、安装与使用

Redis官网

# Download, extract and compile Redis with:

$ wget http://download.redis.io/releases/redis-3.0.6.tar.gz
$ tar xzf redis-3.0.6.tar.gz
$ cd redis-3.0.6
$ make

# The binaries that are now compiled are available in the src directory. Run Redis with:

$ src/redis-server

# You can interact with Redis using the built-in client:

$ src/redis-cli
redis> set foo bar
OK
redis> get foo
"bar"

3、python redis API

(1)安装

sudo pip install redis
or
sudo easy_install redis
or
源码安装
 
详见:https://github.com/WoLpH/redis-py

(2)操作模式

redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。

#!/usr/bin/env python
# coding:utf-8
__author__ = "King"

import redis

r = redis.Redis(host='10.0.7.4', port=7777)
r.set('k1', 'v1')
print r.get('k1')

(3)连接池

redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。

#!/usr/bin/env python
# coding:utf-8
__author__ = "King"

import redis

# 创建一个连接池
pool = redis.ConnectionPool(host='10.0.7.4', port=7777)
# 引用连接也创建一个实例
r = redis.Redis(connection_pool=pool)
r.set('k1', 'v1')
print r.get('k1')

(4)管道

redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。

#!/usr/bin/env python
# coding:utf-8
__author__ = "King"

import redis

pool = redis.ConnectionPool(host='10.0.7.4', port=7777)
r = redis.Redis(connection_pool=pool)

pipe = r.pipeline(transaction=True)
"""
    Return a new pipeline object that can queue multiple commands for
    later execution. ``transaction`` indicates whether all commands
    should be executed atomically. Apart from making a group of operations
    atomic, pipelines are useful for reducing the back-and-forth overhead
    between the client and server.
"""
r.set('k1', 'v1')
r.set('k2', 'v2')

pipe.execute()

(5)发布定阅

1

发布者:服务器

订阅者:Dashboad和数据处理

Demo如下:

#!/usr/bin/env python
# coding:utf-8
__author__ = "QingPing"

import redis


class RedisHelper:

    def __init__(self):
        self.__conn = redis.Redis(host='10.211.55.4')
        self.chan_sub = 'fm104.5'
        self.chan_pub = 'fm104.5'

    def public(self, msg):
        self.__conn.publish(self.chan_pub, msg)
        return True

    def subscribe(self):
        pub = self.__conn.pubsub()
        pub.subscribe(self.chan_sub)
        pub.parse_response()
        return pub

订阅者:

#!/usr/bin/env python
# coding:utf-8
__author__ = "QingPing"

from monitor.RedisHelper import RedisHelper
 
obj = RedisHelper()
redis_sub = obj.subscribe()
 
while True:
    msg= redis_sub.parse_response()
    print msg

发布者:

#!/usr/bin/env python
# coding:utf-8
__author__ = "QingPing"

from monitor.RedisHelper import RedisHelper
 
obj = RedisHelper()
obj.public('hello')

More...

RabbitMQ

 

 

 

 

SQLAlchemy

 

 

 

1

posted @ 2016-01-22 11:56  YaYaTang  阅读(284)  评论(0编辑  收藏  举报