分类:未分类


这个命令你看得懂么


直接上命令

history 1 | { read x cmd; echo “$cmd”; }

对于read命令的了解,仅限于在shell脚本中使用read -p,对于这种用法从来没用过,更不知道它的含义。

今天抽空琢磨了一下,终于搞明白了来龙去脉。先来写几个命令吧:

# read a b c

1 2 3

# echo $a

1

# echo $b

2

# echo $c

3

# read x y

1 2 3

# echo $x

1

# echo $y

2 3

到这,也许你似乎看出一些门道了。read命令,后面跟的是变量名,可以是1个,也可以是多个,用空格分隔。回车后,输入的字符就是在给这些变量赋值,输入的字符串也需要用空格分隔,如果和上面的变量名一个一个地对应,那么这样就一个一个地赋值了。

如果没有对应呢?通过上面的命令也可以发现,如果值比变量多,它只对应前面的。例如,变量只有x和y,而值是1 2 3,则它把x赋值1,后面的2 3一股脑赋值给最后面的变量y。

再来一个例子吧。

# echo 1 2 3 4 5|read a b c

# echo $a

1

# echo $b

2

# echo $c

3 4 5

再回头看这条命令:

history 1 | { read x cmd; echo “$cmd”; }

管道前面,history 1表示取最后一条命令。管道后面'{ }’内是一整体,相当于一个函数,函数里面可以有多条命令,用分号分割,而且最后一条命令也必须加分号。第一条命令和'{‘之间必须要有空格。

iptables,netfilter,firewalld关系


在centos6上,我们用的是iptables服务,而在centos7上,我们用的是firewalld服务。同样的,centos6上安装的是iptables包,而centos7上安装的是firewalld包。

不管是centos6还是centos7,核心其实都是netfilter,netfilter是linux的一个内核模块,iptables命令是linux内核自带的。

centos6上的iptables服务和centos7上的firewalld服务,其实都是用来定义防火墙规则功能的防火墙管理工具。它们都是将定义好的规则交由内核中的netfilter即网络过滤器来读取,从而真正实现防火墙功能,所以其实在配置规则的思路上是完全一致的。

MySQL延迟主从复制


世界上没有卖后悔药的,一旦做错了,后悔莫及。我们作为运维,尤其是不小心误删除数据库里的数据时,那更是损失巨大。对于MySQL来说,这里有一种方法,可以避免这种悲剧的发生。

这儿所谓的延迟,并不是经常说的网络延迟,而是我们故意把从库复制的步伐放慢,比如让从库比主库慢30分钟。这样,如果在半小时内发现数据有问题,还能补救。

MySQL 5.6 已经支持延迟复制, 可设置备节点的延迟时间, 延迟复制是有意义的,例如防止主节点数据误删,查看数据库历史状态等。

配置也不难,做完主从后,再加上这句:

CHANGE MASTER TO MASTER_DELAY = N;

这里的N单位是秒,这样从库则会比主库延时N秒。做完之后,在show slave status的时候,就可以看到SQL_Delay的值。

SQL_Delay: xxx

正则表达式非贪婪匹配


我们学习正则时,用到过贪婪匹配.*
其实,还有一个相对的概念,叫做非贪婪匹配。

如:str=”abcaxc”
  p=”a.*c”
  
贪婪匹配:正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配。如上面使用模式p匹配字符串str,结果就是匹配到:abcaxc。
  
非贪婪匹配:就是匹配到结果就好,最少的匹配字符。如上面使用模式p匹配字符串str,结果就是匹配到:abc(a.*c)。

shell中如何区分两种模式?

默认是贪婪模式;
在量词后面直接加上一个问号?就是非贪婪模式。

常用的量词有:

{m,n}: m到n个
*: 任意多个
+: 一个到多个
?: 0或一个

示例:

str=”123abc0axc456″
echo $str|grep ‘a.*c’
结果: 123abc0axc456

echo $str|grep -P ‘a.*?c’
结果: 123abc0axc456


elastic stack 使用redis作为日志缓冲


直接上步骤:

1、首先建立一个配置文件,将output的数据写到redis中,而不是ES了。配置文件示例:

input {
    stdin { }
}
output {
    redis {
        host => "192.168.1.100"  #redis服务器地址
        port => "6379"  #redis服务端口
        db => "5"  #使用redis第五个库,用其他库也可以
        data_type => "list"  #用list类型
        key => "demo"  #存储的key名,可自定义自己喜欢的
    }
}

 

2、指定配置文件然后运行Logstash,然后我们在标准输入中随便写点什么东西,这个时候输入的数据都会提交到redis中。登录redis后使用info命令可以查看keyspace相关信息,可以看到db5的keys数量有了变化,我们切换到db5再来看看

select 5
keys *

 

3、通过keys *命令可以看到有了一个key叫做demo,这个就是配置文件里设置的key名,使用LLEN demo可以看到该key的长度,input如果输入了100行,那么这个key就应该有100行

4、再次建立一个配置文件,这次input是从第一步里的redis里读取数据,然后output到ES中

input {
    redis {
        host => "192.168.1.100"  
        port => "6379"  
        db => "5"  
        data_type => "list"
        key => "demo" 
    }
}
output {
    elasticsearch {
        hosts => ["192.168.0.100:9200"]
        index => "redis-demo-%{+YYYY.MM.dd}"
    }
}

 

5、运行该配置文件后去redis看看,之前的队列因为被output到了ES中,所以队列会消失掉或者是迅速减少长度

下面是一个改造后的配置文件,更符合实际需求

input {
    file {
        path => "/var/log/messages"
        type => "system"
}
output {
    if [type] == "system" {
        redis {
          host => "192.168.1.100"
          port => "6379"
          db => "5" 
          data_type => "list" 
          key => "system"
    }
}

linux shell命名管道FIFO


在shell脚本中,我们想要实现多进程高并发,最简单的方法是把命令丢到后台去,如果量不大的话,没问题。 但是如果有几百个进程同一时间丢到后台去就很恐怖了,对于服务器资源的消耗非常大,甚至导致宕机。

那有没有好的解决方案呢? 当然有!

我们先来学习下面的常识。

1 文件描述符

文件描述符(缩写fd)在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。每一个unix进程,都会拥有三个标准的文件描述符,来对应三种不同的流:

除了上面三个标准的描述符外,我们还可以在进程中去自定义其他的数字作为文件描述符,后面例子中会出现自定义数字。每一个文件描述符会对应一个打开文件,同时,不同的文件描述符也可以对应同一个打开文件;同一个文件可以被不同的进程打开,也可以被同一个进程多次打开。

我们可以写一个测试脚本/tmp/test.sh,内容如下:

#!/bin/bash

echo “该进程的pid为$$”

exec 1>/tmp/test.log 2>&1

ls -l /proc/$$/fd/

执行该脚本 sh /tmp/test.sh,然后查看/tmp/test.log内容为:

总用量 0

lrwx—— 1 root root 64 11月 22 10:26 0 -> /dev/pts/3

l-wx—— 1 root root 64 11月 22 10:26 1 -> /tmp/test.log

l-wx—— 1 root root 64 11月 22 10:26 2 -> /tmp/test.log

lr-x—— 1 root root 64 11月 22 10:26 255 -> /tmp/test.sh

lrwx—— 1 root root 64 11月 22 10:26 3 -> socket:[196912101]

其中0为标准输入,也就是当前终端pts/3,1和2全部指向到了/tmp/test.log,另外两个数字,咱们暂时不关注。

2 命名管道

我们之前接触过的管道“1”,其实叫做匿名管道,它左边的输出作为右边命令的输入。这个匿名管道只能为两边的命令提供服务,它是无法让其他进程连接的。

实际上,这两个进程(cat和less)并不知道管道的存在,它们只是从标准文件描述符中读取数据和写入数据。

另外一种管道叫做命名管道,英文(First In First Out,简称FIFO)。

FIFO本质上和匿名管道的功能一样,只不过它有一些特点:

1)在文件系统中,FIFO拥有名称,并且是以设备特俗文件的形式存在的;

2)任何进程都可以通过FIFO共享数据;

3)除非FIFO两端同时有读与写的进程,否则FIFO的数据流通将会阻塞;

4)匿名管道是由shell自动创建的,存在于内核中;而FIFO则是由程序创建的(比如mkfifo命令),存在于文件系统中;

5)匿名管道是单向的字节流,而FIFO则是双向的字节流;

有了上面的基础知识储备后,下面我们来用FIFO来实现shell的多进程并发控制。

需求背景:

领导要求小明备份数据库服务器里面的100个库(数据量在几十到几百G),需要以最快的时间完成(5小时内),并且不能影响服务器性能。

需求分析:

由于数据量比较大,单个库备份时间少则10几分钟,多则几个小时,我们算平均每个库30分钟,若一个库一个库的去备份,则需要3000分钟,相当于50个小时。很明显不可取。但全部丢到后台去备份,100个并发,数据库服务器也无法承受。所以,需要写一个脚本,能够控制并发数就可以实现了。

控制并发的shell脚本示例:

#!/bin/sh

function a_sub {
    sleep 2;
    endtime=`date +%s`
    sumtime=$[$endtime-$starttime]
    echo "我是$i,运行了2秒,整个脚本已经执行了$sumtime秒"
}

starttime=`date +%s`
export starttime

##其中$$为该进程的pid
tmp_fifofile="/tmp/$$.fifo"

##创建命名管道
mkfifo $tmp_fifofile

##把文件描述符6和FIFO进行绑定
exec 6<>$tmp_fifofile

##绑定后,该文件就可以删除了
rm -f $tmp_fifofile

##并发量为8,用这个数字来控制并发数
thread=8

for ((i=0;i<$thread;i++));
do
    ##写一个空行到管道里,因为管道文件的读取以行为单位
    echo >&6
done

##循环100次,相当于要备份100个库
for ((i=0;i<100;i++))
do
    ##读取管道中的一行,每次读取后,管道都会少一行
    read -u6
    {
        a_sub || {echo "a_sub is failed"}
        ##每次执行完a_sub函数后,再增加一个空行,这样下面的进程才可以继续执行
        echo >&6
    } & ##这里要放入后台去,否则并发实现不了
done

##这里的wait意思是,需要等待以上所有操作(包括后台的进程)都结束后,再往下执行。
wait

##关闭文件描述符6的写
exec 6>&-

 

vim的加密功能


一、 利用 vim 加密:

优点:加密后,如果不知道密码,就看不到明文,包括root用户也看不了;
缺点:很明显让别人知道加密了,容易让别人把加密的文件破坏掉,包括内容破坏和删除;

vim编辑器相信大家都很熟悉了吧,vim里有一个命令是给文件加密的,举个例子:

1) 首先在root主目录/root/下建立一个实验文件text.txt:
#  vim  text.txt

2) 进到编辑模式,输入完内容后按ESC,然后输入:X(注意是大写的X),回车;

3) 这时系统提示让你输入密码,2次,如下所示:
输入密码: *******
请再输入一次: *******

4) 保存后退出,现在这个文件已经加密了;

5) 用cat或more查看文件内容,显示为乱码;用 vim重新编辑这个文件,会提示输入密码,如果输入的密码不正确,同样会显示为乱码!
注意:文件加密后,千万别忘了密码!

二、 vim编辑加密的文件(前提是你知道加密的密码):

1)  用 vim 打开文件如text.txt,要输入正确的密码,然后在编辑时,将密码设置为空,方法是输入下面的命令:
:set key=
然后直接回车,保存文件后,文件已经解密了。

2) 或者这样也行:
在正确打开文件后用 “:X” 指令,然后给一个空密码也可以。保存用“wq!”保存。
两种方法实际上效果是一样的。

apache rewrite死循环的问题


需求背景是: 把所有请求都转发到/111/目录下面,比如当访问 www.aminglinux.com/1.html时,应该跳转到www.aminglinux.com/111/1.html

核心配置语句是

RwriteRule ^(.*)$  /111/$1 [R,L]

使用curl测试,没有问题,但是使用浏览器访问时,出现了无限循环。
本来访问的是www.aminglinux.com/1.html时,结果变成了www.aminglinux.com/111/111/111/111/…..

解决该问题的方法是,加一个条件

RewriteCond   %{REQUEST_URI} !^/111

RewriteRule ^(.*) /111/$1 [R,L]

关于mysql优化的一些心得


先介绍下服务器架构及配置8核8G,10M带宽Centos6.5,64位,系统的架构为

Nginx 1.8.1,PHP  5.3.29,Mysql  5.5.42。

一电商网站后台查询订单时,经常php超时,导致php报错。以下是排查过程。

1、php执行超时,首先我们想到的就是php.ini文件中max_execution_time =  #把默认的值调大。

2、然后在后台执行订单查询php不报错了,但是查询耗时较长,用时65s。而且一些表成锁死状态碎片比较多,本人对mysql数据库优化不是很了解,于是请教了铭哥下,铭哥给出的答复是:一般mysql调优主要是根据慢查询日志去优化sql语句,my.cnf里面可调整的东西不多,而且效果也不明显。 下面就是调整参数,分析mysql慢查询日志。

3、mysql参数优化,主要调整的参数根据机器性能来调整,如果你对参数不是很了解,建议不要盲目的调。给大家一篇参数调整的文章 http://ask.apelearn.com/question/5758 (看第5条)

把一些配置参数修改好后重启mysqld服务,由原来的65s变成了十几秒。效果还是不是很理想,查看了下mysql默认引擎为MyISAM,决定把引擎改为Innodb。具体操作过程如下:

4、导出shop数据库的表结构

mysqldump -d -uxxx -p shop > shop_table.sql

其中-d参数表示不导出数据,只导出表结构

5、替换shop_table.sql里的MyISAM为INNODB

sed -i ‘s/MyISAM/INNODB/g’ shop_table.sql

6、新建数据库shop_new库,并导入表结构

mysql > create database shop_new;

mysql -uroot -p shop_new < shop_table.sql可以通过show table status来检查表引擎是否为INNODB。

7、导出shop的数据

mysqldump -t -uroot -p shop > shop_data.sql其中-t参数表示只导数据,不导表结构

8、导入数据到shop_new

mysql -uroot -p shop_new < shop_data.sql

9、 查看慢查询日志来定位mysql哪条语句执行慢,然后建立索引,优化sql执行语句。这台机器的慢查询日志片段,供大家参考

# Time: 160303 12:12:38

# User@Host: root[root] @  [10.165.34.182]

# Query_time: 10.145685  Lock_time: 0.000395 Rows_sent: 1  Rows_examined: 24306970

use shop;

SET timestamp=1456978358;

SELECT COUNT(*) FROM `shop`.`ecs_order_info` o LEFT JOIN`shop`.`ecs_users` u ON o.user_id = u.user_id LEFT JOIN `shop`.`ecs_affiliate_log` a ON o.order_id = a.order_id WHERE o.user_id > 0 AND (u.parent_id > 0 AND o.is_separate = 0 OR o.is_separate > 0);

# Time: 160303 12:12:44

# User@Host: root[root] @  [10.165.34.182]

# Query_time: 6.073441  Lock_time: 0.000152 Rows_sent: 15  Rows_examined: 24314767

SET timestamp=1456978364;

SELECT o.*, a.log_id, a.user_id as suid,  a.user_name as auser, a.money, a.point, a.separate_type,u.parent_id as up FROM `shop`.`ecs_order_info` o LEFT JOIN`shop`.`ecs_users` u ON o.user_id = u.user_id LEFT JOIN `shop`.`ecs_affiliate_log` a ON o.order_id = a.order_id WHERE o.user_id > 0 AND (u.parent_id > 0 AND o.is_separate = 0 OR o.is_separate > 0)  ORDER BY order_id DESC LIMIT 0,15;

通过慢日志发现其中有几个表查询耗时较长,下面就是把这个查询慢的表建立索引。用到的软件 NAvicat,对查询慢的表进行设计,增加索引。

 

根据 explain  的解释,查看下  索引是否建立,一般都是 这样调整 就行。

 

修改完后重启mysql 服务,查询时间从65s,缩短到 0.017407 秒

git,github,gitlab


如果初次接触git的朋友一定搞不清git,github以及gitlab这几个概念。

git如果不知道是啥,那你总知道svn是啥吧。什么?svn也不知道?那只好辛苦你动动手搜一下了。

git用一句话介绍:它是一个分布式的版本管理工具。然后我从网上找了两张图来对比svn和git的最主要的差异——分布式。

 

从上面两个图,可以看出使用svn的版本变化数据都是存在于服务端的,最终控制中心只有一个。而git,每一个客户端都可以作为一个版本管理中心,当然它也需要有一个公共的总控制点。

再给大家举一个例子吧,比如我和朋友一起开发一个软件,这个软件有很多代码片段,所以改动也比较频繁。如果使用svn,那我们无论谁每改动一段代码都要推送到svn中心去,而为了保证代码统一,其中一个人只要因为推送新的代码变动了控制中心,另一个人都要把改动的地方拉取到自己的电脑。所以这样就比较麻烦了。

而使用git时,我和朋友都可以在自己电脑上搞一个git控制中心,我们电脑里面的代码可以不一致,只需要用自己的git管理自己的那一部分代码。而git服务端只是用来合并我和朋友的最终版本代码的,平时的小改动由我们自己电脑里面的控制中心来管理,git服务端不用关心。

下面我用一个公司老总管理员工的例子再来总结一下svn和git的差异。svn架构里面的管理者比较独裁,不信任任何人,所有的事情都是亲力亲为,它宁愿管理所有员工也不设置下级管理者。

而git架构里面的老总比较明智,他比较偷懒,只管大事情,小事情都是交给下面的小leader去搞定的。每个小leader去管理自己的下属也不用关心其他leader的事情。但是所有leader都需要不定期向大boss汇报一下近期的情况。

github,是一个web界面的git管理平台,也就是说它底层的技术驱动依然是git。一句话区分,git是管理工具,github是在线的基于git的平台(或者叫做服务)。github的角色也就是我们上面例子中的大boss。github是公开的,谁都可以注册账号,并创建自己的项目,大部分项目以代码为主,比如wordpress、discuz都是托管在github里面的,当然还有好多好多开源的软件。

既然github是一个公共的,在线的提供服务的平台,那企业就可以把公司内部的代码托管在这里,为了安全我们可以选择付费服务,定制个性化方案。但毕竟github在国外,要想获得更好的功能还需要花钱,小企业或者个人用户自然是不愿意去开销了。

还好又一款开源的软件可以帮我们搭建一套类似github的平台,这就是接下来我要介绍的gitlab。 gitlab适合企业内部构建私有代码管理平台,它有健全的权限控制系统和各种强大的功能,很赞。

所以,gitlab和github一样,也是一个基于git的提供web界面的代码管理平台。