写在前面:系统的ubuntu14.04,语言:python
ubuntu下载的redis的方式很多,都是直接下载,不用安装的,很绿色,很环保。只要进入到对应的目录下唉启动文件就可以啦。
以我下载的版本为例:
- 第一步找到../redis-3.2.0/src/redis-server文件,在终端下找到该文件
- redis-server
- 运行面的命令,即可启动redis的服务,运行时可能会报错,可以参考我的另一文章。
- 进入redis界面:运行命令redis-cli
即可进入到127.0.0.1:6379> 这样的界面啦。如果数据库里包含中文的结果,那就需要运行redis-cli --raw
这个形式才可以显示中文。
- 运行redis的命令,即可操作redis了。可以到http://redis.io/commands这个官网查看对应的命令。
***************前言end************************
# coding=utf-8
import redis
class RedisQueue(object):
def __init__(self, name, namespace=''):
"""
连接数据库
:param name:对应redis的数据库的键
:param namespace:
:return:
"""
self.__db = redis.Redis(host='192.168.**.**', port=6379, db=0) # 127.0.0.1,#这里是关键,是连接数据库的配置ip
self.key = '%s%s' % (namespace, name)
print self.key
def qsize(self):
"""
对应键的大小
:return:
"""
return self.__db.llen(self.key)
def empty(self):
"""
是否为空
:return:
"""
return self.qsize() == 0
def put(self, item):
"""
放进对应键的值,插入
:param item:
:return:
"""
self.__db.rpush(self.key, item)
def get(self, block=True, timeout=None):
"""
"""
if block:
item = self.__db.blpop(self.key, timeout=timeout)
# Redis Blpop 命令移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
# 如果列表为空,返回一个 nil 。 否则,返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 key ,第二个元素是被弹出元素的值。
else:
# Redis Lpop 命令用于移除并返回列表的第一个元素。
item = self.__db.lpop(self.key)
if item:
item = item[1]
return item
def get_lrange(self, start, end):
"""
取对应位置的值
:param end:
:return:
"""
return self.__db.lrange(self.key, start, end)
def del_key(self):
"""
删除键
:return:
"""
self.__db.delete(self.key)
def exists_key(self, keys):
"""
判断是否存在
"""
return self.__db.exists(keys) == 1
def get_key(self,key_pattern):
"""
获取模式下的键
"""
return self.__db.keys(key_pattern)
以上代码是直接对redis操作的代码,思路很简单——主要是连接到对应的redis库就可以用对应的redis语法进行操作。
那么怎么实现分布式??我是这样做的,有两个方法:
有了基本的操作后,我们将使用python进行redis的使用。
# coding=utf-8
from Queue import Queue
import re
def set_key(redis_key):
"""
以事件为redis的key
:param redis_key:事件
:return:
"""
global redis
redis = RedisQueue(redis_key)
def read_txt(file_name):
"""
打开文本,把对应的内容放进队列
:param file_name: 文本所在的位置
:return:
"""
queue = Queue()
txt = open(file_name, 'r')
words = txt.readlines()
for i in range(len(words)):
words[i] = words[i].replace('\n', '')
queue.put(words[i])//把每一行的人名放进队列
# print 'There are %d username11' % queue.qsize()
return queue
def main_put():
"""
把队列的内容放进redis
:return:
"""
value=""#对应的文件路径
queue = read_txt(value) #数据放进队列了
while not queue.empty(): # 如果队列不空
username = queue.get() # 取第一个然后移出
# print username
redis.put(username) 插入redis数据库,调用类RedisQueue的put方法
print 'There are %d username' % redis.qsize()
# main_put()
- redis有导入数据后,那就需要进行下一步的分布式完成全部任务
上文已经把数据导入redis了,那么分布式的操作也提到了两个方法,那么就先用第一中方法:——redis的数据分批
# coding=utf-8
import redis
downresult_dir = {}
def get_redis_key():
"""
连接数据库取出数据库的key, 然后生成对应的key的文件夹,以便保存结果
:return:
"""
db = redis.Redis(host='192.168.**.**', port=6379, db=0) # 192.168.**.**,这个关键啦,需要连接对应的数据库ip
if db.dbsize():
kes = db.keys("*") #根据模式,取出数据库,这里书全部匹配都取出。
for i in kes:
new_dir = os.path.join(BASE_DIR,'documents','topic',i)
is_exists = os.path.exists(new_dir)
if not is_exists:
os.makedirs(new_dir)
downresult_dir.setdefault(i, new_dir)
return True
else:
return False
def main_headunter(username):
"""
我用了爬虫的方法,爬用户的昵称
:param username: 用户的昵称
:return:
"""
a = Sina('/n/' + str(username))
a.get_result()
def down_username(slave_num, your_id, redis_event):
"""
下载redis的username,进行爬取资料
:param slave_num: 分机的数量
:param your_id: 分机的编号,1,2,3,4....
:return:
"""
average = redis_event.qsize() / int(slave_num)
slave_num = {
1: [0, average], 2: [average + 1, average * 2], 3: [average * 2 + 1, average * 3]}
start_num = slave_num[your_id][0]
end_num = slave_num[your_id][1]
username = redis_event.get_lrange(start_num, end_num)
try:
pool = multiprocessing.Pool(processes=8)
print 'username>>>>>>>>>>>>>>', len(username)
for name_index in xrange(len(username)):
pool.apply_async(main_headunter, (username[name_index],)) #多进程调用了爬虫方法,这里用进程池 apply_async
pool.close()
pool.join()
except Exception, e:
print e
pass
def main_down_stats(SLAVENUM, YOURID):
"""
对数据库的多个事件处理
:return:
YOURID # 机器编号
SLAVENUM # 机器的数量
"""
redis_event = RedisQueue(topic)
down_username(SLAVENUM,YOURID,REDIS_EVENT)
redis_event.del_key() # master清空数据
# main_down_stats(1,1) #第一号机完成第一批任务。其他机子就修改这个参数就可以啦。!!
redis = RedisQueue('key')
while not redis.empty():
try:
username = redis.get()#调用方法,一次取出一个username,取出后这个元素就不存在redis了。直到把redis queue取空为止。
main_headunter(username)#进行username爬虫
expect:
pass
这样,这个方法是全部分机对同一台机子进行操作,没有像第一方法那样分批任务,每台机子有自己对应的批。有理有弊,第一种方法是分工合作,第二方法是共同工作。
# coding=utf-8
import os
import re
def scp_to_master(file_name, YOURID):
"""
上传对应文件夹下的txt到master
:param file_name: txt所在的文件夹的目录
:param YOURID: slave的编号
:return:
"""
stats_txt = './documents/topic/'+YOURID+'.txt'
is_exists = os.path.exists(stats_txt)
if not is_exists:
pass
else:
print '上传....'
scp_chmod = 'scp -p ' +'"' +stats_txt +'"' + ' [email protected]:' +'"/home/users/PycharmProjects/result/documents/topic1/'+ str1+'"'
is_succeed = os.system(scp_chmod) # 传输成功返回大于0的数字
if is_succeed:
print "休眠5s, 再次尝试上传master"
scp_to_master(file_name, YOURID)
else:
print "上传成功", scp_chmod
总结
总结:虽然是实现了分布式,但是对于优缺点还是要说一下的,有点就是针对于单机来说,这样的分布式肯定是比较快的,效率上时快很多的。缺点的话也很明显,首选全部任务都是放在master上,这样导致master的任务还是很重的,因为如果master出现问题,那么其他分机也是无法完成任务的,这就违背了分布式的基本原则了,没有真正意义上的减轻master的任务。然后在回收结果的时候采用的是scp的命令,这也是效率不高的一个错略,redis的分布式是可以直接在内部实现数据的共享的,但我没有学会。
写blog好久没写了,这次是为了留点笔记,和大家一起学习。