浏览器刷新304(Not Modified)和再次请求200(From Cache)结果对比

在做性能测试时,无意中发现一个事情:在一个图片资源已经本地缓存到浏览器并且未过期的情况下,刷新网页和再次请求返回的状态不一致。
以资源ETag=W/“PSA-aj-5xx_WUsSsC"为例:

再次请求:

repsonse=200,直接从从本地缓存中取资源。

Request URL:http://guoj.top/wp-content/uploads/2018/01/QQ%E6%88%AA%E5%9B%BE20180115140217.png
Request Method:GET
Status Code:200 OK (from cache)
Remote Address:47.93.55.78:80

Response Headers
HTTP/1.1 200 OK
Server: nginx/1.13.7
Content-Type: image/png
Content-Length: 8487
Connection: keep-alive
Accept-Ranges: bytes
X-Original-Content-Length: 24343
ETag: W/"PSA-aj-5xx_WUsSsC"
Date: Tue, 16 Jan 2018 08:32:27 GMT
Expires: Wed, 14 Feb 2018 05:59:18 GMT
Cache-Control: max-age=2496410

Request Headers
GET /wp-content/uploads/2018/01/QQ%E6%88%AA%E5%9B%BE20180115140217.png HTTP/1.1
Host: guoj.top
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4295.400 QQBrowser/9.7.12661.400
Accept: image/webp,image/*,*/*;q=0.8
Referer: http://guoj.top/
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Cookie: Hm_lvt_624adbfe276a5668e7b4779815c5ff38=1513561518; Hm_lvt_7e91fd8ec5e72f05612cc7e567977104=1513561518; wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_50ac8821fe935de01bdede6b95928a78=dong4stop%7C1516241303%7CRg3hAvZn7NOjg2mST5JurlQ55m4pDmbTzuiMGDygRfn%7Ccb8c3ee4f27ffba3171f763e4df91e2bb1514bfb5167a8af59a20cbc2dac74ec; wp-settings-1=editor%3Dtinymce%26libraryContent%3Dbrowse%26mfold%3Do%26editor_expand%3Don%26hidetb%3D1%26post_dfw%3Doff%26widgets_access%3Doff%26advImgDetails%3Dshow; wp-settings-time-1=1516087140; _GPSLSC=qEFEXaHVp1!Yd4ct0hstK!DAGQ2tgLU_

刷新网页

不同浏览器的效果不一样,又或者做了特别的设置造成。chrome会返回200(From Cache)。qqbrowser会返回304(Not Modified)。
这是因为qqbrowser刷新网页时在Request Header中加入了:
Cache-Control:max-age=0
If-None-Match:W/“PSA-aj-5xx_WUsSsC”;

Request URL:http://guoj.top/wp-content/uploads/2018/01/QQ%E6%88%AA%E5%9B%BE20180115140217.png
Request Method:GET
Status Code:304 Not Modified
Remote Address:47.93.55.78:80

Response Headers
HTTP/1.1 304 Not Modified
Server: nginx/1.13.7
Date: Tue, 16 Jan 2018 08:36:10 GMT
Connection: keep-alive

Request Headers
Accept:image/webp,image/*,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Cookie:Hm_lvt_624adbfe276a5668e7b4779815c5ff38=1513561518; Hm_lvt_7e91fd8ec5e72f05612cc7e567977104=1513561518; wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_50ac8821fe935de01bdede6b95928a78=dong4stop%7C1516241303%7CRg3hAvZn7NOjg2mST5JurlQ55m4pDmbTzuiMGDygRfn%7Ccb8c3ee4f27ffba3171f763e4df91e2bb1514bfb5167a8af59a20cbc2dac74ec; wp-settings-1=editor%3Dtinymce%26libraryContent%3Dbrowse%26mfold%3Do%26editor_expand%3Don%26hidetb%3D1%26post_dfw%3Doff%26widgets_access%3Doff%26advImgDetails%3Dshow; wp-settings-time-1=1516087140; _GPSLSC=qEFEXaHVp1!Yd4ct0hstK!DAGQ2tgLU_
Host:guoj.top
If-None-Match:W/"PSA-aj-5xx_WUsSsC"
Referer:http://guoj.top/
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4295.400 QQBrowser/9.7.12661.400

ansible简介

Ansible 是一个基于 Python 的自动化运维的工具,无需安装服务端和客户端,只需要有ssh即可,而且使用简单。同类的产品Puppet、Chef、SaltStack都是基于服务端+客户端的模式。 官方称之为 “Ansible is Simple IT Automation”。

官网 github

安装

sudo apt-get install software-properties-common
sudo apt-add-repository ppa:ansible/ansible
sudo apt-get update
sudo apt-get install ansible

命令应用基础

ansible [-f forks] [-m module_name] [-a args]

-f forks:启动的并发线程数

-m module_name: 要使用的模块

-a args: 模块特有的参数

ansible-doc -l 查看所有模块

ansible-doc -s MODULE_NAME 查看指定模块的详细帮助

查看全部模块文档

  • 使用lineinfile模块向/tmp/test写入一行helloworld
ansible 127.0.0.1 -m lineinfile -a "dest=/tmp/test line='helloworld'"
  • 使用git模块拉取资源到/tmp/ansible目录
ansible 127.0.0.1 -m git -a "repo='https://github.com/ansible/ansible.git' dest='/tmp/ansible'

playbook

playbook是ansible中批量执行命令的文件,基于yaml格式,类似于chef中的cookbook。

标准的playbook如下:

- hosts: webservers
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root
  tasks:
  - name: ensure apache is at the latest version
    yum: pkg=httpd state=latest
  - name: write the apache config file
    template: src=/srv/httpd.j2 dest=/etc/httpd.conf
    notify:
    - restart apache
  - name: ensure apache is running
    service: name=httpd state=started
  handlers:
    - name: restart apache
      service: name=httpd state=restarted
  • 检查一个playbook
ansible-playbook deploy.yml --check
  • 执行一个playbook
ansible-playbook playbook.yml -f 10

nginx模块ngx_pagespeed配置

官方文档 性能测试

http{
        # 启用ngx_pagespeed
        pagespeed on;

        pagespeed Statistics on;
        pagespeed StatisticsLogging on;
        pagespeed LogDir /var/log/pagespeed;
        pagespeed FileCachePath /tmp/cache/ngx_pagespeed_cache;
        # 隐藏pagespeed版本信息
        pagespeed XHeaderValue "Powered By ngx_pagespeed";
        # google字体直接写入html 目的是减少浏览器请求和DNS查询 
        pagespeed EnableFilters inline_google_font_css;
        pagespeed RewriteLevel PassThrough;
        # 改善资源的可缓存性
        pagespeed EnableFilters extend_cache;
        # 预解析DNS查询 
        pagespeed EnableFilters insert_dns_prefetch;

        pagespeed EnableFilters local_storage_cache;
        # 删除无用的url前缀 
        pagespeed EnableFilters trim_urls;
        # 合并head
        pagespeed EnableFilters combine_heads;
        # 移除多余html标签
        pagespeed EnableFilters elide_attributes;
        # 移除html空白
        pagespeed EnableFilters collapse_whitespace;
        # 移除html注释
        pagespeed EnableFilters remove_comments;
        # 移除html属性中的不必要的引号
        pagespeed EnableFilters remove_quotes;

        # css
        # 合并css 
        pagespeed EnableFilters combine_css;
        # 压缩css 
        pagespeed EnableFilters rewrite_css;
        # 将css内容移动到script之前,优先于script渲染
        pagespeed EnableFilters move_css_above_scripts;
        pagespeed EnableFilters move_css_to_head;
        # 重写CSS,首先加载渲染页面的CSS规则 
        pagespeed EnableFilters prioritize_critical_css;
        pagespeed EnableFilters flatten_css_imports;
        pagespeed CssFlattenMaxBytes 5120;

        # js
        # 合并js
        pagespeed EnableFilters combine_javascript;
        # 压缩js
        pagespeed EnableFilters rewrite_javascript;
        pagespeed EnableFilters defer_javascript;
        # 将小的js文件已内联方式引入,避免http请求
        pagespeed EnableFilters inline_javascript;


        # image
        # 延时加载客户端看不见的图片
        pagespeed EnableFilters lazyload_images;
        # 压缩图片
        pagespeed EnableFilters rewrite_images;
        # 将小图片的http调用转成内联方式调用
        pagespeed EnableFilters inline_images;
        pagespeed EnableFilters inline_preview_images;
        # 自动将多张背景图片合并成一张图片。
        pagespeed EnableFilters sprite_images;
        pagespeed EnableFilters dedup_inlined_images;
        pagespeed EnableFilters responsive_images_zoom;
        # 移动端图片自适应重置
        pagespeed EnableFilters resize_mobile_images;

        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
}

Linux-PAM模块简介

Linux-PAM工程的目的就是分离应用软件和验证机制的开发。通过验证函数库可以实现上述目的,一个应用程序可以使用这些函数库去进行用户的认证。

模块pam_*.so以动态可加载目标文件(使用dloptn(3)函数打开)的形式保存在 /lib/security、 /lib64/security、/lib/x86_64-linux-gnu/security/等。

配置文件:

  • /etc/pam.conf
  • /etc/pam.d/
  • /etc/security/*(其他PAM环境的配置文件)。 以/etc/pam.d/sudo配置为例: [table id=3 /]
验证类型 控制标记 模块路径 模块参数
session required pam_env.so readenv=1 envfile=/etc/default/locale user_readenv=0

验证类型

名称 说明
aut 用于检查用户和密码,并分配权限。
account 负责账户合法性检查,确认帐号是否过期,是否有权限登录系统等;
password 修改密码需要用到的。如果用户不修改密码,几乎用不到这个模块。
session 提供对会话的管理,限定会话限制的。比如:vsftpd下午6点不允许访问,那6点过后用户再去访问的话就会被限制,或内存不足不允许访问等。

控制标记

控制 说明
requuisite 与required类似,该模块必须返回成功才能通过认证。一旦失败就不再执行堆中后面的其他模块,并且鉴别过程到此结束,同时也会立即返回错误信息。
required 通过鉴别的必要条件。换句话说,只有当对应于应用程序的所有带 required标记的模块全部成功后,该程序才能通过鉴别。同时,如果任何带required标记的模块出现了错误,PAM并不立刻将错误消息返回给应用程序,而是在所有模块都调用完毕后才将错误消息返回调用他的程序。 反正说白了,就是必须将所有的模块都执行一次,其中任何一个模块验证出错,验证都会继续进行,并在执行完成之后才返回错误信息。这样做的目的就是不让用户知道自己被哪个模块拒绝,通过一种隐蔽的方式来保护系统服务。
sufficient 如果本条目的条件被满足,且本条目之前没有任何required条目失败,则立即返回“认证成功”信号;如果对本条目的验证失败,不对结果造成影响。
sufficient 表明本模块返回成功已经足以通过身份认证的要求,不必再执行同一stack内的其它模块,但是如果本模块返回失败的话可以忽略。可以认为是一个充分条件。
optional 表明本模块是可选的,它的成功与否一般不会对身份认证起关键作用,其返回值一般被忽略。即便该行所涉及的模块验证失败用户仍能通过认证。在PAM体系中,带有该标记的模块失败后将继续处理下一模块。也就是说即使本行指定的模块验证失败,也允许用户享受应用程序提供的服务。使用该标志,PAM框架会忽略这个模块产生的验证错误,继续顺序执行下一个层叠模块。
substack 运行其他配置文件中的流程,并将整个运行结果作为该行的结果进行输出。该模式和 include的不同点在于认证结果的作用域:如果某个流程栈include了一个带requisite的栈,这个requisite
include 在验证过程中调用其他的PAM配置文件。

模块路径

名称 说明
pam_unix.so 传统意义上的帐号和密码认证机制,这个机制实现了标准C库中基于让用户输入帐号密码并完成检测的认证过程。
pam_permit.so 直接通过,允许访问,定义默认策略。
pam_deny.so 拒绝访问,定义默认策略。
pam_cracklib.so 用来检验密码的强度,包括设定的密码是否在字典中,修改的密码是否能和上次一样,密码至少包含多 少个数字字符,可以输入多少次错误密码等,都是由这个模块定义的。
pam_shells.so 检查用户登录的shell是否是安全shell,也就是写在 /etc/shells中的shell
pam_securetty.so 限定管理员只能通过安全的tty登录,/etc/securetty,tty就是传统终端
pam_rootok.so 管理员su到其他用户不用输入密码就是靠这个定义的。
pam_nologin.so 可以限制一般用户是否能够登入主机,当/etc/nologin这个档案存在时,则所有一般使用者均无法再登入系统。
pam_limits.so 资源限定打开文件数,使用进程数等等,对任何人都生效,/etc/security/limits或/etc/security/limits.d/*。

Capistrano v3 软链接

本地、测试、生产环境的不同,可能需要不同的配置文件。为了避免每次推送版本都修改配置文件,可以事先将配置文件放置在服务器端,推送完版本后通过软链接指向即可。
通过linked_files、linked_dirs可以将文件、目录链接到shared目录下的文件、目录。
例如:

shared的目录结构

shared/
  
├── conf 
│   ├── database.conf 
│   └── global.conf 
├── main.conf
└── resources

配置文件

append :linked_files, "main.conf"
append :linked_dirs, "conf", "resources"

推送版本的目录结构

注意:目录链接会导致原有目录下的文件丢失

├── conf -> /tmp/stock/shared/conf
├── main.conf -> /tmp/stock/shared/main.conf
├── README.md
├── resources -> /tmp/stock/shared/resources
└── REVISION

Capistrano v3修改部署后文件目录权限

在部署完项目后,可能会需要对部署好的项目文件和目录做一些权限上的更改。可以,通过下面两种方式的任务完成。其它,个性要求同理。

注意:capistrano v2中的latest_release,在capistrano v3已变更为release_path

namespace :permission do
    desc "permission update"
    task :update do
        on roles(:app), in: :sequence, wait: 5 do
            execute :echo, "hello"
            execute :chown, "-R www:www #{release_path}"
	    execute :chmod, "-R 755 #{release_path}"
        end
    end
end

namespace :deploy do
    after :finishing, "permission:update"
end

或者

namespace :permission do
    desc "permission update"
    task :update do
        on roles(:all), in: :sequence, wait: 5 do
            execute :echo, "change start"
            within release_path  do
                 execute :chown, "-R www:www *"
				 execute :chmod, "-R 755 #{release_path}"
            end
        end
    end
end

namespace :deploy do
    after :finishing, "permission:update"
end

Capistrano v3推送指定版本

capistrano v3使用属性branch控制版本信息,默认值是:master。 实际中,经常需要根据测试、生成环境发布不同的版本。

修改deploy.rb

set :branch, ENV["REVISION"] || ENV["BRANCH_NAME"] || "master"

或者

set :branch, ENV.fetch("REVISION", "master")

推送v1.0版本则运行:

REVISION=v1.0 cap production deploy

推送master则运行:

cap production deploy

gogs后台守护运行

后台脚本 在%GOGS_HOME%/scripts目录下,已经包含了各个系统的脚本,只需要稍微修改即可添加到自启动。

root@iZ2ze9hvf7pey4vrxv9r8gZ:/usr/local/gogs# tree scripts/
scripts/
├── autoboot.sh
├── build_freebsd.sh
├── build_linux64.sh
├── build.sh
├── init
│   ├── centos
│   │   └── gogs
│   ├── debian
│   │   └── gogs
│   ├── freebsd
│   │   └── gogs
│   ├── gentoo
│   │   └── gogs
│   ├── openbsd
│   │   └── gogs
│   └── suse
│       └── gogs
├── launchd
│   └── io.gogs.web.plist
├── mysql.sql
├── README
├── supervisor
│   └── gogs
├── systemd
│   └── gogs.service
└── windows
    └── install-as-service.bat

以Ubuntu16、gogs-v0.11.34.1122为例:

复制脚本并赋予执行权限

cp scripts/init/debian/gogs /etc/init.d/
chmod +x /etc/init.d/gogs
cp scripts/systemd/gogs.service /lib/systemd/system/
chmod +x /lib/systemd/system/gogs.service

修改配置

/etc/init.d/gogs /etc/init.d/gogs /lib/systemd/system/gogs.service /lib/systemd/system/gogs.service

启动

service gogs restart

或者

/etc/init.d/gogs restart

ansible git模块

git模块文档

ansible 127.0.0.1 -m git -a "repo='https://github.com/ansible/ansible.git' dest='/tmp/ansible'"

通过用户名和密码拉取git代码

---
- hosts: all 
  gather_facts: no
  become: yes
  tasks:
    - name: install git package
      apt:
        name: git

    - name: Get updated files from git repository 
      git: 
        repo: "http://{{ githubuser | urlencode }}:{{ githubpassword | urlencode }}@github.com/dong4stop/hello.git"
        dest: /tmp/git
        version: v1.0

若密码中有特殊字符可以加上urlencode,{{ githubpassword | urlencode }}。

ansible-playbook git.yml -e "githubuser=*\*\\*\*"; -e "githubpassword=\*\**";

nginx与php-fpm权限不一致问题

在使用wordpress时,发现一些目录及文件读写权限的问题。
目录已设置为755权限。
检查后,发现是nginx与php-fpm使用的用户和用户组不一致导致的。

PHP-FPM用户和用户组

vi /etc/php/5.6/fpm/pool.d/www.conf

/etc/init.d/php5.6-fpm restart

Nginx用户和用户组

vi /etc/nginx/nginx.conf

nginx -t
nginx -s reload