MacOS 下 Docker 容器内挂载的文件内外不一致问题

Docker挂载的文件,在外部修改后,容器内不生效问题

问题

MacOS,装了vbox,在里面运行的Docker,拉了一个 openresty-alpine镜像,发现volume挂载的文件,通过tail -n 100 /usr/share/nginx/xx.lua, 和 cat /usr/share/nginx/xx.lua 两个命令展示的结果不一致。

我想大家也会有类似的,在IDE编辑了代码,发现Docker容器内的文件没变化这样的问题。

解决否

已解决

方案

version: "2"
services:
    php:
        image: php
        volumes:
            - /mnt/vbox/compose/bs/php/:/var/www/html/:rw,cached

最简单粗暴的就是在rw后面加上cached,至于原因,见下面的官方解释,以及国内大牛讲解。

官方解释:link

国内大佬的总结:blog

MySQL 查询优化,explain 各个字段指标说明

MySQL explain 优化sql时,你知道 select_type, type, possible_keys, key, key_len,ref, row, Extra 这些个字段是代表什么意思?那就来看看吧

explain

别名:desc

例子些

  • 例子1:
select * from `tuanmei_deals` where deal_id = 23421;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE tuanmei_deals const PRIMARY PRIMARY 4 const 1 NULL

例子2:

select * from `tuanmei_deals` where ( `end_time` > '1592234464' ) limit 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE tuanmei_deals range end_time end_time 4 NULL 234142 Using index condition; Using MRR
  • 例子3:
select * from `tuanmei_deals` where hash_id = 'ht2020517p51688' or ( `end_time` > '1592234464' ) limit 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE tuanmei_deals index_merge hash_id,end_time,idx_HashId_StartTm hash_id,end_time 32,4 NULL 234143 Using sort_union(hash_id,end_time); Using where

id, table

Id 就不说了,table就是你查阅了哪个表,key就是实际用到的索引

select_type

查询类型,就是我们从sql语法角度来看,会被拆封成什么任务

(1) SIMPLE(简单SELECT,不使用UNION或子查询等), 比如上面的一个单表查询

(2) PRIMARY(查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)

(3) UNION(UNION中的第二个或后面的SELECT语句) 如果你使用了union了多个select 集合

(4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)

(5) UNION RESULT(UNION的结果)

(6) SUBQUERY(子查询中的第一个SELECT), 例如你用到了 where in (select )

(7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,取决于外面的查询)

(8) DERIVED(派生表的SELECT, FROM子句的子查询)

(9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)

type

ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行

index: Full Index Scan,index与ALL区别为index类型只遍历索引树

range:只检索给定范围的行,使用一个索引来选择行

ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件。触发条件:只匹配到一行的时候。除了system和const之外,这是最好的连接类型了。当我们使用主键索引或者唯一索引的时候,且这个索引的所有组成部分都被用上,才能是该类型。

const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system。system的触发条件:表只有一行,这是一个const type 的特殊情况。

NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。

possible_keys

指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用

key列显示MySQL实际决定使用的键(索引)

key

如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。

key_len

表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)

不损失精确性的情况下,长度越短越好。

key_len 表示一行数据该索引占用的数据宽度,比如对一个 字段类型为 int 建立索引,那么索引的key_len 就是 4。和数量多少没有关系。

ref

显示索引的哪一列被使用了,如果可能的话,是一个常数

表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

rows

表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数, 注意:这是预估值,非实际值

Extra

该列包含MySQL解决查询的详细信息

  • Using index:表示使用索引,如果只有 Using index,说明他没有查询到数据表,只用索引表就完成了这个查询,这个叫覆盖索引。如果同时出现Using where,代表使用索引来查找读取记录, 也是可以用到索引的,但是需要查询到数据表。
  • Using where:表示条件查询,如果不读取表的所有数据,或不是仅仅通过索引就可以获取所有需要的数据,则会出现 Using where。如果type列是ALL或index,而没有出现该信息,则你有可能在执行错误的查询:返回所有数据。
  • Using MRR:MMR全称是Multi-Range Read,是MYSQL5.6优化器的一个新特性,在MariaDB5.5也有这个特性。优化的功能在使用二级索引做范围扫描的过程中减少磁盘随机IO和减少主键索引的访问次数。将随机IO转换为顺序IO
  • Using filesort:不是“使用文件索引”的含义!filesort是MySQL所实现的一种排序策略,通常在使用到排序语句ORDER BY的时候,会出现该信息。
  • Using temporary:表示为了得到结果,使用了临时表,这通常是出现在多表联合查询,结果排序的场合。

MRR和没有MRR的区别

给出一个简单的例子,在innodb表执行下面的查询:

SELECT non_key_column FROM tbl WHERE key_column=x

在没有MRR的情况下,它是这样得到结果的:

1.  select key_column, pk_column from tb where key_column=x order  by key_column ---> 假设这个结果集是t2.  for each row in t ; 
select non_key_column from tb where pk_column = pk_column_value。(在oracle里第2步叫回表)在有MRR的情况下,它是这样执行的:
1.  select key_column, pk_column from tb where key_column = x  order by key_column ---> 假设这个结果集是t
2.  将结果集t放在buffer里面(直到buffer满了),然后对结果集t按照pk_column排序 ---> 假设排序好的结果集是t_sort
3.  select non_key_column fromtb where pk_column in (select pk_column from t_sort)

两者的区别主要是两点:

  1. 没有MRR的情况下,随机IO增加,因为从二级索引里面得到的索引元组是有序,但是他们在主键索引里面却是无序的,所以每次去主键索引里面得到non_key_column的时候都是随机IO。(如果索引覆盖,那也就没必要利用MRR的特性了,直接从索引里面得到所有数据)

  2. 没有MRR的情况下,访问主键索引的次数增加。没有MRR的情况下,二级索引里面得到多少行,那么就要去访问多少次主键索引(也不能完全这样说,因为mysql实现了BNL),而有了MRR的时候,次数就大约减少为之前次数t/buffer_size。

关于 Explain 的相关注意事项

总结:
– • EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
– • EXPLAIN不考虑各种Cache
– • EXPLAIN不能显示MySQL在执行查询时所作的优化工作
– • 部分统计信息是估算的,并非精确值
– • EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划。

show profile

show profile作用:
能够查出最近15条SQL语句的运行状态(包含运行过程中执行了哪些操作,各占用了多长时间),以便开发者的分析。

1、查看MySQL的版本是否支持show profie
2、查看是否已经开启show profile

$ SHOW VARIABLES LIKE 'profiling';

3、开启功能,默认是关闭
SET profiling=ON;
SHOW VARIABLES LIKE ‘profiling’;

4、运行sql
随便运行几条SQL,以便于show prifiles的日志分析。
5、查看结果
show profiles;

6、诊断SQL
用于单独分析某条sql,查看某条sql的生命周期以及各占用多少时间。
SHOW PROFILE cpu, block io FOR QUERY id;
id为show profiles查出来的某条记录的id


set profiling=1; //打开分析 run your sql1; run your sql2; show profiles; //查看sql1,sql2的语句分析 show profile for query 1; //查看sql1的具体分析 show profile ALL for query 1; //查看sql1相关的所有分析【主要看i/o与cpu,下边分析中有各项意义介绍】 set profiling=0; //关闭分析

引用

  • https://mengkang.net/1124.html
  • https://www.cnblogs.com/fu-yong/p/8496368.html
  • https://www.cnblogs.com/kubidemanong/p/10734045.html
  • https://blog.csdn.net/liang_0609/article/details/44040357
  • https://zhuanlan.zhihu.com/p/100427746
  • https://blog.csdn.net/mingover/article/details/79066064
  • https://www.tuicool.com/articles/ZFrUzia
  • https://blog.csdn.net/lihuayong/article/details/42044593
  • https://www.cnblogs.com/xuanzhi201111/p/4175635.html

WordPress 禁用feeds订阅

我用的百度BCE搭建的该站点,这天它检查我的站点后,告知我一个安全隐患,吓我一跳,赶紧解决啊

因何而起

百度检查我的站点发现一个安全隐患:

http://blog.itjsz.com/?cat=http%3A%2F%2Fcirt.net%2Frfiinc.txt&feed=rss2

其实呢,这就是一个rss订阅功能,作为一个小博主,没有必要。

设置

这里可以限制feed输出,但不能完全限制。

wordpress setting

插件禁用

有个插件 disable feeds

disable feeds

好久没更新了,不知能用不。

手动改代码

这里需要改动,你正在使用的主题文件。

<?php
// WordPress/wp-content/themes/xxx/function.php
function wpjam_disable_feed() {
    wp_die(__('<h1>本博客不再提供 Feed,请访问网站<a href="'.get_bloginfo('url').'">首页</a>!</h1>'));
}
add_action('do_feed',      'wpjam_disable_feed', 1);
add_action('do_feed_rdf',  'wpjam_disable_feed', 1);
add_action('do_feed_rss',  'wpjam_disable_feed', 1);
add_action('do_feed_rss2', 'wpjam_disable_feed', 1);
add_action('do_feed_atom', 'wpjam_disable_feed', 1);

没有生效,尝试切换主题,多刷新试试。

Mac Homebrew 使用

HomeBrew 是 MacOS 上使用非常广泛的包管理工具. 他有着自由开放特点,广受喜爱。作为程序员,它太好用了,必须学会使用brew

是什么

HomeBrew 是 MacOS 上使用非常广泛的包管理工具. 他有着自由开放特点,广受喜爱。

好比 Debian 上的 apt-get, CentOS 上的 yum。

安装

## 官方推荐的默认安装方式
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

## 手动安装方式
$ mkdir homebrew && curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew

试试看,安装好没有。

## 检查版本
$ brew -v

通过brew安装的文件会自动设置环境变量,所以不用担心命令行不能启动的问题。 比如安装好了gradle,即可运行 gradle -v。

包管理

HomeBrew 软件的命令入口是 brew.

注意,使用HomeBrew软件不要加上sudo权限,哪怕是有报错,或者提示没有权限覆盖系统自带软件,也不要加sudo!

## 检查版本
$ brew -v

## 帮助
$ brew --help

## 安装一个软件
$ brew install wget

## 卸载软件
$ brew uninstall wget

## 通过 *.rb 文件的方式安装软件,如:mpv
$ wget https://raw.githubusercontent.com/Homebrew/homebrew-core/master/Formula/mpv.rb
$ brew install ./mpv.rb

## 搜索软件 vim
$ brew search vim

升级软件

## 升级 HomeBrew
$ brew update

## 升级所有已过时的软件,(这里软件指,通过brew安装的软件)
$ brew upgrade

## 指定升级某个软件
$ brew upgrade python

## 升级所有软件包,包裹未清理干净的旧版本包
$ brew upgrade --all
  • 不让某些包的升级
## 锁住 git,不让其更新
$ brew pin git

## 解锁 git
$ brew unpin git

卸载 & 清理

## 清理所有旧版本的软件包
$ brew cleanup

## 
$ brew cleanup -n

## 清理具体的一个包 node
$ brew cleanup node

## 强制卸载,不管依赖
$ brew unistall <fromula> --force

## 移除软件包
$ brew remove <fromula> 

查看

HomeBrew 安装的软件会放到文件夹 /usr/local/Cellar/ 下.

## 查看已安装列表
$ brew list

## 查看一个具体软件信息, 如 nginx
$ brew info nginx

## 查看各个包的依赖关系
$  brew deps

## 查看已安装的包的依赖,树形显示
$ brew deps --installed --tree

通过依赖关系,就能知道哪些包还在使用。

为 HomeBrew 软件,新增图标

$ brew linkapps mpv

HomeBrew 管理

自检

如果你的 Hombrew 没有办法正常的工作,你可以执行 brew doctor 来开启 Homebrew 自带的检查,从而确认有哪些问题,并进行修复。

服务

诸如 Nginx、MySQL 等软件,都是有一些服务端软件在后台运行,如果你希望对这些软件进行管理,可以使用 brew services 命令来进行管理

好比是 Linux 上的 systemctl

## 查看所有服务
$ brew services list

## 单次运行某个服务 nginx
$ brew services run nginx

## 运行某个服务,并设置开机自动运行。 sleepwatcher
$ brew services start sleepwatcher 

## 停止某个服务 nginx
$ brew services stop nginx

## 重启某个服务 nginx
$ brew services restart nginx

HomeBrew 加速

换源

  • 中科大 镜像
cd "$(brew --repo)"
git remote set-url origin git://mirrors.ustc.edu.cn/brew.git
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin git://mirrors.ustc.edu.cn/homebrew-core.git
  • 清华大学 镜像
git -C "$(brew --repo)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git

git -C "$(brew --repo homebrew/core)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core.git

网络代理

brew支持全局socks代理,使用前打开终端,加上这一句:


$ export ALL_PROXY=socks5://127.0.0.1:port ## 或者仅这条命令使用代理 $ ALL_PROXY=socks5://127.0.0.1:port brew upgrade

结语

(完)

PHP Opcache 使用

Opcache 是PHP上简单好用,立马见效的优化神器,鸟哥都推荐,那我也要用啊。

Opcache 介绍

Opcache 呢。它的目标是提供一个自由、 开放,和健全的框架用于缓存和优化PHP的中间代码。

OPcache 通过将 PHP 脚本预编译的字节码存储到共享内存中来提升 PHP 的性能, 存储预编译字节码的好处就是 省去了每次加载和解析 PHP 脚本的开销。

PHP 5.5.0 及后续版本中已经绑定了 OPcache 扩展。 对于 PHP 5.25.35.4 版本可以使用 » PECL 扩展中的 OPcache 库。

— 摘自 PHP.net

注意,它和 Alternative PHP Cache (APC) 是一个开放自由的PHP opcode 缓存,是两个东西,别搞混了。

安装

PHP 5.5.0 及后续版本

OPcache 只能编译为共享扩展。 如果你使用 --disable-all 参数 禁用了默认扩展的构建, 那么必须使用 --enable-opcache 选项来开启 OPcache。

编译之后,就可以使用 zend_extension 指令来将 OPcache 扩展加载到 PHP 中。

PHP 5.4 以及更低版本

pecl 下载安装

运行时配置

/php/php.ini

[opcache]
; dll地址
zend_extension=php_opcache.dll

; 启用该拓展打开
opcache.enable=1

; 在cli模式页开启opcache加速 
opcache.enable_cli=1

; 可用内存, 酌情而定, 单位为:Mb
opcache.memory_consumption=128

; Zend Optimizer + 暂存池中字符串的占内存总量.(单位:MB)
opcache.interned_strings_buffer=8

; 对多缓存文件限制, 命中率不到 100% 的话, 可以试着提高这个值
opcache.max_accelerated_files=4000

; 启用,那么 OPcache 会每隔 opcache.revalidate_freq 设定的秒数 检查脚本是否更新。如果禁用此选项,你必须使用 opcache_reset() 或者 opcache_invalidate() 函数来手动重置 OPcache,也可以 通过重启 Web 服务器来清空
opcache.validate_timestamps=0

; Opcache 会在一定时间内去检查文件的修改时间, 这里设置检查的时间周期, 默认为 2, 设置为 0 会导致针对每个请求, OPcache 都会检查脚本更新。单位:秒。 
opcache.revalidate_freq=60

; 打开快速关闭, 打开这个在PHP Request Shutdown的时候回收内存的速度会提高
opcache.fast_shutdown=1

; opcache 不保存注释,减少opcode大小
opcache.save_comments=0


; 启用或禁用在共享内存中的 opcode 缓存。
opcache.file_cache_only=0

;设置不缓存的黑名单
; opcache.blacklist_filename=/png/php/opcache_blacklist

; 配置二级缓存目录并启用二级缓存。 默认值为空字符串 "",表示禁用基于文件的缓存。
opcache.file_cache=/var/www/html/php_cache/
; opcache.file_cache=/var/www/php/cache

更多配置见: php.net

配置好之后,我们运行phpinfo试试看。

如果能看到这界面,说明这个拓展装好了,

注意看到标红,这个说明命中次数,为啥7次呢,因为这个页面我刷行了7次。

使用

opcache_compile_file

该函数可以用于在不用运行某个 PHP 脚本的情况下,编译该 PHP 脚本并将其添加到字节码缓存中去。 该函数可用于在 Web 服务器重启之后初始化缓存,以供后续请求调用。

<?php
/**
* @params string $file 被编译的 PHP 脚本的路径。
* @return boolean 便已成功否
*/
function opcache_compile_file ( string $file ) : boolean

注意事项,Opcache 倾向于编译面向对象编程的代码。并且是在不运行脚本的情况下去编译,也就是它不会判断该脚本在运行时,哪些代码肯定会被执行,哪些不会被执行。也不会判断你的代码执行顺序。它会假设你的代码都会被执行,所以,一些函数的重复定义,会报错。

opcache_invalidate

该函数的作用是使得指定脚本的字节码缓存失效。 如果 force 没有设置或者传入的是 FALSE,那么只有当脚本的修改时间 比对应字节码的时间更新,脚本的缓存才会失效。

<?php
/**
 * @param string $script    缓存需要被作废对应的脚本路径
 * @param bool   $force     
如果该参数设置为TRUE,那么不管是否必要,该脚本的缓存都将被废除。
 * @return bool 成功否,如果脚本的字节码缓存失效设置成功或者该脚本本来就没有缓存,则返回 TRUE;如果字节码缓存被禁用,则返回FALSE。
 */
function opcache_invalidate ( string $script [, boolean $force = FALSE ] ) : boolean

opcache_is_script_cached

此函数检查PHP脚本是否已缓存在OPCache中。这可用于更轻松地检测特定脚本的缓存“变化”。

<?php
/**
 * @param string $file  需要被检查的脚本路径
 * @return bool 如果被Opcache缓存就返回true
 */
function opcache_is_script_cached ( string $file ) : bool

opcache_reset

该函数将重置整个字节码缓存。 在调用 opcache_reset() 之后,所有的脚本将会重新载入并且在下次被点击的时候重新解析。

<?php
/**
 * @return bool 如果字节码缓存被重置成功,则返回 TRUE;如果字节码缓存被禁用,则返回 FALSE。
 */
function opcache_reset ( void ) : boolean

使用说明: 该函数不能和 opcache_compile_file 函数在同一个脚本生命周期调用。 reset 需要用脚本单独调用。

实战

<?php
// file: opcach_init.php
define('DS', DIRECTORY_SEPARATOR);
$basePath = $argv[1];
if (empty($basePath)) {
    $basePath = __DIR__ . DS . '..' . DS . 'php_project';
}
//opcache_reset();  // 不能先reset,再刷缓存,需要在另外一个脚本运行。
//sleep(2);
opcache_compile_files($basePath);
function opcache_compile_files($dir) {
    foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) as $v) {
        if(!$v->isDir() && preg_match('%\.php$%', $v->getRealPath())) {
            opcache_invalidate($v->getRealPath(), true);
            opcache_compile_file($v->getRealPath());
            echo $v->getRealPath()."\n";
        }
    }
}

PHP cli 模式下运行该命令,就会为该目录,以及子目录下php文件生成Opcache 缓存。

$ php ./opcach_init.php ./../php_project/

cachetool

官方网站github

兼容性

  • CacheTool 5.x works with PHP >=7.2
  • CacheTool 4.x works with PHP >=7.1
  • CacheTool 3.x works with PHP >=5.5.9
  • CacheTool 2.x works with PHP >=5.5.9
  • CacheTool 1.x works with PHP >=5.3.3

下载

  1. githup 下载 cachetool.phar:
  1. 从 composer 下载
$ composer require gordalina/cachetool

$ composer require gordalina/cachetool:~1.0

使用


$ php cachetool.phar --help $ php cachetool.phar apcu:cache:info --fcgi $ php cachetool.phar apcu:cache:info --fcgi=127.0.0.1:9000 $ php cachetool.phar opcache:status --fcgi=/var/run/php5-fpm.sock $ php cachetool.phar opcache:status --cli $ php cachetool.phar opcache:status --web --web-path=/path/to/your/document/root --web-url=http://url-to-your-document.root