OpenResty之单元测试

当项目功能开发完毕时,我们常常为了保证自己代码的功能正常,符合自己的预期结果而编写单元测试,并且以后当我们修改代码后,只需要跑一边单元测试便可以看我们有没有把代码给改残了。所以单元测试的重要性不言而喻。

使用不同的编程语言编写代码时,通常都有不同的单元测试框架。而当我们编写OpenResty项目时,比较好用的的测试框架还是比较少等,因为之前一直在看《OpenResty 最佳实践》一书,里面作者自己开发了一套测试框架lua-resty-test,使用后感觉还不错,便在项目中使用了一下。下面大概总结下使用心得。

Nginx 配置添加测试服务器

在配置文件中新增一个专门用于跑单元测试的服务器,并且将它的错误日志专门用另一个test_error.log文件存储。然后新建一个test文件夹用于放置单元测试代码,设置执行单元测试的主入口文件为main.lua,
这里别忘了设置下lua_package_path的值,把lua-resty-test的路径加上去。因为我吧项目的一些公共库都放置在了lualib下,所以我的lua_package_path设置如下

# conf/nginx.conf
lua_package_path '${prefix}project/?.lua;${prefix}lualib/?.lua;;';
# 新增的单元测试服务器配置
server {
    listen  8090;
    access_log off;
    # 此处修改单元测试服务器的错误日志为test_error.log,有别于开发项目的 error.log文件
    error_log logs/test_error.log error;
    # 主入口文件为 mian.lua
    location /test {
        content_by_lua_file 'test/main.lua';
    }
}

在主入口文件中加载各个单元测试代码

因为我这里是按照一个文件编写一个单元测试的,所以在主入口文件中进行加载每一个要被测试的代码,代码如下

# test/main.lua
local iresty_test    = require "resty.iresty_test"
-- 测试项目中的utils.lua文件
require("test.test_utils.test_utils")(iresty_test)
-- 测试项目中的transac.lua文件
-- require("test.test_controller.test_transac")(iresty_test)

utils 文件的单元测试代码大致如下

 # test/test_utils/test_utils.lua

 local utils = require("utils.utils")
 local cjson = require("cjson")

 local function test_utils( iresty_test )

     -- 设置此模块的单元测试名称
     local test_utils = iresty_test.new({unit_name="test_utils"})

     -- init方法可以在跑单元测试的时候执行一些初始化的操作
     --function test_utils:init(  )
     --    self:log("init complete")
     --end

     -- 测试utils模块的isDigit函数
     function test_utils:test_isDigit()
         -- case one
         local result = utils.isDigit()
         local expect = false
         assert(expect == result, "isDigit function should return false")

         -- case two 
         local result = utils.isDigit("")
         local expect = false
         assert(expect == result, "isDigit function should return false")

         -- case three 
         local result = utils.isDigit("12345")
         local expect = true
         assert(expect == result, "isDigit function should return true")

         -- case four 
         local result = utils.isDigit("123abc")
         local expect = false
         assert(expect == result, "isDigit function should return true")
     end

     -- 测试utils模块的trim函数
     function test_utils:test_trim()
         -- log方法用于记录单元测试的时候,一些日志数据
         -- self:log("ok")
     end

     -- 运行此文件的单元测试
     test_utils:run()
end

return test_utils

运行单元测试代码

建议在命令行中使用curl命令,这样的话可以比较明显的看出不同颜色的输出日志

curl http://10.100.157.198:8090/test

输出效果如下

0.000 [test_utils] unit test start
0.000   _[test_isDigit] PASS
0.000   _[test_trim] PASS
0.000 [test_utils] unit test complete

nginx如何配置兼容ThinkPHP各种url模式

我们知道ThinkPHP是有多种访问模式的,比如较常用的普通模式以及rewrite模式,也就是网址 /index.php?m=Zhonglian&c=Index&a=register 以及 网址 /DailiUser/alipay_notify_url,这两种模式用得比较多了。

为什么要做多种兼容呢,因为最近做了支付宝的回调,而支付宝是不认第一种模式的,只能使用 rewrite 模式,而我本地使用的是 nginx 服务器,所以需要在 nginx里面去做一下兼容配置了,配置的方法也很简单,在linux或者windows+nginx的环境下配置 nginx.conf 文件。

location / {    
     root /var/www;    
     index index.html index.htm index.php;    
     if (!-e $request_filename) {    
         rewrite ^/index.php(.*)$ /index.php?s=$1 last;    
         rewrite ^(.*)$ /index.php?s=$1 last;    
         break;    
     }    
 }    

好了,配置成功之后,Thinkphp的三种模式都可以兼容使用了,在本地的话就可以使用普通的模式,如果使用支付宝或者微信支付等回调的话就可以使用 rewrite 类的模式。

nginx限速之连接数限制技巧分享

前言

我们经常会遇到这种情况,服务器流量异常,负载过大等等。对于大流量恶意的攻击访问,会带来带宽的浪费,服务器压力,影响业务,往往考虑对同一个ip的连接数,并发数进行限制。nginx 内置模块限速怎么使用就不多说了,今天来说说连接数和单个连接数限速的事。话不多说了,来一起看看详细的介绍吧。

场景

A公司有100人,A公司只有一个公网IP,假设A公司可能有100个人同时在下载你的网站文件。

但是,你的连接数限制配置为:

limit_conn_zone $binary_remote_addr zone=perip:1m;
server {
 ---
 limit_conn perip 1;
 limit_rate 1024k;
 ---
}

允许单个连接数,单个连接数最大带宽为1M。
这样就会有99个人的请求状态为 503, 其他人如果想下载就必须人工等待(nginx不会通知用户说A用户下载完了,该你B用户下载了)。这样造成的用户体验极差。但是优点也很明显,带宽很快就会降下来。

可能有人就要问了,你限制成很低的连接数是想搞事情?NO,绝对不是。前面的100个人同时下载网站资源的情况有多大呢?没做过统计,但是可能性极小。并且前端页面和下载资源不共用一个域名,所以不会影响到前端页面的访问。
那都是谁在大量使用连接数呢?分两类:

  • 下载工具类(迅雷)。
  • 各种各样的采集程序。
  • 同时进行多个下载任务。

小明快乐的在看电视,瞥了左边频幕一眼,握草,带宽又满了,来吧,限速吧,

limit_conn_zone $binary_remote_addr zone=perip:1m;
server {
 ---
 limit_rate 1024k;
 ---
}

小明做了如上限速,OK,我告诉你们谁被限速了,当然是浏览器下载用户,360浏览器的下载器都不一定能限制,好的,来算算速度吧。
浏览器: 2014K
下载器: 1024 * 15(最大连接数) * VIP
采集器: 1024 * 连接数

所以我们得到如下结论:

带宽有限,同个IP同时下载的情况很小的,或者说是可以预知的业务,尽量将连接数限制的小一点。
反之,别限制了。就降低单个连接数带宽吧!要知道大家谁没事会用浏览器自带下载器下载呢?
注:本文只探讨nginx限速模块在不同业务下的限速

彩蛋:偶尔发现,将连接数限制为1迅雷不能高速下载了。

未分类

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对编程小技巧的支持。

Nginx下修改WordPress固定链接设置后无法访问

用WordPress肯定是要用固定链接,不仅目录清晰,而且利于SEO。当你用Apache做Web服务器的时候自然是没什么问题,只需要在设置-固定链接设置中选择一下就好了,不过当你用Nginx的时候,就有点小问题了,当你选固定链接的时候,你的网站会无法访问。

未分类

以下文章主要介绍了Nginx下修改WordPress固定链接导致无法访问的问题解决,同时作者也给出了官方关于修改固定链接的方法,需要的朋友可以参考下:

wordpress提供多种类型的链接形式

未分类

我选择了自定义。下面就出现了修改固定链接后,访问文章会出现404错误,以前我用apache做web服务器,所以只要apache下就三个关键,即

wordpress对目录下的.htaccess拥有读写权限

固定链接的目录结构需要 Apache服务器的mod_rewrite模块支持,所以在Apache配置文件httpd.conf中将 LoadModule rewrite_module modules/mod_rewrite.so设置为启用。

同样是Apache配置文件,其中对于站点目录下的AllowOverride None的参数设置为All。当然修改完配置后,一定要重启Apache服务。

由于是新配置的本地测试环境,2、3两项问题同时出现,逐项更正设置后,固定链接的工作正常。

现在我用的nginix,所以也要修改nginix的ngnix.conf配置文件,让其支持重定向。

假设我的wordpress博客是的 server{}段是直接放到放到了nginx.conf (有的人为了方便管理,都习惯在单独写个vhost/目录来存放每个网站的配置文件,这就要根据你自己的设置来添加了)

vi /your_nginx_path/conf/nginx.conf

按照nginix的正则表达式的规则,可参考:Nginx 的中文维基

  • ^:匹配输入字符的开始位置

  • $:匹配数日字符串的结束位置

  • +:匹配前面的子表达式一次或者多次

  • [0-9]:数字字符范围

  • $1:调用变量

在server{} 字段 中的 “root /websit/wwwroot/;”(这行就是指定网站所在目录的) 这一行的下面 ,添加下面的内容:

if (-f $request_filename/index.html){
rewrite (.*) $1/index.html break;
}
if (-f $request_filename/index.php){
rewrite (.*) $1/index.php;
}
if (!-f $request_filename){
rewrite (.*) /index.php;
}
rewrite /wp-admin$ $scheme://$host$uri/ permanent;//这行是为了防止打开后台、插件页等打不开的。

保存后,输入 /etc/init.d/nginx restart , 重启nginix。就ok了!

相当于告诉nginix访问这些后按照正则表达式转到其唯一正确的地址,以此打开文章。

貌似/%postname%/会以中文为链接,为了seo,可以考虑一个插件 WP Slug Translate,它会自动换中文标题为英文,不能联网就改为拼音。

貌似官方给出了新的pha100 pha-3,也简单的多。这里假设,我在nginx的conf文件夹下创建个wordpress.conf ,将下面的代码粘贴进去:

location / {
try_files $uri $uri/ /index.php?$args;
}
rewrite /wp-admin$ $scheme://$host$uri/ permanent;

我的博客nginx虚拟机配置文件在 conf/vhost/www.dabu.info.conf 。同样,在root 那行下面,添加一行:

include wordpress.conf;

接着重启nginx就可以正常访问了。

Nginx如何解决“The plain HTTP request was sent to HTTPS port”错误

Nginx HTTP服务器的一条报错“400 Bad Request: The plain HTTP request was sent to HTTPS port”,本文将讲解如何解决这个问题。从报错的字面意思上来看,是因为HTTP请求被发送到HTTPS端口,这种报错多出现在Nginx既处理HTTP请求又处理HTTPS请求的情况。

为了便于理解,我们假设这样一个场景。Nginx为web网站提供提供服务,而其中只有一个网站使用SSL协议。

以下是Nginx常用的SSL配置(出于安全原因,我们使用了示例域名),配置文件将让Nginx侦听80和443端口,并将所有的HTTP请求重定向到HTTPS。

server{
        listen 80;
        server_name example.com www.example.com;
        return 301 https://www.example.com$request_uri;
}
server {
        listen 443 ssl http2;
        server_name example.com www.example.com;

        root   /var/www/html/example.com/;
        index index.php index.html index.htm;

        #charset koi8-r;
        access_log /var/log/nginx/example.com/example.com_access_log;
        error_log   /var/log/nginx/example.com/example.com_error_log   error;

        # SSL/TLS configs
        ssl on;
        ssl_certificate /etc/ssl/certs/example_com_cert_chain.crt;
        ssl_certificate_key /etc/ssl/private/example_com.key;

        include /etc/nginx/ssl.d/ssl.conf;

        location / {
                try_files $uri $uri/ /index.php?$query_string;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
                root   /var/www/html/example.com/;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ .php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ .php$ {

                root   /var/www/html/example.com/;
                fastcgi_pass   127.0.0.1:9001;
                #fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
                fastcgi_index  index.php;
                fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                include         fastcgi_params;
                include /etc/nginx/fastcgi_params;

        }
        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /.ht {
        #    deny  all;
        #}
}

以上的配置看上去都很正常,但是用户想通过80端口来访问网站时,例如使用http://example.com,那么这个用户就会在浏览器收到错误400“The plain HTTP request was sent to HTTPS port”,示例图片如下:

未分类

出现这个错误,因为每一次客户试图通过HTTP访问你的网站,这个请求被重定向到HTTPS。于是Nginx预计使用SSL交互,但原来的请求(通过端口80接收)是普通的HTTP请求,于是会产生错误。

另一方面,如果一个客户使用https://example.com访问网站,他们就不会遇到上述错误。此外,如果你有其他的网站配置为不使用SSL,Nginx会尝试使用HTTPS,这种情况下也会造成上述错误。

解决办法也很简单,就是将上面配置文中的“ ssl on ; ” 注释掉或者修改成 “ ssl off ;”,这样,Nginx就可以同时处理HTTP请求和HTTPS请求了。

Nginx手动安装、增加ssl模块、升级更新、删除等操作

以下的操作都在Ubuntu系统下,其它系统请绕过

一般我们都需要先装pcre, zlib,前者为了重写rewrite,后者为了gzip压缩。

sudo apt-get install libpcre3 libpcre3-dev        //PCRE库
sudo apt-get install zlib1g-dev                        //zlib库
sudo apt-get install openssl libssl-dev            //OpenSSL库

1. 选定源码目录

选定目录 /usr/local/

cd /usr/local/

2. 安装nginx

Nginx 一般有两个版本,分别是稳定版和开发版,您可以根据您的目的来选择这两个版本的其中一个,下面是把 Nginx 安装到 /usr/local/nginx 目录下的详细步骤:
备注:nginx请到http://nginx.org/download 查找并下载。

cd /usr/local/
wget http://nginx.org/download/nginx-1.2.8.tar.gz
tar -zxvf nginx-1.2.8.tar.gz
cd nginx-1.2.8  
./configure --prefix=/usr/local/nginx 
make
make install

–with-pcre=/usr/src/pcre-8.21 指的是pcre-8.21 的源码路径。
–with-zlib=/usr/src/zlib-1.2.7 指的是zlib-1.2.7 的源码路径。

3. 启动

确保系统的 80 端口没被其他程序占用,

/usr/local/nginx/sbin/nginx

检查是否启动成功:

netstat -ano|grep 80 有结果输入说明启动成功
打开浏览器访问此机器的 IP,如果浏览器出现 Welcome to nginx! 则表示 Nginx 已经安装并运行成功。

4. 重启

/usr/local/nginx/sbin/nginx –s reload

5. 修改配置文件

cd /usr/local/nginx/conf
vi nginx.conf

6. 增加未开启的ssl,http2模块

切换到源码包cd /usr/local/nginx-1.2.8后查看nginx原有的模块

sudo /usr/local/nginx/sbin/nginx -V 

原有应该如下:

--prefix=/usr/local/nginx 

新的配置应该这么写:

--prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module 

那么应该运行下面的命令,配置完成后,执行:

./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module 

配置完成后,运行命令:

make 

不要make install,否则就覆盖安装了。

先停止nginx运行pkill -9 nginx,这里强制停止。

然后备份原有已经安装好的nginx配置

cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak 

将刚刚编译的覆盖原有的nginx

cp ./objs/nginx /usr/local/nginx/sbin/ 

启动nginx:

/usr/local/nginx/sbin/nginx 

查看是否安装成功新的ssl模块:

sudo /usr/local/nginx/sbin/nginx -V

7. 升级nginx

下载最新版nginx源码并解压编译

cd /usr/local/
wget http://nginx.org/download/nginx-1.13.6.tar.gz
tar zxvf nginx-1.13.6.tar.gz
cd nginx-1.13.6
#编译nginx,添加http_v2模块应用

开始编译nginx

./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module 

编译完成后,执行make,但不执行make install

make 

将旧版本的nginx二进制文件,重命名一个名字,在这期间,当前运行的nginx进程不会停止,不影响应用运行。

mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old 

然后将上一步通过make编译好的新版nginx二进制文件,拷贝到运行目录

cp ./objs/nginx /usr/local/nginx/sbin/nginx 

在源码目录根目录下,执行更新安装命令:

make upgrade 

注意:如果原来的相关配置文件中,写有和ssl有关的配置信息,需要先暂时注释掉,否则更新时会报错。

更新完成后,执行

nginx -V 

可以看到nginx已经更新到1.13.6版本。

NGINX下升级HTTPS踩到的坑

由于项目业务升级,全站升级https协议。

导致了资源跨域 https下无法访问http协议的资源,项目原本有很多图片存储在数据库url使用http协议,导致了项目的图片,样式丢失,部分图片上传组件也无法使用。

HTTPS 是 HTTP over Secure Socket Layer,以安全为目标的 HTTP 通道,所以在 HTTPS 承载的页面上不允许出现 http 请求,一旦出现就是提示或报错:

Mixed Content: The page at 'https://www.example.com' was loaded over HTTPS, but requested an insecure image ‘http://static.example.com/test.jpg’. This content should also be served over HTTPS.

首先,为了解决样式问题,我在前端页面,引入了一个meta

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />

等效于用PHP设置头部

header("Content-Security-Policy: upgrade-insecure-requests");

这样导致了一个问题,我的测试环境下并没有ssl证书,因此又冒出很多问题。

后面接触了下CSPCSP

我改变了下思路,在nginx上做处理。一个nginx的配置

server {
        listen       443;
        server_name  www.example.com;
        #charset koi8-r;

        error_log  /logs/nginx/error.log;
        root /var/www/www.example.com;
        index  index.php index.html index.htm;
        ssl on;
        ssl_certificate   cert/test/test.pem;
        ssl_certificate_key  cert/test/test.key;
        ssl_session_timeout 5m;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;

        add_header  X-Frame-Options  deny;
        add_header  X-Content-Type-Options  nosniff;
        add_header  X-XSS-Protection "1; mode=block";
        add_header Strict-Transport-Security max-age=86400;
        add_header Content-Security-Policy "upgrade-insecure-requests;default-src *;script-src 'self' https://static.example.com http://static.example.com 'unsafe-inline' 'unsafe-eval';style-src https://static.example.com http://static.example.com 'self' 'unsafe-inline';frame-src 'self';connect-src 'self';img-src https://static.example.com http://static.example.com data: blob: 'self'";

        location / {
                if (!-f $request_filename){
                        rewrite ^/(.*)$ /index.php?s=$1 last;
                        break;
                }
                limit_except GET POST DELETE PUT {
                        deny all;
                }
        }


        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
                        root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ .php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ .php$ {
                        fastcgi_pass   127.0.0.1:9000;
                        fastcgi_index  index.php;
                        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                        include        fastcgi_params;
        }

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        location ~ /.ht {
                        deny  all;
        }
}

几个header的意思,改天再写一篇文章详细讲解下。

Mysql开启慢查询记录耗时SQL语句

简述

  网站数据达到一定的数量级,就会有页面卡,出现50x等各种问题,mysql服务器CPU居高不下等症状。因为sql缓慢导致php缓慢,导致超时。这个时候应该先从mysql入手。就像看病一样,要先找病根,记录慢查询日志,就是观察期,观察到迹象我们就可以对症下药了。

配置参数说明

主要靠三个参数来配置,我们用通俗的话来解释。

1、开关(不多说,关闭就不记录了)

slow_query_log

2、log存储位置(记录下来,我得知道你在哪吧,一般将它存放到mysql数据目录,也就是和你创建的数据库在同级目录)

slow_query_log_file

3、超时时间 (我得让你知道多慢我忍不了)

long_query_time

设置方法

方法一:全局变量设置

将 slow_query_log 全局变量设置为“ON”状态

mysql> set global slow_query_log='ON';

设置慢查询日志存放的位置(默认在 mysql data 目录下)

mysql> set global slow_query_log_file='slow.log';

记录超时1秒的sql语句

mysql> set global long_query_time=1;

注意:无需重启即可生效,但重启会失效。set global 改的参数是暂时的,想重启不变请配合修改mysql配置文件。

方法二:配置文件设置

修改配置文件my.cnf(Windows 下是my.ini),在[mysqld]下的下方加入

slow_query_log = ON
slow_query_log_file = slow.log
long_query_time = 1

注意:修改配置文件之后需要重启mysql服务。

查看设置后的参数

mysql> show variables like 'slow_query%';
+---------------------+----------+
| Variable_name       | Value    |
+---------------------+----------+
| slow_query_log      | ON       |
| slow_query_log_file | slow.log |
+---------------------+----------+
2 rows in set

mysql> show variables like 'long_query_time';
+-----------------+----------+
| Variable_name   | Value    |
+-----------------+----------+
| long_query_time | 1.000000 |
+-----------------+----------+
1 row in set

测试生成log

mysql> select sleep(2);

从log文件中发下慢查询

# Query_time: 2.062500  Lock_time: 0.000000 Rows_sent: 1  Rows_examined: 0
use test;
SET timestamp=1515638101;
select sleep(2);

重新生成log文件

  
有时候log文件过大需要清空,直接删除log文件,本以为下次再有慢查询会自动生成文件并记录,其实并不会生成。当然重启mysql是可以生成的,但是生产环境重启mysql一定要慎重,不到万不得已不要重启mysql。在删除log文件之后,重新生成log文件需要运行 flush logs 命令。

mysql> flush logs;
Query OK, 0 rows affected

好了,mysql记录慢查询的步骤就这些了,通过记录慢的 sql 语句来开始你的优化之旅吧!

MySQL 清除表空间碎片的实例详解

碎片产生的原因

(1)表的存储会出现碎片化,每当删除了一行内容,该段空间就会变为空白、被留空,而在一段时间内的大量删除操作,会使这种留空的空间变得比存储列表内容所使用的空间更大;

(2)当执行插入操作时,MySQL会尝试使用空白空间,但如果某个空白空间一直没有被大小合适的数据占用,仍然无法将其彻底占用,就形成了碎片;

(3)当MySQL对数据进行扫描时,它扫描的对象实际是列表的容量需求上限,也就是数据被写入的区域中处于峰值位置的部分;

例如:

一个表有1万行,每行10字节,会占用10万字节存储空间,执行删除操作,只留一行,实际内容只剩下10字节,但MySQL在读取时,仍看做是10万字节的表进行处理,所以,碎片越多,就会越来越影响查询性能。

查看表碎片大小

(1)查看某个表的碎片大小

mysql> SHOW TABLE STATUS LIKE '表名';

结果中’Data_free’列的值就是碎片大小

未分类

(2)列出所有已经产生碎片的表

mysql> select table_schema db, table_name, data_free, engine   
from information_schema.tables 
where table_schema not in ('information_schema', 'mysql') and data_free > 0;

清除表碎片

(1)MyISAM表

mysql> optimize table 表名

(2)InnoDB表

mysql> alter table 表名 engine=InnoDB

Engine不同,OPTIMIZE 的操作也不一样的,MyISAM 因为索引和数据是分开的,所以 OPTIMIZE 可以整理数据文件,并重排索引.

OPTIMIZE 操作会暂时锁住表,而且数据量越大,耗费的时间也越长,它毕竟不是简单查询操作.所以把 Optimize 命令放在程序中是不妥当的,不管设置的命中率多低,当访问量增大的时候,整体命中率也会上升,这样肯定会对程序的运行效率造成很大影响.比较好的方式就是做个shell,定期检查mysql中 information_schema.TABLES字段,查看 DATA_FREE 字段,大于0话,就表示有碎片

建议

清除碎片操作会暂时锁表,数据量越大,耗费的时间越长,可以做个脚本,定期在访问低谷时间执行,例如每周三凌晨,检查DATA_FREE字段,大于自己认为的警戒值的话,就清理一次。

服务器上的WEB项目反复出现MySQL数据库连接失败解决办法

  • 一个原因是没有关闭MySQL的定时任务计划,每天凌晨MySQL会默认运行一个自动更新的定时任务计划,如果没有关闭,就会自动断开连接。 解决办法: 1、这是一个基本的权限问题。去MySQL安装目录下,右键单击MySQL文件夹,进入安全选项卡下,单击“编辑用户组”,在“组和用户”选择你的电脑的用户,选择允许的情况下所有的项,应用并关闭。 2、这是一个Windows的任务计划服务,删除即可,开始右键/计算机管理/任务计划程序/任务计划程序库/MySQL/Installer/ManifestUpdate,右键单击并选择“禁用”。

  • 另一个原因是MySQL数据库的数据库连接有生存期限制,如果在规定时间内没有操作数据库连接对象,连接就会被关闭。也就是常说的MySQL的8小时问题

  • MySQL服务器默认连接的“wait_timeout”是8小时,也就是说一个Connection空闲超过8个小时,MySQL将自动断开该 Connection。但是数据库连接池并不知道连接已经断开了,如果程序正巧使用到这个已经断开的连接,程序就会报错误。

先来了解一下数据库连接池:

  • 用JAVA代码操作数据库需要数据库连接对象,一个用户至少要用到一个连接。现在假设有成千上百万个用户,就要创建十分巨大数量的连接对象,这会使数据库承受极大的压力,为了解决这种现象,一种技术出现了,这就是数据库连接池。

  • 所谓数据库连接池,可以看作在用户和数据库之间创建一个“池”,这个池中有若干个连接对象,当用户想要连接数据库,就要先从连接池中获取连接对象,然后操作数据库。一旦连接池中的连接对象被拿光了,下一个想要操作数据库的用户必须等待,等待其他用户释放连接对象,把它放回连接池中,这时候等待的用户才能获取连接对象,从而操作数据库。

  • 以下是两个连接池的简单实现~ 代码来自:
    https://www.cnblogs.com/vmax-tam/p/4158802.html 代码来自:https://www.cnblogs.com/xiaotiaosi/p/6398371.html

代码我就不搬过来了,重点讲讲如何解决问题

方法一:修改数据库的等待时间

1、首先重启MySQL服务,开始→右键→计算机管理→服务,找到MySQL的服务,重新启动

2、设置MySQL最大等待时间,运行MySQL 5.7 Command Line Client,输入密码后,拷贝运行以下代码段:

show variables LIKE '%timeout%';
show global variables LIKE '%timeout%';
set global wait_timeout=2147483;
set wait_timeout=2147483;
set global interactive_timeout=31536000;
set interactive_timeout=31536000;

3、重启Tomcat

方法二:让自己编写的数据库连接池代码生成数据库连接对象时,增加一个自动刷新的功能,间隔时间自动生成一个新的数据库连接对象。也就是定期使用连接池内的连接,使得它们不会因为闲置超时而被 MySQL 断开。

方法三:连接数据库的时候加上autoReconnect=true这个参数:

jdbc:mysql://localhost:3306/accounant?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true

方法四:减少连接池内连接的生存周期,使之小于上述项中所设置的“wait_timeout”的值。

方法五:将“testOnBorrow”设置为false,而将“testWhileIdle”设置为true,再设置好“testBetweenEvictionRunsMillis”值(小于8小时)。那些被MySQL关闭的连接就不会被清除出去,避免“8小时问题”。 例:http://www.totcms.com/html/201602-29/20160229114145.htm

Apache官方文档给出的配置示例可参见:http://tomcat.apache.org/tomcat-9.0-doc/