作者: Mr.Li

  • MONGODB原子操作常用命令,如:$set,$unset,$inc

    原子操作常用命令

    $set

    用来指定一个键并更新键值,若键不存在并创建。

    { $set : { field : value } }

    $unset

    用来删除一个键。

    { $unset : { field : 1} }

    $inc

    $inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。

    { $inc : { field : value } }
    
    实战实例:
    1.Update update = new Update();
    2.mongoTemplate.upsert(query, update.inc("count", 1), User.class);
    
    Yii 2 MongonDB 实战
    XXXXX::updateAll(['$inc'=>['count'=> $num]],[条件]);
    

    $push

    用法:

    { $push : { field : value } }

    把value追加到field里面去,field一定要是数组类型才行,如果field不存在,会新增一个数组类型加进去。

    $pushAll

    同$push,只是一次可以追加多个值到一个数组字段内。

    { $pushAll : { field : value_array } }

    $pull

    从数组field内删除一个等于value值。

    { $pull : { field : _value } }

    $addToSet

    增加一个值到数组内,而且只有当这个值不在数组内才增加。

    $pop

    删除数组的第一个或最后一个元素

    { $pop : { field : 1 } }

    $rename

    修改字段名称

    { $rename : { old_field_name : new_field_name } }

    $bit

    位操作,integer类型

    {$bit : { field : {and : 5}}}

    偏移操作符

    > t.find() { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 3 }, { "by" : "jane", "votes" : 7 } ] }
     
    > t.update( {'comments.by':'joe'}, {$inc:{'comments.$.votes':1}}, false, true )
     
    > t.find() { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 4 }, { "by" : "jane", "votes" : 7 } ] }
  • PHP数字补零的两种方法

    在php中有两个函数——至少有两个是否有其他的我还不知道,能够实现数字补零,str_pad(),sprintf()详细如下

    str_pad

    顾名思义这个函数是针对字符串来说的这个可以对指定的字符串填补任何其它的字符串

    例如:str_pad(带填补的字符串,填补后的长度,填补字符串,填补位置)

    其中填补后的长度必须是个正整数,填补位置有三个选项,

    左边:STR_PAD_LEFT,

    右边:STR_PAD_RIGHT,

    两端:STR_PAD_BOTH

    例如:

    1

    echo str_pad(1,8,"0",STR_PAD_LEFT);

    结果:00000001

    1

    echo str_pad(1,8,"0",STR_PAD_RIGHT);

    结果:10000000

    1

    echo str_pad(1,8,"0",STR_PAD_BOTH);

    结果:00010000

    在上边的例子中值得注意的一个细节是,如果填补的位数是个奇数,例如例三中填补了7个0,右边优先。

    再看补零的另外一种方法sprintf

    这个函数学过c的都十分了解它,呵呵……

    不过咱不说这么多,因为用起来实在太灵活了,以至于我基本不会用,不过在左边补零(或者在小数点后补零)用起来还是很方便的

    先看左边补零

    1

    echo sprintf("%05d",1);

    先说%05d的意思,用一个5位数的数字格式化后边的参数,如果不足5位就补零

    运行结果是00005

    再看小数点后补零

    1

    echo sprintf("%01.3f",1);

    %01.3f的意思是说,用一个小数点后最少三位不足三位补零,小数点前最少一位,不足一位补零的浮点数格式化后边的参数

    其运行结果是:1.000

    关于补零的这两种方法大家可以挑选着使用,其实各有优劣,sprintf能够保证你不至于误操作吧1补成1000000哈哈,str_pad可以保证你想补啥补啥。

  • yii2.0中使用mongodb处理模糊查询

    场景:模糊查询名称
    分析:mongodb对与模糊的查询的实现是依赖正则
    解决:

    yii  $regex 它的值是不含 // 的正则字符串就好

    $conditions['tel'] = ['$regex' => $conditions['title']]; // ^$  

    php 原生

    $query=array("name"=>new MongoRegex("/.*”.$title.".*/i"));

    $db->find($query);

  • Yii2中MongoDB多字段分组汇总统计并分页

    $match = [
        '$match' => [
            'created_at'=>[
                '$gte'=>$strstarttime,
                '$lt'=>$strendtime
            ],
        ]
    ];


    $issuesrescount = Issue::getCollection()->aggregate([
        $match,
        [
            '$group'=>[
                '_id'=>[‘raise_org’=>’$raise_org’],
                'count'=>[
                    '$sum'=>1
                ]
            ],
        ]
    ]);
    $itemcount = $issuesrescount[0][‘count’];
    $issuesres = Issue::getCollection()->aggregate([
        $match,
        [
            '$group'=>[
                '_id'=>[‘raise_org’=>’$raise_org’], //通过user_id分组去重
                'product'=>[
                    '$push'=>'$product'
                ],
                'qtype'=>[
                    '$push'=>'$qtype'
                ],
                'count'=>[
                    '$sum'=>1
                ],

            ],

        ],
        [‘$skip’=>(int)($page-1)*$pagesize],
        [‘$limit’=>(int)$pagesize],
        [
            '$sort'=>[
                'count'=>-1
            ]
        ]
    ]);

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

    本文链接:https://blog.csdn.net/weixin_40613168/article/details/108126263

  • Yii2中mongodb的聚合操作

    最近项目使用到mongodb的聚合操作,但是yii文档中对这方面资料较少,记录下

    $where[‘created_time’] = [‘$gt’ => “$start_date_str”, ‘$lte’ => “$end_date_str”];
            $where[‘token’] = [‘$ne’ => null];
            $where[‘app’] = $app;
            $where[‘source_type’] = $source_type;
            $loanmarket_info = Loanmarket::find()->asArray()->orderBy('created_time DESC')->all();
            if (!empty($keyword)) {
                $loanmarket_info = Loanmarket::find()->where([‘or’,[‘like’,’name’,$keyword],[‘like’,’number’,$keyword]])->asArray()->orderBy('created_time DESC')->all();
                $keyword_arr = array_reduce($loanmarket_info, function ($result, $value) {
                    return array_merge($result, array_values($value));
                }, array());
                if (!empty($keyword_arr)) {
                    $where[‘lm_number’] = [‘$in’ => $keyword_arr];
                }
            }

            $aggregate = [
                [‘$match’ => $where]    // 按照创建时间筛选,同时 token 不为空
                , [‘$group’ => [“_id” => [“lm_number” => ‘$lm_number’, “source_type” => ‘$source_type’, “app” => ‘$app’, “token” => ‘$token’]]]  // token 去重
                , [‘$group’ => [“_id” => [“lm_number” => ‘$_id.lm_number’, “source_type” => ‘$_id.source_type’, “app” => ‘$_id.app’], “COUNT(token)” => [‘$sum’ => 1]]]  // 统计UV
                , [‘$project’ => [“_id” => 0, “lm_number” => ‘$_id.lm_number’, “source_type” => ‘$_id.source_type’, “app” => ‘$_id.app’, “uv” => ‘$COUNT(token)’]] // 显示相应的字段
            ];

    //        $query = new \yii\mongodb\Query;
    //        $data_arr = $query->from([‘数据库名’,’数据表名’])->offset(3)->limit(5)->aggregate($aggregate);

            $data_arr = MongoBizEventReport::getCollection()->aggregate($aggregate);
     

    转载:https://www.cnblogs.com/two-bees/p/10483435.html

  • PhpStorm 默认快捷键

    PhpStorm 默认快捷键

    ctrl+j            插入活动代码提示

    ctrl+alt+t        当前位置插入环绕代码
    alt+insert        生成代码菜单
    Shift + Enter 新一行
    ctrl+q            查看代码注释
    ctrl+d            复制当前行
    ctrl+y            删除当前行

    ctrl+alt+y      刷新项目缓存Synchronize 或文件夹右键Synchronize 
    shift+F6          重命名
    ctrl+shift+u      字母大小写转换 
    ctrl+f            查找
    ctrl+r            替换
    ctrl+shift+I      查看变量或方法定义源
    ctrl+g            跳转行
    ctrl+alt+F12      跳转至当前文件在磁盘上的位置
    alt+down          查看下一个方法
    alt+up            查看上一个方法
    ctrl+alt+l        重新格式化代码 
    ctrl+shift+down   statement向下移动
    ctrl+shift+up     statement向上移动
    alt+shift+down    line向下移动
    alt+shift+up      line向上移动
    ctrl+/            行注释
    ctrl+shift+/      块注释

    Ctrl + Shift + Z:redo

    Ctrl + Shift + F:区域查找 
    ctrl+shift+n      打开工程中的文件
    ctrl+b            跳到变量申明处
    ctrl+[]           匹配 {}[]
    ctrl+shift+]/[    选中块代码<table>….</table>
    ctrl+x            剪切行
    ctrl+shift+v      复制多个文本 
    alt+left/right    标签切换
    ctrl+p            显示默认参数

    ctrl + '-/+': 可以折叠项目中的任何代码块

     

    苹果本本请将 ctrl 换为 command

  • 数据结构:八大数据结构分类

    数据结构分类

    数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成 。
    常用的数据结构有:数组,栈,链表,队列,树,图,堆,散列表等,如图所示:
    这里写图片描述
    每一种数据结构都有着独特的数据存储方式,下面为大家介绍它们的结构和优缺点。

    1、数组

    数组是可以再内存中连续存储多个元素的结构,在内存中的分配也是连续的,数组中的元素通过数组下标进行访问,数组下标从0开始。例如下面这段代码就是将数组的第一个元素赋值为 1。

    int[] data = new int[100];data[0]  = 1;
    
    • 1
    • 2

    优点:
    1、按照索引查询元素速度快
    2、按照索引遍历数组方便

    缺点:
    1、数组的大小固定后就无法扩容了
    2、数组只能存储一种类型的数据
    3、添加,删除的操作慢,因为要移动其他的元素。

    适用场景:
    频繁查询,对存储空间要求不大,很少增加和删除的情况。

    2、栈

    栈是一种特殊的线性表,仅能在线性表的一端操作,栈顶允许操作,栈底不允许操作。 栈的特点是:先进后出,或者说是后进先出,从栈顶放入元素的操作叫入栈,取出元素叫出栈。
    这里写图片描述
    栈的结构就像一个集装箱,越先放进去的东西越晚才能拿出来,所以,栈常应用于实现递归功能方面的场景,例如斐波那契数列。

    3、队列

    队列与栈一样,也是一种线性表,不同的是,队列可以在一端添加元素,在另一端取出元素,也就是:先进先出。从一端放入元素的操作称为入队,取出元素为出队,示例图如下:
    这里写图片描述
    使用场景:因为队列先进先出的特点,在多线程阻塞队列管理中非常适用。

    4、链表

    链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,每个元素包含两个结点,一个是存储元素的数据域 (内存空间),另一个是指向下一个结点地址的指针域。根据指针的指向,链表能形成不同的结构,例如单链表,双向链表,循环链表等。
    这里写图片描述
    链表的优点:
    链表是很常用的一种数据结构,不需要初始化容量,可以任意加减元素;
    添加或者删除元素时只需要改变前后两个元素结点的指针域指向地址即可,所以添加,删除很快;

    缺点:
    因为含有大量的指针域,占用空间较大;
    查找元素需要遍历链表来查找,非常耗时。

    适用场景:
    数据量较小,需要频繁增加,删除操作的场景

    5、树

    是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做 “树” 是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:

    • 每个节点有零个或多个子节点;
    • 没有父节点的节点称为根节点;
    • 每一个非根节点有且只有一个父节点;
    • 除了根节点外,每个子节点可以分为多个不相交的子树;

    在日常的应用中,我们讨论和用的更多的是树的其中一种结构,就是二叉树
    这里写图片描述
    二叉树是树的特殊一种,具有如下特点:

    1、每个结点最多有两颗子树,结点的度最大为2。
    2、左子树和右子树是有顺序的,次序不能颠倒。
    3、即使某结点只有一个子树,也要区分左右子树。

    二叉树是一种比较有用的折中方案,它添加,删除元素都很快,并且在查找方面也有很多的算法优化,所以,二叉树既有链表的好处,也有数组的好处,是两者的优化方案,在处理大批量的动态数据方面非常有用。

    扩展:
    二叉树有很多扩展的数据结构,包括平衡二叉树、红黑树、B+树等,这些数据结构二叉树的基础上衍生了很多的功能,在实际应用中广泛用到,例如mysql的数据库索引结构用的就是B+树,还有HashMap的底层源码中用到了红黑树。这些二叉树的功能强大,但算法上比较复杂,想学习的话还是需要花时间去深入的。

    6、散列表

    散列表,也叫哈希表,是根据关键码和值 (key和value) 直接进行访问的数据结构,通过key和value来映射到集合中的一个位置,这样就可以很快找到集合中的对应元素。

    记录的存储位置=f(key)

    这里的对应关系 f 成为散列函数,又称为哈希 (hash函数),而散列表就是把Key通过一个固定的算法函数既所谓的哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的下标,将value存储在以该数字为下标的数组空间里,这种存储空间可以充分利用数组的查找优势来查找元素,所以查找的速度很快。

    哈希表在应用中也是比较常见的,就如Java中有些集合类就是借鉴了哈希原理构造的,例如HashMap,HashTable等,利用hash表的优势,对于集合的查找元素时非常方便的,然而,因为哈希表是基于数组衍生的数据结构,在添加删除元素方面是比较慢的,所以很多时候需要用到一种数组链表来做,也就是拉链法。拉链法是数组结合链表的一种结构,较早前的hashMap底层的存储就是采用这种结构,直到jdk1.8之后才换成了数组加红黑树的结构,其示例图如下:
    这里写图片描述
    从图中可以看出,左边很明显是个数组,数组的每个成员包括一个指针,指向一个链表的头,当然这个链表可能为空,也可能元素很多。我们根据元素的一些特征把元素分配到不同的链表中去,也是根据这些特征,找到正确的链表,再从链表中找出这个元素。

    哈希表的应用场景很多,当然也有很多问题要考虑,比如哈希冲突的问题,如果处理的不好会浪费大量的时间,导致应用崩溃。

    7、堆

    堆是一种比较特殊的数据结构,可以被看做一棵树的数组对象,具有以下的性质:

    • 堆中某个节点的值总是不大于或不小于其父节点的值;

    • 堆总是一棵完全二叉树。

    将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。

    堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。
    (ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4…n/2),满足前者的表达式的成为小顶堆,满足后者表达式的为大顶堆,这两者的结构图可以用完全二叉树排列出来,示例图如下:
    这里写图片描述
    因为堆有序的特点,一般用来做数组中的排序,称为堆排序。

    8、图

    图是由结点的有穷集合V和边的集合E组成。其中,为了与树形结构加以区别,在图结构中常常将结点称为顶点,边是顶点的有序偶对,若两个顶点之间存在一条边,就表示这两个顶点具有相邻关系。

    按照顶点指向的方向可分为无向图和有向图:
    这里写图片描述
    这里写图片描述
    图是一种比较复杂的数据结构,在存储数据上有着比较复杂和高效的算法,分别有邻接矩阵 、邻接表、十字链表、邻接多重表、边集数组等存储结构,这里不做展开,读者有兴趣可以自己学习深入。

    原文链接:https://blog.csdn.net/yeyazhishang/article/details/82353846

  • 什么是数据库索引

    大家平时在开发过程中都避免不了使用数据库索引,那么你了解数据库索引么,接下来呢,我就简单讲一下什么是数据库索引。

    一、数据索引是干什么用的呢?

    数据库索引其实就是为了使查询数据效率快。

    二、数据库索引有哪些呢?

    1. 聚集索引(主键索引):在数据库里面,所有行数都会按照主键索引进行排序。
    2. 非聚集索引:就是给普通字段加上索引。
    3. 联合索引:就是好几个字段组成的索引,称为联合索引。

    1

    key 'idx_age_name_sex' ('age','name','sex')

     联合索引遵从最左前缀原则,什么意思呢,就比如说一张学生表里面的联合索引如上面所示,那么下面A,B,C,D,E,F哪个会走索引呢?

    1

    2

    3

    4

    A:select * from student where age = 16 and name = '小张'

    B:select * from student where name = '小张' and sex = '男'

    C:select * from student where name = '小张' and sex = '男' and age = 18

    D:select * from student where age > 20 and name = '小张'<br>E:select * from student where age != 15 and name = '小张'<br>F:select * from student where age = 15 and name != '小张'

     A遵从最左匹配原则,age是在最左边,所以A走索引;

     B直接从name开始,没有遵从最左匹配原则,所以不走索引;

     C虽然从name开始,但是有索引最左边的age,mysql内部会自动转成where age = '18' and name = '小张'  and sex = '男' 这种,所以还是遵从最左匹配原则;

     D这个是因为age>20是范围,范围字段会结束索引对范围后面索引字段的使用,所以只有走了age这个索引;

     E这个虽然遵循最左匹配原则,但是不走索引,因为!= 不走索引;

     F这个只走age索引,不走name索引,原因如上;

    三、有哪些列子不走索引呢?

     表student中两个字段age,name加了索引

    1

    2

    key 'idx_age' ('age'),

    key 'idx_name' ('name')

       1.Like这种就是%在前面的不走索引,在后面的走索引

    1

    2

    A:select * from student where 'name' like '王%'

    B:select * from student where 'name' like '%小'

      A走索引,B不走索引

      2.用索引列进行计算的,不走索引

    1

    2

    A:select * from student where age = 10+8

    B:select * from student where age + 8 18

     A走索引,B不走索引

     3.对索引列用函数了,不走索引

    1

    2

    A:select * from student where  concat('name','哈') ='王哈哈';

    B:select * from student where name = concat('王哈','哈');

     A不走索引,B走索引

     4. 索引列用了!= 不走索引,如下:

    1

    select * from student where age != 18

     四、为什么索引用B+树?

      这个可以参考什么是B+树

    五、索引在磁盘上的存储?

     聚集索引和非聚集索引存储的不相同,那么来说下都是怎么存储的?

     有一张学生表

    create table `student` (
    `id` int(11) not null auto_increment comment '主键id',
    `name` varchar(50) not null default '' comment '学生姓名',
    `age` int(11) not null default 0 comment '学生年龄',
    primary key (`id`),
    key `idx_age` (`age`),
    key `idx_name` (`name`)
    ) ENGINE=InnoDB default charset=utf8 comment ='学生信息';

      表中内容如下

    id 为主键索引,name和age为非聚集索引

    1.聚集索引在磁盘中的存储

     聚集索引叶子结点存储是表里面的所有行数据;

     每个数据页在不同的磁盘上面;

    如果要查找id=5的数据,那么先把磁盘0读入内存,然后用二分法查找id=5的数在3和6之间,然后通过指针p1查找到磁盘2的地址,然后将磁盘2读入内存中,用二分查找方式查找到id=5的数据。

    2.非聚集索引在磁盘中的存储

    叶子结点存储的是聚集索引键,而不存储表里面所有的行数据,所以在查找的时候,只能查找到聚集索引键,再通过聚集索引去表里面查找到数据。

    如果要查找到name = 小徐,首先将磁盘0加载到内存中,然后用二分查找的方法查到在指针p1所指的地址上,然后通过指针p1所指的地址可知道在磁盘2上面,然后通过二分查找法得知小徐id=4;

    然后在根据id=4将磁盘0加载到内存中,然后通过二分查找的方法查到在指针p1所指的地址上,然后通过指针p1所指的地址可知道在磁盘2上面,然后通过id=4查找出郑正行数据,就查找出name=小徐的数据了。

  • Supervisor使用详解

    一、supervisor简介

    Supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启。它是通过fork/exec的方式把这些被管理的进程当作supervisor的子进程来启动,这样只要在supervisor的配置文件中,把要管理的进程的可执行文件的路径写进去即可。也实现当子进程挂掉的时候,父进程可以准确获取子进程挂掉的信息的,可以选择是否自己启动和报警。supervisor还提供了一个功能,可以为supervisord或者每个子进程,设置一个非root的user,这个user就可以管理它对应的进程。

    注:本文以centos7为例,supervisor版本3.4.0。

    二、supervisor安装

    1. 配置好yum源后,可以直接安装

      yum install supervisor
      

    2. Debian/Ubuntu可通过apt安装

      apt-get install supervisor
      

    3. pip安装

      pip install supervisor
      

    4. easy_install安装

      easy_install supervisor
      

    三、supervisor使用

    supervisor配置文件:/etc/supervisord.conf

    注:supervisor的配置文件默认是不全的,不过在大部分默认的情况下,上面说的基本功能已经满足。

    子进程配置文件路径:/etc/supervisord.d/

    注:默认子进程配置文件为ini格式,可在supervisor主配置文件中修改。

    四、配置文件说明

    supervisor.conf配置文件说明:

    [unix_http_server]
    file=/tmp/supervisor.sock   ;UNIX socket 文件,supervisorctl 会使用
    ;chmod=0700                 ;socket文件的mode,默认是0700
    ;chown=nobody:nogroup       ;socket文件的owner,格式:uid:gid
     
    ;[inet_http_server]         ;HTTP服务器,提供web管理界面
    ;port=127.0.0.1:9001        ;Web管理后台运行的IP和端口,如果开放到公网,需要注意安全性
    ;username=user              ;登录管理后台的用户名
    ;password=123               ;登录管理后台的密码
     
    [supervisord]
    logfile=/tmp/supervisord.log ;日志文件,默认是 $CWD/supervisord.log
    logfile_maxbytes=50MB        ;日志文件大小,超出会rotate,默认 50MB,如果设成0,表示不限制大小
    logfile_backups=10           ;日志文件保留备份数量默认10,设为0表示不备份
    loglevel=info                ;日志级别,默认info,其它: debug,warn,trace
    pidfile=/tmp/supervisord.pid ;pid 文件
    nodaemon=false               ;是否在前台启动,默认是false,即以 daemon 的方式启动
    minfds=1024                  ;可以打开的文件描述符的最小值,默认 1024
    minprocs=200                 ;可以打开的进程数的最小值,默认 200
     
    [supervisorctl]
    serverurl=unix:///tmp/supervisor.sock ;通过UNIX socket连接supervisord,路径与unix_http_server部分的file一致
    ;serverurl=http://127.0.0.1:9001 ; 通过HTTP的方式连接supervisord
     
    ; [program:xx]是被管理的进程配置参数,xx是进程的名称
    [program:xx]
    command=/opt/apache-tomcat-8.0.35/bin/catalina.sh run  ; 程序启动命令
    autostart=true       ; 在supervisord启动的时候也自动启动
    startsecs=10         ; 启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒
    autorestart=true     ; 程序退出后自动重启,可选值:[unexpected,true,false],默认为unexpected,表示进程意外杀死后才重启
    startretries=3       ; 启动失败自动重试次数,默认是3
    user=tomcat          ; 用哪个用户启动进程,默认是root
    priority=999         ; 进程启动优先级,默认999,值小的优先启动
    redirect_stderr=true ;stderr重定向到stdout,默认false
    stdout_logfile_maxbytes=20MB  ; stdout 日志文件大小,默认50MB
    stdout_logfile_backups = 20   ; stdout 日志文件备份数,默认是10
    ; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
    stdout_logfile=/opt/apache-tomcat-8.0.35/logs/catalina.out
    stopasgroup=false     ;默认为false,进程被杀死时,是否向这个进程组发送stop信号,包括子进程
    killasgroup=false     ;默认为false,向进程组发送kill信号,包括子进程
     
    ;包含其它配置文件
    [include]
    files = relative/directory/*.ini    ;可以指定一个或多个以.ini结束的配置文件
    

    子进程配置文件说明:

    给需要管理的子进程(程序)编写一个配置文件,放在/etc/supervisor.d/目录下,以.ini作为扩展名(每个进程的配置文件都可以单独分拆也可以把相关的脚本放一起)。如任意定义一个和脚本相关的项目名称的选项组(/etc/supervisord.d/test.conf):

    #项目名
    [program:blog]
    #脚本目录
    directory=/opt/bin
    #脚本执行命令
    command=/usr/bin/python /opt/bin/test.py
    
    #supervisor启动的时候是否随着同时启动,默认True
    autostart=true
    #当程序exit的时候,这个program不会自动重启,默认unexpected,设置子进程挂掉后自动重启的情况,有三个选项,false,unexpected和true。如果为false的时候,无论什么情况下,都不会被重新启动,如果为unexpected,只有当进程的退出码不在下面的exitcodes里面定义的
    autorestart=false
    #这个选项是子进程启动多少秒之后,此时状态如果是running,则我们认为启动成功了。默认值为1
    startsecs=1
    
    #脚本运行的用户身份 
    user = test
    
    #日志输出 
    stderr_logfile=/tmp/blog_stderr.log 
    stdout_logfile=/tmp/blog_stdout.log 
    #把stderr重定向到stdout,默认 false
    redirect_stderr = true
    #stdout日志文件大小,默认 50MB
    stdout_logfile_maxbytes = 20MB
    #stdout日志文件备份数
    stdout_logfile_backups = 20
    

    子进程配置示例:

    #说明同上
    [program:test] 
    directory=/opt/bin 
    command=/opt/bin/test
    autostart=true 
    autorestart=false 
    stderr_logfile=/tmp/test_stderr.log 
    stdout_logfile=/tmp/test_stdout.log 
    #user = test  
    

    五、supervisor命令说明

    常用命令

    supervisorctl status        //查看所有进程的状态
    supervisorctl stop es       //停止es
    supervisorctl start es      //启动es
    supervisorctl restart       //重启es
    supervisorctl update        //配置文件修改后使用该命令加载新的配置
    supervisorctl reload        //重新启动配置中的所有程序
    

    注:把es换成all可以管理配置中的所有进程。直接输入supervisorctl进入supervisorctl的shell交互界面,此时上面的命令不带supervisorctl可直接使用。

    注意事项

    使用supervisor进程管理命令之前先启动supervisord,否则程序报错。
    使用命令supervisord -c /etc/supervisord.conf启动。
    若是centos7:

    systemctl start supervisord.service     //启动supervisor并加载默认配置文件
    systemctl enable supervisord.service    //将supervisor加入开机启动项
    

    常见问题
    1. unix:///var/run/supervisor.sock no such file
      问题描述:安装好supervisor没有开启服务直接使用supervisorctl报的错
      解决办法:supervisord -c /etc/supervisord.conf

    2. command中指定的进程已经起来,但supervisor还不断重启
      问题描述:command中启动方式为后台启动,导致识别不到pid,然后不断重启,这里使用的是elasticsearch,command指定的是$path/bin/elasticsearch -d
      解决办法:supervisor无法检测后台启动进程的pid,而supervisor本身就是后台启动守护进程,因此不用担心这个

    3. 启动了多个supervisord服务,导致无法正常关闭服务
      问题描述:在运行supervisord -c /etc/supervisord.conf之前,直接运行过supervisord -c /etc/supervisord.d/xx.conf导致有些进程被多个superviord管理,无法正常关闭进程。
      解决办法:使用ps -fe | grep supervisord查看所有启动过的supervisord服务,kill相关的进程。

    文章来源:https://www.jianshu.com/p/0b9054b33db3
  • Linux定时任务Crontab命令详解

    linux 系统则是由 cron (crond) 这个系统服务来控制的。Linux 系统上面原本就有非常多的计划性工作,因此这个系统服务是默认启动的。另 外, 由于使用者自己也可以设置计划任务,所以, Linux 系统也提供了使用者控制计划任务的命令 :crontab 命令。

    一、crond简介

    crond 是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务 工具,并且会自动启动crond进程,crond进程每分钟会定期检查是否有要执行的任务,如果有要执行的任务,则自动执行该任务。

    Linux下的任务调度分为两类,系统任务调度和用户任务调度。

    系统任务调度:系统周期性所要执行的工作,比如写缓存数据到硬盘、日志清理等。在/etc目录下有一个crontab文件,这个就是系统任务调度的配置文件。

    /etc/crontab文件包括下面几行:

    cat /etc/crontab

    SHELL=/bin/bash

    PATH=/sbin:/bin:/usr/sbin:/usr/bin

    MAILTO=HOME=/

    # run-parts

    51 * * * * root run-parts /etc/cron.hourly

    24 7 * * * root run-parts /etc/cron.daily

    22 4 * * 0 root run-parts /etc/cron.weekly

    42 4 1 * * root run-parts /etc/cron.monthly


    前 四行是用来配置crond任务运行的环境变量,第一行SHELL变量指定了系统要使用哪个shell,这里是bash,第二行PATH变量指定了系统执行 命令的路径,第三行MAILTO变量指定了crond的任务执行信息将通过电子邮件发送给root用户,如果MAILTO变量的值为空,则表示不发送任务 执行信息给用户,第四行的HOME变量指定了在执行命令或者脚本时使用的主目录。第六至九行表示的含义将在下个小节详细讲述。这里不在多说。

    用户任务调度:用户定期要执行的工作,比如用户数据备份、定时邮件提醒等。用户可以使用 crontab 工具来定制自己的计划任务。所有用户定义的crontab 文件都被保存在 /var/spool/cron目录中。其文件名与用户名一致。

    使用者权限文件:

    文件:

    /etc/cron.deny

    说明:

    该文件中所列用户不允许使用crontab命令

    文件:

    /etc/cron.allow

    说明:

    该文件中所列用户允许使用crontab命令

    文件:

    /var/spool/cron/

    说明:

    所有用户crontab文件存放的目录,以用户名命名

    crontab文件的含义:

    用户所建立的crontab文件中,每一行都代表一项任务,每行的每个字段代表一项设置,它的格式共分为六个字段,前五段是时间设定段,第六段是要执行的命令段,格式如下:

    minute hour day month week command

    其中:

    minute: 表示分钟,可以是从0到59之间的任何整数。

    hour:表示小时,可以是从0到23之间的任何整数。

    day:表示日期,可以是从1到31之间的任何整数。

    month:表示月份,可以是从1到12之间的任何整数。

    week:表示星期几,可以是从0到7之间的任何整数,这里的0或7代表星期日。

    command:要执行的命令,可以是系统命令,也可以是自己编写的脚本文件。

    在以上各个字段中,还可以使用以下特殊字符:

    星号(*):代表所有可能的值,例如month字段如果是星号,则表示在满足其它字段的制约条件后每月都执行该命令操作。

    逗号(,):可以用逗号隔开的值指定一个列表范围,例如,“1,2,5,7,8,9”

    中杠(-):可以用整数之间的中杠表示一个整数范围,例如“2-6”表示“2,3,4,5,6”

    正斜线(/):可以用正斜线指定时间的间隔频率,例如“0-23/2”表示每两小时执行一次。同时正斜线可以和星号一起使用,例如*/10,如果用在minute字段,表示每十分钟执行一次。

    二、crond服务

    安装crontab:

    yum install crontabs

    服务操作说明:

    /sbin/service crond start //启动服务

    /sbin/service crond stop //关闭服务

    /sbin/service crond restart //重启服务

    /sbin/service crond reload //重新载入配置

    /sbin/service crond status //启动服务


    查看crontab服务是否已设置为开机启动,执行命令:

    ntsysv

    加入开机自动启动:

    chkconfig –level 35 crond on

    三、crontab命令详解

    1.命令格式:

    crontab [-u user] file

    crontab [-u user] [ -e | -l | -r ]

    2.命令功能:

    通过crontab 命令,我们可以在固定的间隔时间执行指定的系统指令或 shell script脚本。时间间隔的单位可以是分钟、小时、日、月、周及以上的任意组合。这个命令非常设合周期性的日志分析或数据备份等工作。

    3.命令参数:

    -u user:用来设定某个用户的crontab服务,例如,“-u ixdba”表示设定ixdba用户的crontab服务,此参数一般有root用户来运行。

    file:file是命令文件的名字,表示将file做为crontab的任务列表文件并载入crontab。如果在命令行中没有指定这个文件,crontab命令将接受标准输入(键盘)上键入的命令,并将它们载入crontab。

    -e:编辑某个用户的crontab文件内容。如果不指定用户,则表示编辑当前用户的crontab文件。

    -l:显示某个用户的crontab文件内容,如果不指定用户,则表示显示当前用户的crontab文件内容。

    -r:从/var/spool/cron目录中删除某个用户的crontab文件,如果不指定用户,则默认删除当前用户的crontab文件。

    -i:在删除用户的crontab文件时给确认提示。

    4.常用方法:

    1). 创建一个新的crontab文件

    在 考虑向cron进程提交一个crontab文件之前,首先要做的一件事情就是设置环境变量EDITOR。cron进程根据它来确定使用哪个编辑器编辑 crontab文件。9 9 %的UNIX和LINUX用户都使用vi,如果你也是这样,那么你就编辑$ HOME目录下的. profile文件,在其 中加入这样一行:

    EDITOR=vi; export EDITOR

    然后保存并退出。不妨创建一个名为<user> cron的文件,其中<user>是用户名,例如, davecron。在该文件中加入如下的内容。

    # (put your own initials here)echo the date to the console every

    # 15minutes between 6pm and 6am

    0,15,30,45 18-06 * * * /bin/echo ‘date’ > /dev/console

    保存并退出。确信前面5个域用空格分隔。

    在 上面的例子中,系统将每隔1 5分钟向控制台输出一次当前时间。如果系统崩溃或挂起,从最后所显示的时间就可以一眼看出系统是什么时间停止工作的。在有些 系统中,用tty1来表示控制台,可以根据实际情况对上面的例子进行相应的修改。为了提交你刚刚创建的crontab文件,可以把这个新创建的文件作为 cron命令的参数:

    $ crontab davecron

    现在该文件已经提交给cron进程,它将每隔1 5分钟运行一次。

    同时,新创建文件的一个副本已经被放在/var/spool/cron目录中,文件名就是用户名(即dave)。

    2). 列出crontab文件

    为了列出crontab文件,可以用:

    $ crontab -l

    0,15,30,45,18-06 * * * /bin/echo `date` > dev/tty1

    你将会看到和上面类似的内容。可以使用这种方法在$ H O M E目录中对crontab文件做一备份:

    $ crontab -l > $HOME/mycron

    这样,一旦不小心误删了crontab文件,可以用上一节所讲述的方法迅速恢复。

    3). 编辑crontab文件

    如果希望添加、删除或编辑crontab文件中的条目,而E D I TO R环境变量又设置为v i,那么就可以用v i来编辑crontab文件,相应的命令为:

    $ crontab -e

    可以像使用v i编辑其他任何文件那样修改crontab文件并退出。如果修改了某些条目或添加了新的条目,那么在保存该文件时, c r o n会对其进行必要的完整性检查。如果其中的某个域出现了超出允许范围的值,它会提示你。

    我们在编辑crontab文件时,没准会加入新的条目。例如,加入下面的一条:

    # DT:delete core files,at 3.30am on 1,7,14,21,26,26 days of each month

    30 3 1,7,14,21,26 * * /bin/find -name “core’ -exec rm {} \;

    现在保存并退出。最好在crontab文件的每一个条目之上加入一条注释,这样就可以知道它的功能、运行时间,更为重要的是,知道这是哪位用户的作业。

    现在让我们使用前面讲过的crontab -l命令列出它的全部信息:

    $ crontab -l

    # (crondave installed on Tue May 4 13:07:43 1999)

    # DT:ech the date to the console every 30 minites

    0,15,30,45 18-06 * * * /bin/echo `date` > /dev/tty1

    # DT:delete core files,at 3.30am on 1,7,14,21,26,26 days of each month

    30 3 1,7,14,21,26 * * /bin/find -name “core’ -exec rm {} \;

    4). 删除crontab文件

    要删除crontab文件,可以用:

    $ crontab -r

    5). 恢复丢失的crontab文件

    如果不小心误删了crontab文件,假设你在自己的$ H O M E目录下还有一个备份,那么可以将其拷贝到/var/spool/cron/<username>,其中<username>是用户名。如果由于权限问题无法完成拷贝,可以用:

    $ crontab <filename>

    其中,<filename>是你在$ H O M E目录中副本的文件名。

    我建议你在自己的$ H O M E目录中保存一个该文件的副本。我就有过类似的经历,有数次误删了crontab文件(因为r键紧挨在e键的右边)。这就是为什么有些系统文档建议不要直接编辑crontab文件,而是编辑该文件的一个副本,然后重新提交新的文件。

    有些crontab的变体有些怪异,所以在使用crontab命令时要格外小心。如果遗漏了任何选项,crontab可能会打开一个空文件,或者看起来像是个空文件。这时敲delete键退出,不要按<Ctrl-D>,否则你将丢失crontab文件。

    5.使用实例

    实例1:每1分钟执行一次command
    命令:
    * * * * * command

    实例2:每小时的第3和第15分钟执行
    命令:
    3,15 * * * * command

    实例3:在上午8点到11点的第3和第15分钟执行
    命令:
    3,15 8-11 * * * command

    实例4:每隔两天的上午8点到11点的第3和第15分钟执行
    命令:
    3,15 8-11 */2 * * command

    实例5:每个星期一的上午8点到11点的第3和第15分钟执行
    命令:
    3,15 8-11 * * 1 command

    实例6:每晚的21:30重启smb
    命令:
    30 21 * * * /etc/init.d/smb restart


    实例7:每月1、10、22日的4 : 45重启smb
    命令:
    45 4 1,10,22 * * /etc/init.d/smb restart


    实例8:每周六、周日的1 : 10重启smb
    命令:
    10 1 * * 6,0 /etc/init.d/smb restart


    实例9:每天18 : 00至23 : 00之间每隔30分钟重启smb
    命令:
    0,30 18-23 * * * /etc/init.d/smb restart


    实例10:每星期六的晚上11 : 00 pm重启smb
    命令:
    0 23 * * 6 /etc/init.d/smb restart


    实例11:每一小时重启smb
    命令:
    * */1 * * * /etc/init.d/smb restart


    实例12:晚上11点到早上7点之间,每隔一小时重启smb
    命令:
    * 23-7/1 * * * /etc/init.d/smb restart

    实例13:每月的4号与每周一到周三的11点重启smb
    命令:
    0 11 4 * mon-wed /etc/init.d/smb restart

    实例14:一月一号的4点重启smb
    命令:
    0 4 1 jan * /etc/init.d/smb restart


    实例15:每小时执行/etc/cron.hourly目录内的脚本
    命令:
    01 * * * * root run-parts /etc/cron.hourly
    说明:
    run-parts这个参数了,如果去掉这个参数的话,后面就可以写要运行的某个脚本名,而不是目录名了


    四、使用注意事项

    注意环境变量问题
    有时我们创建了一个crontab,但是这个任务却无法自动执行,而手动执行这个任务却没有问题,这种情况一般是由于在crontab文件中没有配置环境变量引起的。

    在 crontab文件中定义多个调度任务时,需要特别注意的一个问题就是环境变量的设置,因为我们手动执行某个任务时,是在当前shell环境下进行的,程 序当然能找到环境变量,而系统自动执行任务调度时,是不会加载任何环境变量的,因此,就需要在crontab文件中指定任务运行所需的所有环境变量,这 样,系统执行任务调度时就没有问题了。

    不要假定cron知道所需要的特殊环境,它其实并不知道。所以你要保证在shelll脚本中提供所有必要的路径和环境变量,除了一些自动设置的全局变量。所以注意如下3点:

    1)脚本中涉及文件路径时写全局路径;

    2)脚本执行要用到java或其他环境变量时,通过source命令引入环境变量,如:

    cat start_cbp.sh

    #!/bin/sh

    source /etc/profile

    export RUN_CONF=/home/d139/conf/platform/cbp/cbp_jboss.conf

    /usr/local/jboss-4.0.5/bin/run.sh -c mev &

    3)当手动执行脚本OK,但是crontab死活不执行时。这时必须大胆怀疑是环境变量惹的祸,并可以尝试在crontab中直接引入环境变量解决问题。如:

    0 * * * * . /etc/profile;/bin/sh /var/www/java/audit_no_count/bin/restart_audit.sh

    注意清理系统用户的邮件日志
    每条任务调度执行完毕,系统都会将任务输出信息通过电子邮件的形式发送给当前系统用户,这样日积月累,日志信息会非常大,可能会影响系统的正常运行,因此,将每条任务进行重定向处理非常重要。

    例如,可以在crontab文件中设置如下形式,忽略日志输出:

    0 */3 * * * /usr/local/apache2/apachectl restart >/dev/null 2>&1

    “/dev/null 2>&1”表示先将标准输出重定向到/dev/null,然后将标准错误重定向到标准输出,由于标准输出已经重定向到了/dev/null,因此标准错误也会重定向到/dev/null,这样日志输出问题就解决了。

    系统级任务调度与用户级任务调度
    系 统级任务调度主要完成系统的一些维护操作,用户级任务调度主要完成用户自定义的一些任务,可以将用户级任务调度放到系统级任务调度来完成(不建议这么 做),但是反过来却不行,root用户的任务调度操作可以通过“crontab –uroot –e”来设置,也可以将调度任务直接写入/etc /crontab文件,需要注意的是,如果要定义一个定时重启系统的任务,就必须将任务放到/etc/crontab文件,即使在root用户下创建一个 定时重启系统的任务也是无效的。

    其他注意事项
    新创建的cron job,不会马上执行,至少要过2分钟才执行。如果重启cron则马上执行。

    当crontab突然失效时,可以尝试/etc/init.d/crond restart解决问题。或者查看日志看某个job有没有执行/报错tail -f /var/log/cron。

    千万别乱运行crontab -r。它从Crontab目录(/var/spool/cron)中删除用户的Crontab文件。删除了该用户的所有crontab都没了。

    在crontab中%是有特殊含义的,表示换行的意思。如果要用的话必须进行转义\%,如经常用的date ‘+%Y%m%d’在crontab里是不会执行的,应该换成date ‘+\%Y\%m\%d’。