• 快速生成千万条mysql数据

    目的

    学习、测试mysql大数据场景,需要先生成大量数据。

    思路

    mysql官方文档说得很清楚。"load data infile"导入数据比insert要快20倍。所以我们先生成一千万条数据的文件。 然后将数据导入表中。

    生成数据

    假如有个用户表(id, username,password, age, sex),id是自动增长,我们现在需要生成username等信息 生成一千万条数据,速度还能接受,耗时236秒,文件大小315M。

    import string
    import random
    
    def random_str(length=1):
        template = string.letters + string.digits
        chars = random.sample(template, length)
        return "".join(chars)
    
    def generate_record():
        """
        username/password/age/sex
        """
        length = random.randint(6, 20)
        username = random_str(length)
    
        length = random.randint(6, 20)
        password = random_str(length)
    
        age = random.randint(10, 100)
        sex = random.choice([0, 1])
        return [username, password, age, sex]
    
    def create_file(num=10000000):
        with open("user_data.txt", "w") as f:
            for i in range(num):
                row = generate_record()
                f.write(",".join(map(str, row))+"\n")
    
    if __name__ == '__main__':
        import datetime
        start = datetime.datetime.now()
        create_file()
        end = datetime.datetime.now()
        cost = (end -start).total_seconds()
        print("cost: %s" % cost)
    #一千万条,耗时236s,文件315M
    

    导入

    load data infile命令有安全限制,最好是把数据拿到mysql server端,再通过mysql -uxxx -pxxx进入命令,再导入。 我的虚拟机导入耗时57秒

    load data infile "/user_data.txt" into table user
    fields terminated by ','
    lines terminated by '\n'
    (username, password, age, sex);
    

    其它方式

    • 测试工具sysbench sysbench是批量insert,性能比不上导入。但是它更接近实际场景

    • 存储过程 速度很快,但是不如用熟悉的脚本方便

  • 如何判断类是类

    在写动态加载时,通常需要过滤出需要的类。如何从模块中过滤出其中的类呢?

    • 判断a是类A的实例
    isinstance(a, A)
    
    • 判断B类是A的子类
    issubclass(B, A)
    
    • 判断A是一个类
    isinstance(A, type)
    
    • 判断B是类并且是A的子类
    isinstance(B, type) and issubclass(B, A)
    
  • python中如何防止sql注入

    python访问数据库的底层库很多,以pymysql为例, 它在执行sql前,会对sql中的特殊字符进行转义,如

    • 字符转义
    def escape_string(value, mapping=None):
        """escape_string escapes *value* but not surround it with quotes.
    
        Value should be bytes or unicode.
        """
        if isinstance(value, unicode):
            return _escape_unicode(value)
        assert isinstance(value, (bytes, bytearray))
        value = value.replace('\\', '\\\\')
        value = value.replace('\0', '\\0')
        value = value.replace('\n', '\\n')
        value = value.replace('\r', '\\r')
        value = value.replace('\032', '\\Z')
        value = value.replace("'", "\\'")
        value = value.replace('"', '\\"')
        return value
    
    • 执行sql的正确方法,不要在sql中拼接参数,字符转义只会针对参数args
    # query作为sql模板,args为将要传入的参数
    execute(query, args=None)
    
    • django/sqlalchemy

    orm框架都是使用pymysql/MySQL-python等库,并且都使用execute(query,args)调用,将sql与参数分开传入。

    • sql注入检测工具

    sqlmap

  • docker容器中不能ping

    • 描述

    进入容器内,执行ping命令,提示缺少权限

    docker exec -it deac /bin/bash
    bash-4.3$ ping 192.168.1.100
    PING 192.168.1.100 (192.168.10.100): 56 data bytes
    ping: permission denied (are you root?)
    ``
    
    * 首先,查看当前用户
    
    ```bash
    bash-4.3$ whoami
    jenkins
    
    • 然后,再看看文件权限

    缺少权限创建socket

    # 查看ping权限
    bash-4.3# ls -lsh /bin/ping
    0 lrwxrwxrwx 1 root root 12 May  9  2017 /bin/ping -> /bin/busybox
    
    #查看ping连接文件的权限
    bash-4.3$ ls -lhs /bin/busybox
    804K -rwr-xr-x 1 root root 803K Oct 26  2016 /bin/busybox
    
    • 方法一,临时方式,以root用户登录
    docker exec -u root -it deac /bin/bash
    
    • 方法二,永久,添加s权限
    #添加权限
    chmod u+s /bin/ping  # 让用户在执行ping时,暂时拥有权限
    
    #再查看权限
    bash-4.3$ ls -lsh /bin/busybox
    804K -rwsr-xr-x 1 root root 803K Oct 26  2016 /bin/busybox
    
  • docker基础镜像怎么选?

    先看看基础镜像的dockerfile,它们是怎么创建出来的。

    • scratch (空镜像)

    • alpine

    FROM scratch
    ADD rootfs.tar.xz /
    CMD ["/bin/sh"]
    
    • debian
    FROM scratch
    ADD rootfs.tar.xz /
    CMD ["bash"]
    
    • centos/fedora/ubuntu
    FROM scratch
    ADD centos-7.4.1708-docker.tar.xz /
    
    LABEL name="CentOS Base Image" \
        vendor="CentOS" \
        license="GPLv2" \
        build-date="20170911"
    
    CMD ["/bin/bash"]
    
    • 建议

    docker是容器不同于虚拟机,运行之后只有应用程序在里面运行,基础镜像只是为应用程序提供依赖包。应用程序是主,基础镜像是次。

    如果没有必要,选择最小的依赖环境alpine,然后在这个基础上制作自己的镜像。

    如果是redis,选择redis+alpine

  • 同时管理git与svn两种仓库

    如果开发环境使用git仓库,正式环境使用svn仓库。如何将管理有种仓库的代码呢? 幸好git与svn有一个桥接工具git-svn,可以将两种仓库衔接起来,用不同分支进行管理。

    下面以将git代码,并入svn仓库为例

    • 首先从svn仓库克隆代码
    git svn int http://ip/svn/demo/trunk  demo
    git svn fetch -r HEAD
    
    • 添加git仓库地址
    cd demo
    git remote add git  http://ip/path/demo.git
    
    • 获取git仓库的分支
    git fetch git master    #获取git仓库的master分支
    git fetch git 1.0       #获取git仓库的1.0分支
    git fetch git           #获取所有git分支
    
    • 此时本地git的分支情况
    ➜  demo git:(master) git branch -a
    * master              #默认对应svn
      remotes/git-svn     #分支svn
      remotes/git/1.0     #远程git的1.0分支
      remotes/git/master  #远程git的master分支
    
    • 将git代码合并到svn分支
    git merge  git-master
    
    • 更新并提交
    git svn rebase
    git svn dcommit
    
  • subprocess.Popen(cmd)包含中文怎么办

    在windows中通过subprocess调用cmd命令行,命令中包含中文是很令人头痛的事。

    由于cmd控制台用的是gbk编码,而python用的是utf-8。utf-8的字符串,在gbk编码的控制台上运行,当然会运行不了。

    假如再要你兼容繁体版的windows,此时更麻烦了。还好python提供了本地化接口

    • 本地化
    >>> import locale
    >>> locale.getdefaultlocale()
    ('zh_CN', 'cp936')
    
    • 示例
    import locale
    cmd = cmd.encode(locale.getdefaultlocale()[1])
    subprocess.Popen(cmd)
    
  • 32位python在windows中os.system返回码一直为0

    32位python在windows上调用命令行(os.system或subprocess.Popen)。执行后,如果返回码太大,python取得的返回值也是0。 此时无法判断执行成功还是失败,这个是32位python的bug。

    以时间同步命令w32tm位例子

    • 在命令上执行
    C:\WINDOWS\system32>w32tm /resync
    发生下列错误: 服务尚未启动。 (0x80070426)
    
    C:\WINDOWS\system32>echo %errorlevel%
    -2147023834
    
    • 在64位python上执行
    >>> os.system("w32tm /resync")
    发生下列错误: 服务尚未启动。 (0x80070426)
    -2147023834
    
    • 在32位python上执行
    >>> os.system("w32tm /resync")
    发生下列错误: 服务尚未启动。 (0x80070426)
    0
    

    注意:此时命令执行错误返回码也是0。 通常成功的返回码才是0,这里执行错误返回码也是0。当要判断执行成功还失败时,这里便是个坑。

    • os.system文档 https://docs.python.org/2/library/os.html
  • angluarjs+django出现http 403(Forbidden)错误

    • angularjs向django提交post请求,出现http 403错误
    Forbidden (CSRF cookie not set.): /user/add/
    [15/Feb/2016 02:05:24] "POST /user/add/ HTTP/1.1" 403 2629
    
    • 发送post请求代码
    myModule.factory('user', function($resource) {
        return $resource('user', null,{
                add: {method:'POST', "/user/add/"}
        });
    });
    
    function ($scope, user) {
        user.add($scope.project, function (success) {
                console.log('success');
            },
            function (error) {
                console.log('error');
            });
    }
    
    • 解决方法
    var app = angular.module('yourApp');
    app.config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.xsrfCookieName = 'csrftoken';
        $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
    }]);
    
    • 官方参考文档
    http://docs.angularjs.cn/api/ng/provider/$httpProvider
    
  • apscheduler提示maximum错误

    起因

    在tornado中用apscheduler实现计划任务,出现错误提示

    2015-12-04 19:10:22,227 - apscheduler.scheduler - WARNING - Execution of job "TaskHandle.progress_job (trigger: date[2015-12-04 19:10:22 CST], next run at: 2015-12-04 19:10:22 CST)" skipped: maximum number of running instances reached (1)
    

    分析

    缺乏资料,所以根据提示,分析apscheduler源码

    • 记录异常位置

    在源码目录下,搜索关键字maxinum,找到记录异常的位置

    #apscheduler/schedulers/base.py
    if run_times:
        try:
            executor.submit_job(job, run_times)
        except MaxInstancesReachedError:
            self._logger.warning(
                'Execution of job "%s" skipped: maximum number of running instances reached (%d)',
                job, job.max_instances)
        except:
            self._logger.exception('Error submitting job "%s" to executor "%s"', job, job.executor)
    
    • 异常抛出位置

    继续看submit_job函数,找到异常抛出位置

    #apscheduler/executors/base.py
    def submit_job(self, job, run_times):
        """
        Submits job for execution.
    
        :param Job job: job to execute
        :param list[datetime] run_times: list of datetimes specifying when the job should have been run
        :raises MaxInstancesReachedError: if the maximum number of allowed instances for this job has been reached
        """
    
        assert self._lock is not None, 'This executor has not been started yet'
        with self._lock:
            if self._instances[job.id] >= job.max_instances:
                raise MaxInstancesReachedError(job)
    
            self._do_submit_job(job, run_times)
            self._instances[job.id] += 1
    
    • _instances变量作用

    在submit_job(提交任务)时加1,在_run_job_success(任务运行成功)时减1。 当self._instances[job.id]大于job.max_instances抛出异常。 max_instances默认值为1,它表示id相同的任务实例数。

    解决

    设置max_instances参数

    sched.add_job(child_job, max_instances=10, trigger=DateTrigger(), id="123")
    

    重现脚本

    import time
    import tornado.ioloop
    from apscheduler.triggers.date import DateTrigger
    from apscheduler.schedulers.tornado import TornadoScheduler
    
    sched = TornadoScheduler()
    
    def child_job():
        print "start"
        time.sleep(60)
        print "end"
    
    def main_job():
        sched.add_job(child_job, trigger=DateTrigger(), id="123")
    
    sched.add_job(main_job, 'interval', seconds=5)
    
    sched.start()
    tornado.ioloop.IOLoop.instance().start()
    
    
    • 输出 job_id: 7279209ab6c2498698f2117bb97e18a1, instances: 0, max_instances: 1 job_id: 123, instances: 0, max_instances: 1 start job_id: 7279209ab6c2498698f2117bb97e18a1, instances: 0, max_instances: 1 job_id: 123, instances: 1, max_instances: 1 WARNING:apscheduler.scheduler:Execution of job "child_job (trigger: date[2015-12-07 15:27:11 CST], next run at: 2015-12-07 15:27:11 CST)" skipped: maximum number of running instances reached (1) job_id: 7279209ab6c2498698f2117bb97e18a1, instances: 0, max_instances: 1