每日一题_Python.利用gevent和pipeline快速导出近千万Redis字段值?

事情缘由:

昨日下午工信部前来,几个看似很专业搞安全的非要让现场写脚本导出几百万条Redis记录中的IP字段,由于之间确实没想过如何快速导出这么多数据,只能尴尬认怂~但下来仔细想想我们可以做到~办法总比困难多~

具体需求:

1. 快速导出Redis中只包含[0-9a-z]组成的16序列号下的WlanIP字段

实现思路:

1. 必然先想到多线程/多进程/多协程,最终选择gevent协程池的原因的是涉及到Redis读和文件写操作,相对于多进程/多线程更容易控制且时间不会浪费在阻塞上,异步来回切换更适合

2. 为了减轻每次调用Redis接口keys指令,所以先计算出[0-9a-z]组成的2位序列号排列组合,顺便将其作为250多个文件名

3. 为了减轻每次调用Redis接口hgetall指令,所以使用pipeline,超过1000个指令后统一通过各自管道发送来防止反复连接执行耗时

4. 由于Redis接口连接池只是提供了keepalive功能,所以在协程内部直接维护100个"假"连接池,但还有一个最主要的功能是为了解决pipeline混乱的问题

具体代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
#
# Authors: limanman
# OsChina: http://xmdevops.blog.51cto.com/
# Purpose:
#
"""
# 说明: 导入公共模块
import os
from gevent import monkey
from gevent.pool import Pool
from itertools import product
from redis.exceptions import ResponseError
from redis import StrictRedis, ConnectionPool
# 说明: 导入其它模块

host = ‘127.0.0.1‘
port = 5123
monkey.patch_all()

def write_serialdata(key):
    rds_pool = ConnectionPool(host=host, port=port)
    rds_inst = StrictRedis(connection_pool=rds_pool, retry_on_timeout=True, max_connections=10)
    rds_pipe = rds_inst.pipeline()
    prefix = ‘‘.join(key)
    redis_key = ‘{0}*‘.format(prefix)
    rds_pipe.keys(redis_key)
    redis_val = rds_pipe.execute()
    if not redis_val:
        return
    with open(prefix, ‘a+b‘) as fd:
        for index, serial_key in enumerate(redis_val[0]):
            if index % 1000 == 0:
                serial_val = rds_pipe.execute()
                if not serial_val:
                    continue
                for item in serial_val:
                    if ‘WanIP‘ not in item:
                        continue
                    ip = item[‘WanIP‘]
                    print ‘record ip => {0} to file {1}‘.format(ip, prefix)
                    fd.write(‘‘.join([ip, os.linesep]))
            if not serial_key.isalnum():
                continue
            rds_pipe.hgetall(serial_key)
        serial_val = rds_pipe.execute()
        if not serial_val:
            return
        for item in serial_val:
            if ‘WanIP‘ not in item:
                continue
            ip = item[‘WanIP‘]
            print ‘record ip => {0} to file {1}‘.format(ip, prefix)
            fd.write(‘‘.join([ip, os.linesep]))

def generat_product():
    s_bit = ‘abcdef0123456789‘
    return product(s_bit, repeat=2)

if __name__ == ‘__main__‘:
    pool = Pool(100)
    keys = generat_product()
    path = []
    for key_pairs in keys:
        fpath = ‘‘.join(key_pairs)
        path.append(fpath)
        if not os.path.exists(fpath):
            file(fpath, ‘w+b‘).close()
    pool.map(write_serialdata, path)

有图有相:

时间: 2024-10-14 06:57:39

每日一题_Python.利用gevent和pipeline快速导出近千万Redis字段值?的相关文章

每日一题_Python.利用yield生成器实现协程下的tps透明传输CS测试

具体需求:1. 模拟Device首先发送注册包注册到TPS服务器,然后Client发送私有数据包到TPS,测试Device可以接收到私有数据包则返回成功或标志位(0, '')或(1, 'errormsg')2. 由于此插件是用于自己写的插件式监控系统,所以入口函数名必须和文件名保持一致,这里暂定为server_tps_status.py 实现思路: 具体代码: #!/usr/bin/env python # -*- coding: utf-8 -*- """ # # Auth

每日一题_Python.纯Python实现Low-Level discovery动态服务发现?

具体需求:1. 由于自主开发的XmZoomEye-Agent目前被动监控为主,为了实现Zabbix Low-Level Discovery服务自主发现,需要根据进程名自动获取占用端口列表,并根据端口分析上报数据 实现思路: 1. 利用psutil模块通过进程名获取进程id列表2. 遍历/proc/net/tcp文件获取rem_address为00000000:0000的列,将第九列的socket_id和它以集合形式的字典存储去重3. 利用获取到的pid列表和socket_id集合字典生成端口集合

每日一题_JavaScript.利用纯JavaScript Dom Core实现一个图片轮播效果 ?

具体需求:1. 页面加载后每隔2秒自动从轮播图片2. 鼠标悬停或是点击页面中小图片时,大图片自动跟随切换,并且停止轮播3. 鼠标离开小图片时,图片重新开始轮播 实现思路: 具体代码: html <!DOCTYPE html> <html>     <head>         <meta charset="utf-8" />         <title>Js实现图片轮播</title>         <l

每日一题_JavaScript.利用Js操作frameset框架集对象实现购物车?

具体需求: 1. 框架集中包含上下两个框架,上面为购物车,下面为商品列表,点击商品列表中购买,实现购物车中额数字增加并传递商品ID 实现思路: 具体代码: shopping.html <!DOCTYPE html> <html>     <head>         <meta charset="UTF-8">         <title></title>     </head>     <fr

每日一题之动归-换钱的最少次数(一)

题目: 给定数组arr,arr中所有的值都为正数且不重复.每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim代表要找的钱数,求组成aim的最少货币数. 举个例子 arr[5,2,3] ,aim=20 4张5元可以组成20,并且是最小的,所以返回4 arr[5,2,3],aim=0. 不用任何货币就可以组成0元,这里返回0. arr[5,2,3],ami=4 这里无法组成返回-1 思路:这里我们采用经典的动态规划的方法做,时间复杂度可以在O(n^2). 经典动态规划的放法

&#8203;老男孩教育每日一题-第73天 -基础命令点:可恶的^C

题目背景: 很多运维的朋友都遇到过一个问题,输入一串命令,每次按下ctrl+c都会出现一个比较麻烦的字符信息^C请问有什么方法可以不让^C字符信息出现呢? 解决方法: 利用stty命令即可解决:中断不显示^C:  stty -echoctl终端显示^C:    stty echoctl就是这么简单,碍眼的^C字符信息就可以没有了 备注 今天是每日一题陪伴大家的第73天,期待你的进步.对于题目和答案的任何疑问,请在博客评论区留言.往期题目索引http://lidao.blog.51cto.com/

老男孩教育每日一题-第107天-简述你对VPN的理解,常见的有哪几种?

参考答案: VPN(全称Virtual Private Network)虚拟专用网络. 依靠ISP和其他的NSP,在公共网络中建立专用的数据通信网络的技术,可以为企业之间或者个人与企业之间提供安全的数据传输隧道服务. 在VPN中任意两点之间的连接并没有传统专网所需的端到端的物理链路,而是利用公共网络资源动态组成的,可以理解为通过私有的隧道技术在公共数据网络上模拟出来的和专网有同样功能的点到点的专线技术. 谓虚拟是指不需要去拉实际的长途物理线路,而是借用了公共 Intemet网络实现. 图解 备注

C语言每日一题之No4.

这几天老大也没安排我什么项目,于是想正好趁着空补C.当然,是利用晚上加班时间,白天正常上班时间还是学习公司的平台. 今儿个突然弱弱的感觉到在公司补C是件很低级的事情,哪怕是在加班时间都会被喷,因为大家在关心Linux玩得顺溜不顺溜的情况下,我在补C,万恶的C.想想也是,这种最最基础的C语言只能自己挤出时间来补了,在公司最起码也得学点高端点的,比如Linux,如果作为一个软件开发人员,你不会Linux还搞毛线啊? 好吧,工作一天了,今日吐槽完毕,人生因吐槽而舒畅爽快 ,神一样的存在.此时此刻就是回

C语言每日一题之No.8

正式面对自己第二天,突然一种强烈的要放弃的冲动,在害怕什么?害怕很难赶上步伐?害怕这样坚持到底是对还是错?估计是今天那个来了,所以身体激素有变化导致情绪起伏比较大比较神经质吧(☆_☆)~矮油,女人每个月总有这么几天的....晚上闺蜜打电话来,共同探讨了作为单身女性身在一线城市的生活,互相安慰互相关心,心里一下子就温暖了许多.总在这个时候,你会觉得,这个冷静的城市里你不是一个人在行走,还有另一颗心牵挂着你.嘿嘿,回来该学习还学习.现在不管坚持是对的还是错的,你都踏上了研发这条不归路,那就一条黑走到