Ubuntu安装配置Samba

公司要建一个共享文件服务器,我就简单配置了一个samba服务器,系统使用的是Ubuntu 14.04。

samba是Linux系统上的一种文件共享协议,可以实现其他系统访问Linux系统上的共享资源。

一、安装samba

打开”终端窗口”,输入下面的命令更新源和软件

sudo apt-get update &&  apt-get upgarde

使用下面命令安装

sudo apt-get install -y samba samba-common

二、配置samba

打开”终端窗口”,输入下列命令创建共享文件夹,并修改权限

sudo mkdir /home/share
sudo chmod 777 /home/share

使用vim编辑samba配置文件

cp /etc/samba/smb.conf /etc/samba/smb.conf_bak
sudo vim /etc/samba/smb.conf

在smb.conf文件最后添加下列配置

#security = share  #配置无需密码访问,但是我发现这句没用,添了还启动不了

[Share] # 访问时候显示的文件夹名字
  comment = Share for work
  path = /home/share   # Ubuntu中要共享的目录,记的 chmod 755 修改目录属性
  public = yes
  writeable = yes
  guest ok = yes
  create mask = 0664
  directory mask = 0664
  force user = root
  force group = root
  browseable = yes
  available = yes

保存退出,使用以下命令启动服务器

/etc/init.d/smbd start
/etc/init.d/smbd status

然后就可以访问了,windows下 win+R 输入 “\192.168.2.5” 不用输入账号密码可以直接访问,
mac下要使用Finder中的连接服务器

看图操作:

未分类

未分类

三、设置开机启动

Redhat 或者 Centos 配置开机自启动可以配置 chkconfig,但是Ubuntu 没有,可以使用类似的功能命令 sysv-rc-conf

sudo apt-get install -y sysv-rc-conf #安装
sudo sysv-rc-conf #运行

未分类

按空格进行将启动项反选,按q退出之后配置即完成,重启电脑就可以查看效果。

saltstack自定义模块

今天在基于salt api开发监控平台的时候发现salt的模块有些不是很友好,就准备进行自定义模块来满足需求

配置master

vim /etc/salt/master
file_roots:
  base:
    - /srv/salt

创建模块目录

mkdir -p /srv/salt/_modules

定义模块

vim /srv/salt/_modules/info.py
def test()
    return 'module is ok'

同步模块

salt '*' saltutil.sync_modules
----------输出----------
iZrj91nl9ur3zi797yj8veZ:
    - modules.info
www.uyghurcongress.org:
    - modules.info

执行

salt '*' info.test

PHP性能调优,PHP慢日志—善用php-fpm的慢执行日志slow log,分析php性能问题

众所周知,MySQL有slow query log,根据慢查询日志,我们可以知道那些sql语句有性能问题。作为mysql的好搭档,php也有这样的功能。如果你使用php-fpm来管理php的话,你可以通过如下选项开启。
PHP 5.3.3 之前设置如下:

<value name="request_slowlog_timeout">5s</value>
<value name="slowlog">logs/php-fpm-slowlog.log</value>

PHP 5.3.3 之后设置以下如下:

request_slowlog_timeout = 5s
slowlog = /usr/local/php/log/php-fpm-slowlog.log

说明:

request_slowlog_timeout 是脚本超过多长时间 就可以记录到日志文件
slowlog 是日志文件的路径

开启后,如果有脚本执行超过指定的时间,就会在指定的日志文件中写入类似如下的信息:

[19-Dec-2013 16:54:49] [pool www] pid 18575
script_filename = /home/web/htdocs/sandbox_canglong/test/tt.php
[0x0000000003a00dc8] curl_exec() /home/web/htdocs/sandbox_canglong/test/tt.php:2
[0x0000000003a00cd0] exfilter_curl_get() /home/web/htdocs/sandbox_canglong/test/tt.php:6

日志说明:

  • script_filename 是入口文件
  • curl_exec() : 说明是执行这个方法的时候超过执行时间的。
  • exfilter_curl_get() :说明调用curl_exec()的方法是exfilter_curl_get() 。
  • 每行冒号后面的数字是行号。

开启后,在错误日志文件中也有相关记录。如下:

[19-Dec-2013 15:55:37] WARNING: [pool www] child 18575, script '/home/web/htdocs/sandbox_canglong/test/tt.php' (request: "GET /test/tt.php") executing too slow (1.006222 sec), logging
[19-Dec-2013 15:55:37] NOTICE: child 18575 stopped for tracing
[19-Dec-2013 15:55:37] NOTICE: about to trace 18575
[19-Dec-2013 15:55:37] NOTICE: finished trace of 18575

rsync软件服务利用ansible实现一键化部署

首先创建一个脚本文件 /server/tools/peizhi.sh

cat  /server/tools/peizhi.sh
cat >>/etc/rsyncd.conf<<EOF
#luo
##paichu.sh##

uid = rsync
gid = rsync
use chroot = no
max connections = 200
timeout = 300
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsyncd.log
ignore errors
read only = false
list = false
hosts allow = 172.16.1.0/24
hosts deny = 0.0.0.0/32
auth users = rsync_backup
secrets file = /etc/rsync.password
[backup]
comment = "backup dir by oldboy"
path = /backup
EOF

一键化剧本

[root@m01 tools]# cat rsyncpiliang.yml 
- hosts: 172.16.1.141 #服务端
tasks:
- name: yum 
shell: yum install -y rsync #安装rsync
- name: yunm
shell: yum -y install sshpass #安装密钥的软件
- name: chuangjianmulu
shell: mkdir -p /server/tools/ #创建所在配置的文件
- name: peizhi
copy: src=/server/tools/peizhi.sh dest=/server/tools/peizhi.sh
- name: yunxing 
script: /server/tools/peizhi.sh #运行脚本
- name: guanliyunhu
shell: useradd -s /sbin/nologin -M rsync #创建rsync虚拟用户
- name: anquanwenjian
shell: echo "rsync_backup:oldboy123" >/etc/rsync.password #设置密码文件
- name: quanxian
shell: chmod 600 /etc/rsync.password #给予权限
- name: beifenmulu
shell: mkdir -p /backup && chown -R rsync.rsync /backup
- name: qidong
shell: rsync --daemon #运行rsync
- hosts: 172.16.1.108
tasks:
- name: yum
shell: yum install -y rsync # 客户端
- name: chuangjianmulu
shell: mkdir -p /server/tools/
- name: mimawenjian
shell: echo "oldboy123" >/etc/rsync.password && chmod 600 /etc/rsync.password
- hosts: 172.16.1.131
tasks:
- name: yum
shell: yum install -y rsync #客户端 
- name: chuangjianmulu
shell: mkdir -p /server/tools/
- name: mimawenjian
shell: echo "oldboy123" >/etc/rsync.password && chmod 600 /etc/rsync.password

安装saltstack-web管理界面

1、安装salt-master、salt-minion和salt-api

$ sudo yum install epel-release -y

$ sudo yum install salt-master salt-minion salt-api -y


# 配置教程请看 文章 。
# 启动并设置开机启动服务

$ sudo systemctl  start salt-master
$ sudo systemctl  enable salt-master

$ sudo systemctl  start salt-minion
$ sudo systemctl  enable salt-minion

$ sudo systemctl  start salt-api
$ sudo systemctl  enable salt-api

2、安装halite及其依赖文件

$ sudo yum install python-pip -y && sudo pip install --upgrade pip 
$ sudo pip install -U halite
$ sudo pip install cherrypy
$ sudo pip install paste

$ sudo yum install python-devel gcc -y 
$ sudo pip install gevent 
$ sudo pip install pyopenssl

3、在配置文件master

$ sudo vim /etc/salt/master


external_auth:
  pam:
    testuser:            //此用户设置为系统在用的用户
      - .*
      - '@runner'

halite:
  level: 'debug'
  server: 'cherrypy'
  host: '0.0.0.0'
  port: '8080'
  cors: False
  tls: True
  certpath: '/etc/pki/tls/certs/localhost.crt'
  keypath: '/etc/pki/tls/certs/localhost.key'
  pempath: '/etc/pki/tls/certs/localhost.pem'

4、运行命令

$ sudo salt-call tls.create_self_signed_cert tls

5、启动并设置自启动服务

$ sudo systemctl restart salt-master
$ sudo systemctl restart salt-minion
$ sudo systemctl restart salt-api

6、网页打开访问地址

https://IP:8080

未分类

nginx使用DDNS域名作为反向代理的upstream

0x01 前言

我配置所有的服务都喜欢在前面套一个nginx,然后加上SSL以保安全。在这过程中有一种情况比较特殊,就是upstream使用DDNS进行解析。

正好前两天发现有位V友也问了这个问题,在解答之后我将这个问题记录在这里,V站链接如下:

https://www.v2ex.com/t/387350#reply15

这种使用方式也挺常见的,例如后端放在家里或其他没有固定IP的网络中,又需要将这个服务暴露在公网,可是不希望每次访问都输入端口号,这时候就需要反向代理。

0x02 BUG

nginx的反向代理需要配置一个upstream,而upstream支持众多协议,这里以http协议为例:

[root@web conf.d]# cat zabbix.t.com.ngx.conf 
server {

    listen                  80;
    server_name             zabbix.t.com;

    root                    /usr/local/services_data/html/zabbix.t.com/public_html/;

    access_log              /usr/local/services_data/html/zabbix.t.com/logs/ngx_access.log;

    location / {

        index               index.php index.html;
        proxy_pass          http://127.0.0.1:8080;

    }

}

以上是我家zabbix作为后端,nginx作为前端的配置文件,其中proxy_pass使用http协议访问127.0.0.1:8080这个后端地址。

以上配置一般不会出现问题,如果后端的IP地址出现了变更,那么就需要手动修改nginx的配置文件并reload。

如果proxy_pass使用了域名,如下:

proxy_pass http://zabbix-upstream.t.com:8080;

而且这个域名使用DDNS动态解析的方式,就会有一个问题:

nginx只会在nignx启动的时候解析域名并缓存,如果域名的解析变了,nignx也不会有任何动作。

这样会导致这个服务再也无法访问。

0x03 DEBUG

解决方法很简单,只需要将proxy_pass部分做一些改造:

server { 
... 
resolver [DNS IP 地址] valid=5s; 
set $[变量名] "http://ddns.domain.com:4430"; 
proxy_pass $[变量名]; 
... 
}

例如:

server { 
... 
resolver 114.114.114.114 valid=5s; 
set $upstream "http://ddns.domain.com:4430"; 
proxy_pass $upstream; 
... 
}

这里用了set变量这种方式,使用set这种指定变量的方式有一个特点:每次访问都会出发 {} 符号内的set。

这也就是说,每次访问都对运行一遍set。

而上面的proxy_pass配置会强制每一次访问都进行解析,同时使用resolver参数指定DNS和TTL。

resolver参数所指定的TTL优先级最高,可以覆盖DNS的TTL。如果DNS默认的TTL为60s,那么上面的配置会将TTL修改为5s。

这里还有个需要注意的地方,如果不是必要,不要再server段设定set,这在大流量的情况下会引发性能下降,如果可以,将set放置在location段会更好。

0x04 结语

问题解决,如果不是使用DDNS解析的域名作为upstream,请不要使用上述方法配置proxy_pass。另外要尽量减少set变量。

升级PHP 7.1并启用PHP-FPM

一个多月前把系统升级到了Debian Buster,同时Apache也升级到了2.4.27,然后就发现HTTP/2没法用了,因为那时忙别的事情,也就没去管它。

今天闲着无事,就翻了翻文档,才发现在Apache 2.4.27中,Apache MPM (Multi-Processing Module) prefork取消了对HTTP/2的支持。因此,准备随即切换到Apache MPM event。

但随之而来的一个新问题就是,Apache服务器下,PHP所使用的mod_php模块只能支持prefork,因此,同时要将PHP切换到php-fpm以在FastCGI模式下运行PHP。然后想想,不如同时把PHP升级到7.1版本算了。

首先要做的,就是卸载PHP 7.0,虽然直接安装也行,但我还是选择了卸载,反正留着也没用。如果有安装phpMyAdmin,因为依赖被卸载,所以也会连带被卸载,这里直接选择卸载重装。

apt-get purge phpmyadmin php7.0-gd php7.0-xml php7.0 php-pear php7.0-mysql php7.0-common
apt-get autoremove

然后重新安装PHP 7.1,可以一步安装完所有包,也可以分开安装。这里为了写得清楚一点,分开写。但需要注意的是,如果一步安装PHP 7.1基本包的同时安装php7.1-fpm,默认就不会安装包含了mod_php模块的libapache2-mod-php7.1,如果你要用mod_php,要么分开两步装,要么别装php7.1-fpm。

首先安装LAMP需求的包。

apt-get install php7.1 php-pear php7.1-mysql

然后是WordPress需求的包。

apt-get install php7.1-gd php7.1-xml

然后是php-fpm。

apt-get install php7.1-fpm

最后装回phpMyAdmin,需要注意的是,phpMyAdmin默认安装的需求包是php7.0-mbstring,在PHP 7.1下会提示缺少mbstring,这个问题困扰了好久!最后发现,直接选择安装php7.1-mbstring就解决了!

apt-get install phpmyadmin php7.1-mbstring

安装完成之后重新配置以下phpMyAdmin就行。可以参考这里:https://www.prinice.org/2016/06/29/33/

之后就是启用PHP-FPM了。

首先关闭Apache服务器。

service apache2 stop

再执行以下命令。

a2enmod proxy_fcgi setenvif
a2enconf php7.1-fpm
a2dismod php7.1
a2dismod mpm_prefork
a2enmod mpm_event

最后重新启动Apache,这样就大功告成了,很简单。然后测试一下,我遇到了些问题,最后发现是自己写的.htaccess里面有一些PHP语句需要更新,这方面注意一下。

一个不可思议的MySQL慢查分析与解决

一、前言

开发需要定期的删除表里一定时间以前的数据,SQL如下

mysql > delete from testtable WHERE biz_date <= '2017-08-21 00:00:00'  AND status = 2  limit 500G

前段时间在优化的时候,已经在相应的查询条件上加上了索引

KEY `idx_bizdate_st` (`biz_date`,`status`)

但是实际执行的SQL依然非常慢,为什么呢,我们来一步步分析验证下

二、分析

表上的字段既然都有索引,那么按照之前的文章分析,是两个字段都可以走上索引的。如果有疑问,请参考文章 10分钟让你明白MySQL是如何利用索引的

既然能够利用索引,表的总大小也就是200M左右,那么为什么形成了慢查呢?

我们查看执行计划,去掉limit 后,发现他选择了走全表扫描。

mysql > desc  select * from testtable   WHERE biz_date <= '2017-08-21 00:00:00';
+----+-------------+-----------+------+----------------+------+---------+------+--------+-------------+
| id | select_type | table     | type | possible_keys  | key  | key_len | ref  | rows   | Extra       |
+----+-------------+-----------+------+----------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | testtable | ALL  | idx_bizdate_st | NULL | NULL    | NULL | 980626 | Using where |
+----+-------------+-----------+------+----------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)

-- 只查询biz_date
-- 关键点:rows:980626;type:ALL 

mysql > desc  select * from testtable   WHERE biz_date <= '2017-08-21 00:00:00' and status = 2;
+----+-------------+-----------+------+----------------+------+---------+------+--------+-------------+
| id | select_type | table     | type | possible_keys  | key  | key_len | ref  | rows   | Extra       |
+----+-------------+-----------+------+----------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | testtable | ALL  | idx_bizdate_st | NULL | NULL    | NULL | 980632 | Using where |
+----+-------------+-----------+------+----------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)

-- 查询biz_date + status 
-- 关键点:rows:980632;type:ALL  


mysql > desc  select * from testtable   WHERE biz_date <= '2017-08-21 00:00:00' and status = 2 limit 100;
+----+-------------+-----------+-------+----------------+----------------+---------+------+--------+-----------------------+
| id | select_type | table     | type  | possible_keys  | key            | key_len | ref  | rows   | Extra                 |
+----+-------------+-----------+-------+----------------+----------------+---------+------+--------+-----------------------+
|  1 | SIMPLE      | testtable | range | idx_bizdate_st | idx_bizdate_st | 6       | NULL | 490319 | Using index condition |
+----+-------------+-----------+-------+----------------+----------------+---------+------+--------+-----------------------+
1 row in set (0.00 sec)

-- 查询biz_date + status+ limit 
-- 关键点:rows:490319;  

mysql > select count(*)  from testtable   WHERE biz_date <= '2017-08-21 00:00:00' and status = 2;
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.34 sec)


mysql > select count(*)  from testtable   WHERE biz_date <= '2017-08-21 00:00:00';
+----------+
| count(*) |
+----------+
|   970183 |
+----------+
1 row in set (0.33 sec)


mysql > select count(*)  from testtable;
+----------+
| count(*) |
+----------+
|   991421 |
+----------+
1 row in set (0.19 sec)


mysql > select distinct biz_status from whwtestbuffer;
+------------+
| biz_status |
+------------+
|          1 |
|          2 |
|          4 |
+------------+

通过以上查询,我们可以发现如下几点问题:

  • 通过 biz_date 预估出来的行数 和 biz_date + status=2 预估出来的行数几乎一样,为98w。
  • 实际查询表 biz_date + status=2 一条记录都没有。
  • 整表数据量达到了99万,MySQL发现通过索引扫描需要98w行(预估)

因此,MySQL通过统计信息预估的时候,发现需要扫描的索引行数几乎占到了整个表,放弃了使用索引,选择了走全表扫描。

那是不是他的统计信息有问题呢?我们重新收集了下表统计信息,发现执行计划的预估行数还是一样,猜测只能根据组合索引的第一个字段进行预估(待确定)

那我们试下直接强制让他走索引呢?

mysql > select * from testtable   WHERE biz_date <= '2017-08-21 00:00:00' and status = 2;
Empty set (0.79 sec)

mysql > select * from testtable force index(idx_bizdate_st)  WHERE biz_date <= '2017-08-21 00:00:00' and status = 2;
Empty set (0.16 sec)

我们发现,强制指定索引后,查询耗时和没有强制索引比较,的确执行速度快了很多,因为没有强制索引是全表扫描嘛!但是!依然非常慢!

那么还有什么办法去优化这个本来应该很快的查询呢?

大家应该都听说过要选择性好的字段放在组合索引的最前面?
是的,相对于status字段,biz_date 的选择性更加不错,那组合索引本身已经没有好调整了

那,能不能让他不要扫描索引的那么多范围呢?之前的索引模型中也说过,MySQL是通过索引去确定一个扫描范围,如果能够定位到尽可能小的范围,那是不是速度上会快很多呢?

并且业务逻辑上是定期删除一定日期之前的数据。所以逻辑上来说,每次删除都是只删除一天的数据,直接让SQL扫描一天的范围。那么我们就可以改写SQL啦!

mysql > select * from testtable WHERE biz_date >= '2017-08-20 00:00:00' and biz_date <= '2017-08-21 00:00:00' and status = 2;
Empty set (0.00 sec)

mysql > desc select * from testtable WHERE biz_date >= '2017-08-20 00:00:00' and biz_date <= '2017-08-21 00:00:00' and status = 2;
+----+-------------+------------------+-------+----------------+----------------+---------+------+------+-----------------------+
| id | select_type | table            | type  | possible_keys  | key            | key_len | ref  | rows | Extra                 |
+----+-------------+------------------+-------+----------------+----------------+---------+------+------+-----------------------+
|  1 | SIMPLE      | testtable        | range | idx_bizdate_st | idx_bizdate_st | 6       | NULL |  789 | Using index condition |
+----+-------------+------------------+-------+----------------+----------------+---------+------+------+-----------------------+
1 row in set (0.00 sec)

-- rows降低了很多,乖乖的走了索引

mysql > desc select * from testtable WHERE biz_date >= '2017-08-20 00:00:00' and biz_date <= '2017-08-21 00:00:00' ;
+----+-------------+------------------+-------+----------------+----------------+---------+------+------+-----------------------+
| id | select_type | table            | type  | possible_keys  | key            | key_len | ref  | rows | Extra                 |
+----+-------------+------------------+-------+----------------+----------------+---------+------+------+-----------------------+
|  1 | SIMPLE      | testtable        | range | idx_bizdate_st | idx_bizdate_st | 5       | NULL | 1318 | Using index condition |
+----+-------------+------------------+-------+----------------+----------------+---------+------+------+-----------------------+
1 row in set (0.00 sec)

-- 即使没有status,也是肯定走索引啦

三、小结

这个问题,我原本打算用hint,强制让他走索引,但是实际上强制走索引的执行时间并不能带来满意的效果。结合业务逻辑,来优化SQL,是最好的方式,也是终极法宝,一定要好好利用。不了解业务的DBA,不是一个好DBA… 继续去补业务知识去了。。

nfs软件服务利用ansible实现一键化部署

[root@m01 tools]# cat nfspeizhi.sh
cat >>/etc/exports<<EOF 
/data 172.16.1.0/24(rw,sync)
EOF
- hosts: 172.16.1.131 #服务端
tasks:
- name: yum 
shell: yum install -y nfs-utils rpcbind #安装nfs
- name: yunm
shell: yum -y install sshpass #安装密钥的软件
- name: chuangjianmulu
shell: mkdir -p /server/tools/ #创建所在配置的文件
- name: peizhi
copy: src=/server/tools/nfspeizhi.sh dest=/server/tools/nfspeizhi.sh
- name: yunxingjiaoben 
script: /server/tools/nfspeizhi.sh #运行脚本
- name: guanlimulu
shell: mkdir -p /data && chown -R nfsnobody.nfsnobody /data
- name: qidong 
shell: /etc/init.d/rpcbind start #启动
- name: kaijiqidong
shell: chkconfig rpcbind on && chkconfig nfs on
#设置密码文件
- hosts: 172.16.1.108
tasks:
- name: yum
shell: yum install -y nfs-utils rpcbind # 客户端
# - name: gui
# shell: umount -f /mnt
- name: guazai
shell: mount -t nfs 172.16.1.131:/data /mnt
- hosts: 172.16.1.141
tasks:
- name: yumh
shell: yum install -y nfs-utils rpcbind #客户端 
# - name: guih
# shell: umount -f /mnt 
- name: guazaih
shell: mount -t nfs 172.16.1.131:/data /mnt

未分类

Nginx用rsyslog转发日志的一些小坑

我们从Nginx的代码中可以看到,给syslog发通知的时候,tag后面跟了2个字符 冒号+空格,所以阿里云这里的文档完全是坑爹

if $syslogtag == 'nginx' then @@10.101.166.173:11111;ALI_LOG_FMT

这里判断的是$syslogtag,也就是这种配置

access_log syslog:server=ip:port,facility=local7,tag=nginx,severity=info combined;

这边配置tag为 nginx,而 $syslogtag 不会是 nginx,而是 nginx+冒号+空格

查了rsyslog文档,$syslogtag 的行为本来就是程序自己定的,(),真正需要的是 这个 $programname

所以这样的配置是可以work的:

cat /etc/rsyslog.d/nginx.conf

input(type="imuxsock" Socket="/var/log/nginx.sock" CreatePath="on")
# $template ALI_LOG_FMT,"2.3 streamlog_tag %timegenerated:::date-unixtimestamp% %fromhost-ip% %pri-text% %app-name% %syslogtag% %msg:::drop-last-lf%n"
template(name="ALI_LOG_FMT" type="string" string="2.3 streamlog_tag %timegenerated:::date-unixtimestamp% %fromhost-ip% %pri-text% %app-name% %syslogtag% %msg:::drop-last-lf%n")
if $programname == 'nginx' then @@127.0.0.1:11111;ALI_LOG_FMT
& ~

注意,最后的那个 $ ~ 表示被上条规则匹配的日志不在发送到别的地方,因为nginx的默认的facility 是 local7 和boot.log是一样的,会造成发送日志的同时 也写入到boot.log ,造成boot.log巨大,这也是一个坑点。

另外其实,可以自己配置nginx的日志格式 满足ilogtail的采集规则,这样可以少走一次rsysylog。这里的 streamlog_tag 对应阿里云的syslog采集日志的时候的log tag.