Elk 6.1 安装使用说明

ELK 不是一款软件,而是 Elasticsearch、Logstash 和 Kibana 三种软件产品的首字母缩写。这三者都是开源软件,通常配合使用,而且又先后归于 Elastic.co 公司名下,所以被简称为 ELK Stack。根据 Google Trend 的信息显示,ELK Stack 已经成为目前最流行的集中式日志解决方案。

架构

Logstash

介绍

数据收集引擎:数据存储与数据流。它支持动态的从各种数据源搜集数据,并对数据进行过滤、分析、丰富、统一格式等操作,然后存储到用户指定的位置;

安装

1、 官方教程
2、 windows下安装Logstash

效果图

注意事项

1、windows下需要使用NSSM

Elasticsearch

安装

说明:Elastic 需要 Java 8 环境,注意要保证环境变量JAVA_HOME正确设置。
1、下载最新Elasticsearch版本,解压到指定目录。
2、在Unix上运行bin/elasticsearch或者在Windows上运行bin\elasticsearch.bat
3、打开:http://localhost:9200/

效果图

注意事项:

  1. 启动内存不足
# vi ${elasticsearch_HOME}/config/jvm.options
#-Xms2g
#-Xmx2g
-Xms512m
-Xmx512m
  1. 无法以root权限启动
# groupadd es
# useradd es -g es -p es
# chown es:es ${elasticsearch_HOME}/
# sudo su es
# ./bin/elasticsearch

安装elasticsearch-head

git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
npm install
npm run start
open http://localhost:9100/

谷歌插件安装链接

说明

Kibana

介绍

Kibana是个数据分析和可视化平台。通常与 Elasticsearch 配合使用,对其中数据进行搜索、分析和以统计图表的方式展示;

安装

kibana官方文档

效果图

注意事项

1、 需要cmd执行,直接运行.bat无效
2、 Logstash 6.1.1 issue with setup.bat file "could not find jruby in"
在7.0版本修复,下载master文件,并替换bin目录文件接口。

参考资料
1. Kibana入门教程
2. Logstash 最佳实践
3. kibana官方文档
4. ELK+Filebeat 集中式日志解决方案详解

调用链跟踪系统的首秀—查找打印配置未正确加载的bug

背景

问题

连续两天都有商家反馈无法打印,远程查看后都发现打印配置加载的有问题,以前设置好的打印机都没显示出来——显示的是 store 级别的打印配置(打印配置从store细化到entity_store后,如果请求没有entity_store_id,会去查找store级别的打印配置)。

思路

调用链跟踪系统,记录了每次api请求的url、params、返回数据、时间戳、ua、x-forwarded-for、埋点标记 等有用信息,足够我们用来回溯当时的程序运行路径,展示当时程序的部分状态。

操作

  1. 首先从庞大的日志里筛选出需要的所有调用链;
    1.1 根据商家反馈,早上从未成功打印过,我们先确定了一个较小的时间范围:从商家第一次登陆,到打印配置获取完成;
    1.2 我们先在记录里找商家store_id第一次出现的位置,再根据这条记录的ua找到了商家ip,根据此ip筛选出第一批数据,也找到了大概的时间范围;
    1.3 把所有记录复制出来,分组排序(按TraceId分组,组内按RpcId排序,组间按每组内第一条记录的At排序),方便分析;
    1.4 根据TraceId和RpcId补足中间缺失的记录(RpcId是有序的,中间缺失可以看出来)
    1.5 最终筛选出来106条记录,时间跨度约5秒,其中seller端的cash/get/lists接口产生了11个Api调用,相关记录就占了46条);
  2. 找到“获取打印配置”这个接口的请求参数和返回值,发现接口传参不正确,获取到的数据也不正确;
  3. 结合记录和代码,推测程序运行路径,找出问题的原因。

效果

最后找出来一个bug:

check接口和返回值:


PS: 接口没返回entity_store_id,后面却使用了entity_store_id去获取打印配置。

结语

  1. 最终张跃还在js端找出一个bug:打印配置的获取 写在了 setCookie方法 前面,导致获取配置的时候没有取到ntity_store_id(所以也没传)。
  2. 打印配置的获取有三个地方:打印js加载后自动获取、doLogin时获取、checkLogin时获取,所以出bug后也只有部分商户无法打印。
  3. 调用链跟踪记录查阅起来还不是很方便,主要问题有:
    3.1 商家没有固定的身份标识,在记录里难以找出所有的商家相关记录;
    3.2 日志记录无序,还需要自己排一遍序;
    3.3 如果能像数据库一样select筛选数据更好;
  4. 针对上面的问题,分别有一些解决方法:
    4.1 在客户端里获取商家电脑的硬件信息,作为商家的身份标识;
    4.2 日志记录排好序再写到log里,可以保证组内绝对有序,组间相对有序;
    4.3 找一些开源工具。。

mysql 如何恢复数据?

问题:

尝试还原数据库,之后提示 table doesn`t exist。

分析:

类型:MyISAM
数据:Table.frm,Table.MYD,Table.MYI
位置:/data/$databasename/目录中
说明:直接复制到mysql中data目录中,便可以使用

类型:InnoDB
数据文件:存储在/$innodb_data_home_dir/中的ibdata1文件中
结构文件:结构文件存在于/data/table_name.frm中
说明:不可以直接使用,并报错:table doesn`t exist

解决方法:

1、 停止 apache 和 mysql服务
2、 拷贝相应文件到/data/目录,在数据库引擎类型为InnoDB时,拷贝数据文件的同时还需要拷贝ibdata1。
3、 将根目录下的ib_logfile*文件全部删除掉

备注:

1、 正常的数据导出恢复,最好用工具,不要在data文件层面去恢复
2、 测试环境在windows下

参考文档:

1、 mysql 直接从date 文件夹备份表,还原数据库之后提示 table doesn`t exist的原因和解决方法

在api里写可以平滑关闭的进程

背景

对于无关紧要的进程,我们可以随时kill掉再重启,但是有时候不能这样粗暴地操作。

假设我们正在处理一个从消息系统得到的消息,而消息是 非持久化/自动ack 的,如果进程被打断,这条消息就可能丢失。

或者我们在处理一个耗时特别长的任务,这时别人不小心kill掉了我们的进程,那我们前面的成果就付诸东流了。

针对上面这些情况,我们在Api进程里加入了平滑关闭的特性,你可以捕获进程关闭指令,自己决定何时关闭。

下面是一些使用方法:

使用

使用方法一:闭包

class Cront extends MY_Controller
{
    public function run()
    {
        $ready_exit = false;
        $this->regSig(SIGTERM, function() use (&$ready_exit) {
            $ready_exit = true;
            echo "准备退出!";
        });
        while (true) {
            {
                /**
                 * 括号里是业务处理代码
                 */
                echo "正在处理业务...\n";
                sleep(3);
                echo "业务处理完毕!\n";
            }
            $this->catchSig();
            if ($ready_exit) {
                echo "exit now!\n";
                exit;
            }
        }
    }
}

使用方法二:对象方法

class Cront extends MY_Controller
{
    public $ready_exit = false;
    public function handSig($sig, $my_var1, $my_var2)
    {
        switch ($my_var1) {
            case 'run':
                $this->ready_exit = true;
                echo "exit ready\n";
                break;
        }
        var_dump(func_get_args());
    }

    public function run()
    {
        $this->regSig(SIGTERM, array($this, 'handSig'), 'run', 'myvar');
        while (true) {
            {
                /**
                 * 括号里是业务处理代码
                 */
                echo "正在处理业务...\n";
                sleep(3);
                echo "业务处理完毕!\n";
            }
            $this->catchSig();
            if ($this->ready_exit) {
                echo "exit now!\n";
                exit;
            }
        }
    }
}

注意

  1. 进程捕获关闭指令后,用 kill -9 仍然可以杀死进程;
  2. api里的 regSig 不仅可以捕获 SIGTERM 信号,还可以捕获其他信号;
  3. 如果调用了 regSig 而没有调用 catchSig ,程序仍然捕获不到信号;
  4. 不用 declare(ticks = 1); 是考虑到性能;

npm私有包:键盘事件监听


编   写:袁 亮
时   间:2017-08-17
说   明:复杂页面交互,键盘快捷键监听组件

一、功能描述
    1、事件监听
        默认绑定keydown事件
        绑定单例,防止多次绑定,导致多次触发
            ps:vue如果代码自动刷新,会导致又绑定一次
    2、触发条件
        配置条件
            inInput:光标在输入框内是否触发
                true:触发,false:不触发,默认true
            needCtrl:是否需要同时按下ctrl键
                不传,不限制
                true:必须按下Ctrl
                false:不能按下Ctrl
            needShift:是否需要同时按下shift键
                同needCtrl
            needAlt:是否需要同时按下alt键
                同needCtrl
        自定义方法
            触发的时候,会执行该方法判断是否要执行,返回true或者false
            不传,默认true
    3、事件触发执行
        同一事件,多次绑定
            后绑定的优先级更高
        事件冒泡
            如果事件没有被响应,自动按绑定顺序冒泡
        事件互斥
            同一事件,只会触发一次,捕获后,不再冒泡
        默认行为阻止
            事件被捕获,默认行为将被阻止
    4、事件定义
        内置常见事件
            esc:取消
            backspace
            enter
            delete
            up
            down
            increase
            decrease
            
            number:数字
            float:浮点数
            letter:字母
        支持自定义事件配置
            优先级高于内置事件
        
二、使用方法
    1、安装包
        npm install @duomai/keylisten --save
        ps:先切换到多麦的源
    2、代码
        import KeyListen from '@duomai/keyListen'
        
        // 在created钩子里,使用内置事件,不需要setConfig
        KeyListen.setConfig(config.shortcutKey).add({
          up: function () {
            // todo up
          },
          down: function () {
            // todo down
          }
        })
        
    

npm私有仓库3:项目中使用


编   写:袁 亮
时   间:2017-08-15
说   明:npm私有仓库3:项目中使用

一、修改dns地址 192.168.0.224
    1、linux
        vim /etc/resolv.conf
        nameserver 192.168.0.224
    2、windows
        网络设置
        清除缓存 cmd命令行
            ipconfig /flushdns
            
二、nrm管理npm源
    1、安装
        npm install -g nrm
    2、添加私有源
        nrm add duomai http://npm.duomai.com
    3、查看所有源
        nrm ls
    4、使用私有源
        nrm use duomai
        
三、安装包
    1、私有包(跟其他包一样,只是多了一个统一的前缀)
        npm install @duomai/urls
    2、普通包
        npm install vue
    3、包查看
        http://npm.duomai.com
    4、注意事项
        如果私有包使用es6的语法写,webpack打包的时候,需要将其使用babel转换,否则打包的时候会报错
        {
          test: /\.js$/,
          loader: 'babel-loader',
          include: [resolve('src'), resolve('test'), resolve('node_modules/\@duomai')]
        }
    
四、使用参考 @duomai/urls
    1、安装
        npm install @duomai/urls --save
    2、全局引入,设置
        import Urls from '@duomai/urls'
        
        Urls.init({
          store_id: Login.state.data ? Login.state.data.store_id : '' // 链接公共参数注入
        }, {
          shop: process.env.SHOP_BASE_URL, // 测试链接前缀注入,可以不写,默认正式环境
          seller: process.env.SELLER_BASE_URL,
          dealer: process.env.DEALER_BASE_URL
        })
    3、组件中使用
        import Urls from '@duomai/urls'
        console.log(Urls.shop.item(1921))

解读vue-cli脚手架并实际使用

整   理:晋 哲

时   间:2017-06-29

说   明:介绍脚手架搭建生成的各个文件功能,以及在实际项目中使用

一、vue-cli脚手架搭建之后的文件介绍及应用
1、build -- 开发配置文件夹,一般情况下安装时自动添加,通常不用改动
webpack.base.conf.js -- webpack配置文件
1
13

2、config文件夹
这里主要需要注意这几点的设置,正式运行环境下assetsPublicPath的路径设置需要改动为【./】
2

3、package.json -- 记录项目基本信息
4、index.html -- vue生成html的默认head代码部分,需要调整
5、README.md -- 一些执行命令的说明,方便查看使用

6、src -- vue代码存放的主要路径
(1)api -- 封装的api调用方式
使用如下:
3
注:sys_name和store_id已默认,不用传

(2)assets -- 静态文件存放,比如css、js、image、font等等
(3)common -- 存放一些封装的公共方法,比如alertMes、弹出框等等
(4)router -- 路由设置
4

(5)App.vue -- 主体组件
组件内容在里显示,公共样式可以在这里引入
5

(6)main.js -- 入口文件,主要作用是初始化vue实例并使用需要的插件
614

(7)components -- 组件的存放位置
一个主体的集合组件,拼接各个模块的子组件
7

子组件常用代码结构
8

二、引用ElementUI组件
1、安装

npm i element-ui -S

2、main.js里引入Element
9

3、组件里使用
比如“消息提示”组件的使用
this.$message('请输入商品名称')

具体各组件的使用方式查看官方文档
http://element.eleme.io/#/zh-CN/component/installation

三、引用vue插件
举例:vue-awesome-swiper插件
1、安装

npm install vue-awesome-swiper --save

2、main.js里引入插件
11

3、组件里使用
12

Vue开发快速起步


编   写:袁 亮
时   间:2017-06-28
说   明:Vue开发快速起步

一、工作模式
    1、类似jquery,作为类库
    2、单文件组件方式
        开发环境
            node hot reload
        生产环境
            静态html
            任意部署在webserver下即可
    
二、安装起步
    1、环境安装
        node npm vue vue-cli 等安装
    2、项目脚手架安装
        vue init webpack {project_name}
        cd {project_name}
        npm install
            ps:vim config/dev.env.js 修改开发环境端口,默认8080很有可能被占用
        npm run dev
            放在后台运行:nohup npm run dev & 
    3、访问
        http://192.168.0.249:8081
    4、IDE
        webstorm
        sublime
        vscode
    5、其他模块安装
        vuex的安装
            npm install vuex --save
        修改package.json
    6、编译
        npm run build
        
三、开发环境访问流程
    1、index.html
    2、src/main.js
        类似php框架的index.php
    3、src/App.vue
    4、router/index.js
        规则匹配,进行转发
        路由处理
    5、components/Hello.vue
        具体处理逻辑
        可以包含其他的组件
        
四、组件开发
    1、类库文件引入
        1.1 引入
            import
                必须在最开始的地方加,不能放在条件判断等
            require
                可以在条件判断里
        1.2 类库导致
            export default
            module.exports
    2、组件引入
        2.1 html结构
            
            
        2.2 组件源
            import modalMember from '@/components/modalMember.vue'
        2.3 注册?
            components: {
                modalMember
            }
    3、组件数据
        3.1 父组件数据传递 props
            props验证
            值传递 引用传递
            单向数据流
        3.2 组件本身数据 data
        3.3 组件计算属性 computed
            method的区别,缓存,依赖
            getter
            setter
        3.4 数据监听 watch
            vs computed
            异步、开销大的时候,用watch
    4、模板语法
        4.1 文本
            {{}}
            v-text
            v-html
            v-once
                不更新
        4.2 属性
            v-bind:{name}
            简写 :{name}
            :class 注意注意
        4.3 条件属性
            v-if
            v-else-if
            v-else
            v-show
        4.4 循环 v-for
        4.5 事件
            v-on:click
            @click
        4.6 输入数据双向绑定
            v-model
            修饰符
                .lazy
                .number
                .trim
        4.6 注意事项
            a. 以下对数组操作,不会触发视图变更
                当你利用索引直接设置一个项时
                当你修改数组的长度时
            b. 视图更新队列
                数据变更,视图更新会放入到更新队列,异步更新
                如果想更新完进行回调,可以采用Vue.nextTick(callback)
                ps:监听数据变更,改版dom的滚动条位置计算等,数据更新了,但是dom还没有
    5、组件方法
        5.1 method
            获取绑定的数据
                e.currentTarget.dataset.index (数据绑定在父元素的时候用这个)
                e.target.dataset.index (数据绑定在当前元素的时候用这个)
            event
            事件修饰符
                .stop
                .prevent
                .capture
                .self
                .once
            键值修饰符
                事件
                别名 自定义
                修饰键
        5.2 directive 自定义指令(不能直接操作dom,所以需要自定义指令)
            bind
            inserted
            update
            componentUpdated
            unbind
    
    6、生命周期
        beforeCreate
        √ created
        mount
        beforeMount
        mounted
        beforeUpdate
        updated 
        beforeDestory
        destroyed
    
五、状态管理 Vuex
    1、解决什么问题
        一份数据,很多个组件需要使用
        这些组件不仅仅是父子关系
    2、安装
        npm install vuex --save
    3、项目使用(全局store)
        import store from './store/index'
        
        new Vue({
          el: '#app',
          router,
          store,
          template: '',
          components: { App }
        })
    4、store介绍
        4.1 state
            类似组件的data
        4.2 getters
            类似computed计算属性
            setters: 没用过
        4.3 mutations
            类似method
            ps:mutations之间不能直接调用,不确定是否可以这么做
        
六、网络请求 vue-resource
    1、安装
    2、使用
        import VueResource from 'vue-resource'
        Vue.use(VueResource)
        ps:作为插件引入
    3、需要重新封装,跟常规的ajax请求不大一样
        3.1 api地址区分环境
        3.2 统一做鉴权等
    
七、语法注意
    1、var 改用let 或者const
    2、缩进 2个字符
    3、不能有;号
    4、空格
        function () {
        }
        // 注释文字
    
    

mysql binlog日志查看

基本说明

  1. 定义
    binlog基本定义:二进制日志,也成为二进制日志,记录对数据发生或潜在发生更改的SQL语句,并以二进制的形式保存在磁盘中;

  2. 作用
    可以用来查看数据库的变更历史(具体的时间点所有的SQL操作)、数据库增量备份和恢复(增量备份和基于时间点的恢复)、Mysql的复制(主主数据库的复制、主从数据库的复制)

  3. 格式
    binlog的格式有三种,这也反应了mysql的复制技术:基于SQL语句的复制(statement-based replication, SBR),基于行的复制(row-based replication, RBR),混合模式复制(mixed-based replication, MBR)。相应地,binlog的格式也有三种:STATEMENT,ROW,MIXED。

  4. 日志位置
    修改my.cnf参数文件
    [mysqld]
    log-bin=mysql-bin

语法说明

  1. 命令
    binlog不能直接用文本的方式打开。
    使用show binlog events方式可以获取当前以及指定binlog的日志,不适宜提取大量日志。
    使用mysqlbinlog命令行提取(适宜批量提取日志)。

  2. 语法

    直接查看单个二进制日志文件:
    mysqlbinlog filename

    提取指定position位置的binlog日志
    --start-position="120" --stop-position="332"

    提取指定数据库binlog并转换字符集到UTF8
    --database=test --set-charset=utf8

    指定结束时间
    --start-datetime='2015-01-20 09:00:00' --stop-datetime='2015-01-20 12:59:59'

    指定row格式解码
    --base64-output=decode-rows

    -v用于输出基于row模式的binlog日志
    -vv为列数据类型添加注释

日志格式

# at 579744(开始位置)
#150905  7:02:54(时间截) server id 2543308(产生该事件的服务id)  end_log_pos(日志的结束位置) 579815  Query(事件类型)   thread_id=21    exec_time=0     error_code=0
SET TIMESTAMP=1441407774/*!*/;
BEGIN
执行的sql语句

其他说明

  1. 在数据出错的情况下,使用 MYSQLBINLOG 来恢复数据

5.3 迁移 5.6 需要注意的问题

👁代表额外需要注意的,✅代表遇到过

5.3 Migrating 5.4

重点

  1. breakcontinue不再接受可变参数(break 1 + max(x, y)),break 0;continue 0不允许出现
  2. 现在参数名使用全局变量将会导致一个致命错误。禁止类似 function foo($_GET, $_POST) {} 这样的代码。
  3. 非数字的字符串偏移量👁
    $a = '12345';
     var_dump(isset($a['x']); // 5.3 true, 5.4 false
  1. 调用时的引用传递👁
 function f(&$v){$v = true;}
 f(&$v); // 5.3 no problem 5.4 PHP Fatal error

 function f1($v){$v = true;}
 f1(&$v); // 5.3 no problem 5.4 PHP Fatal error

function f2(&$v){$v = true;}
f2($v); // ok

一些不常用的

  1. 不支持安全模式
  2. 移除魔术引号
  3. register_globals 和 register_long_arrays php.ini 指令被移除。

    PHP: 不向后兼容的变更 - Manual

5.4 Migrating 5.5

重点

  1. 原始的 MySQL 扩展 现在被废弃,当连接到数据库时会产生一个 E_DEPRECATED 错误。👁

PHP: 不向后兼容的变更 - Manual

5.5 Migrating 5.6

重点

  1. json_decode 严格模式
  2. cURL文件上传 👁✅
    > 必须先设置 CURLOPT_SAFE_UPLOAD为 FALSE 才能够使用 @file 语法来上传文件。 建议使用 CURLFile 类来上传文件。
  3. 使用::调用非静态方法,现在产生 E_DEPRECATED 错误 (以前是 E_STRICT)
  4. 使用 always_populate_raw_post_data 会导致在填充 $HTTP_RAW_POST_DATA 时产生 E_DEPRECATED 错误。 请使用 php://input 替代 $HTTP_RAW_POST_DATA, 因为它可能在后续的 PHP 版本中被移除。 在php.ini中设置 always_populate_raw_post_data 为 -1 (这样会强制 $HTTP_RAW_POST_DATA 未定义,所以也不回导致 E_DEPRECATED 的错误) 👁✅
  5. 使用数组标识符为类定义数组类型的属性时,数组的键不会被覆盖
    class C {
    const ONE = 1;
    public $array = [
        self::ONE => 'foo',
        'bar',
        'quux',
    ];
}
var_dump((new C)->array);
/* 5.5 before array(2) {
  [0]=>
  string(3) "bar"
  [1]=>
  string(4) "quux"
}
*
* 5.6 
* array(3) {
  [1]=>
  string(3) "foo"
  [2]=>
  string(3) "bar"
  [3]=>
  string(4) "quux"
}
*/

PHP: 向后不兼容 - Manual

其他问题

  1. 线上的php5.6没有编译fileinfo,这个会导致读不到文件信息,因为运维都是统一安装的,所以最好看一下是否enable-fileinfo

  2. 启用 Opcache,之前因为出现了一些问题,运维那边关掉这个缓存,最好和运维沟通,并测试缓存是否正确使用、正常更新。

    现代 PHP 新特性系列(六) —— Zend Opcache