当前位置: 首页 > 编程日记 > 正文

mysql如何实现实时存储_OpenResty + Mysql 实现日志实时存储

应用场景和日志文件解析

本配置主要解决 Nginx 向 MySQL 中实时插入日志的问题,采用 OpenResty + Mysql 实现。

1. 刚开始的时候看了 Nginx 和 MySQL 的连接模块。比如说 nginx-mysql-module,可以连接 MySQL。但是插入日志时遇到问题,我们知道 nginx 的执行过程先是 location 解析并重写阶段,然后是访问权限控制阶段,接着是内容生成阶段,最后是日志记录阶段。MySQL 访问阶段属于内容生成阶段,所以代理运行的时间和状态,MySQL 都无法获取的到。因此,这种通过 nginx 直连 MySQL 的方式无法达到我们的要求。

2. 通过 lua 脚本在日志生成阶段获取信息,然后将数据插入 MySQL。nginx 有一个限制,无法在 log 阶段访问 socket 即无法访问 MySQL,所以无法在 log 阶段直接将数据存入 MySQL。但是可以通过运行包含 MySQL 操作的 shell 脚本来解决这个问题。但是这个方法有两个弊端:

获取到 Nginx 代理的结果后,每次都要连接 MySQL 并向其插入数据。当并发量大时,MySQL 端会出现问题。

不向 MySQL 插入数据,整个时间的消耗大约在 0.02-0.04s 之间。而向 MySQL 插入数据后,整个时间消耗大约在 0.4-0.9 之间,消耗的时间是原来的 10 倍。

3. 通过 lua + ngx.time.at + lua_MySQL + lua.share.dict 解决问题。整个过程如下所示:

在 nginx 启动阶段,ngx.time.at 启动一个延时任务。在任务中,每隔一段时间取出 nginx 内存共享区的 log 数据,将数据合并,存入 MySQL,同时再一个相同的延时任务,递归调用。这样就与 crontab 命令相似。当定时器到期,定时器中的 Lua 代码是在一个“轻线程”中运行的,它与创造它的原始请求是完全分离的,因此不存在大量线程同时运行的情况。

在日志生成阶段,将数据封装并存入 nginx 的内存共享区。

MySQL 访问权限的问题

不但访问 MySQL 的 MySQL 用户需要有操作对应数据库的权限,还需要调用 MySQL 命令的用户具有访问 MySQL 的权限。授权命令如下:

GRANT ALL PRIVILEGES ON *.* to root@xxx IDENTIFIED BY 'password';

MySQL 编码类型

总的来说,MySQL 的数据库对应三种编码。MySQL 客户端显示数据的编码,连接 MySQL 用的编码(即数据存入 MySQL 时,数据的编码),MySQL 存储用的编码(字段,表,数据库三种格式可能不同)。不管 MySQL 存储用的编码是什么,只要 MySQL 客户端显示数据的编码和连接 MySQL 用的编码相同,数据就能通过 MySQL 客户端正确显示。

配置文件

user root;

worker_processes 2;

events {

worker_connections 1024;

}

http{

lua_package_path "/home/oicq/guomm/nginx_lua/lua-resty-mysql-master/lib/?.lua;;"; --重要

lua_shared_dict logs 10m;

init_worker_by_lua_block {

local delay = 10

function put_log_into_mysql(premature)

local mysql = require "resty.mysql"

local db, err = mysql:new()

if not db then

ngx.log(ngx.ERR,"failed to instantiate mysql: ", err)

return

end

db:set_timeout(1000)

local ok, err, errcode, sqlstate = db:connect{

host = "xxx",

port = 3306,

database = "database_name",

user = "username",

password = "password",

charset = "utf8",

}

if not ok then

ngx.log(ngx.ERR,"failed to connect: ", err, ": ", errcode, " ", sqlstate)

return

end

-- get data from shared dict and put them into mysql

local key = "logs"

local vals = ""

local temp_val = ngx.shared.logs:lpop(key)

while (temp_val ~= nil)

do

vals = vals .. ",".. temp_val

temp_val = ngx.shared.logs:lpop(key)

end

if vals ~= "" then

vals = string.sub(vals, 2,-1)

local command = ("insert into es_visit_record(access_ip,server_ip,access_time,run_time,es_response_time,request_body_byte,run_state,url,post_data) values "..vals)

ngx.log(ngx.ERR,"command is ",command)

local res, err, errcode, sqlstate = db:query(command)

if not res then

ngx.log(ngx.ERR,"insert error: ", err, ": ", errcode, ": ", sqlstate, ".")

return

end

end

local ok, err = db:close()

if not ok then

ngx.log(ngx.ERR,"failed to close: ", err)

return

end

-- decycle call timer to run put_log_into_mysql method, just like crontab

local ok, err = ngx.timer.at(delay, put_log_into_mysql);

if not ok then

ngx.log(ngx.ERR, "failed to create timer: ", err)

return

end

end

local ok, err = ngx.timer.at(delay, put_log_into_mysql)

if not ok then

ngx.log(ngx.ERR, "failed to create timer: ", err)

return

end

}

upstream elasticsearch_servers {

server xxx max_fails=3 fail_timeout=30s;

server xxx max_fails=3 fail_timeout=30s;

server xx max_fails=3 fail_timeout=30s;

}

log_format porxy '$remote_addr,$upstream_addr,[$time_local],$request,$request_body,$status,$body_bytes_sent,$request_time,$upstream_response_time';

server {

listen 9202;

location / {

proxy_pass http://elasticsearch_servers;

log_by_lua_block{

local currentTime = os.date("%Y-%m-%d %H:%M:%S", os.time())

currentTime = "\"" .. currentTime .. "\""

local req_body = '-'

if ngx.var.request_body then

req_body = ngx.var.request_body

req_body = string.gsub(req_body,"\n","")

--req_body = string.gsub(req_body,"\t","")

end

req_body = "\"" .. req_body .. "\""

local req_status = 0

if ngx.var.status then

req_status = ngx.var.status

end

local req_time = 0

if ngx.var.request_time then

req_time = ngx.var.request_time

end

local req_req = "\"" .. ngx.var.request .. "\""

local remote_addr = "\"" .. ngx.var.http_x_forwarded_for .. "\""

local server_addr = "\"" .. ngx.var.upstream_addr .. "\""

local myparams = ("("..remote_addr..",".. server_addr..","..currentTime..","..ngx.var.request_time .. ",".. ngx.var.upstream_response_time..","..ngx.var.body_bytes_sent..","..ngx.var.status..","..req_req..","..req_body..")")

local key = "logs"

local len,err = ngx.shared.logs:rpush(key, myparams)

if err then

ngx.log(ngx.ERR,"failed to put log vals into shared dict")

return

end

}

}

access_log logs/es_access.log porxy;

}

}

相关文章:

简易RS232 建模二 (接收)

//clK系统时钟为50MHZ 先发低位后发高位 先接收地位后接收高位module uart_tx (input clk,rst_n, UART_CTS, output reg UART_RTS, input UART_RXD, output reg UART_TXD, output [7:0] led);reg [3:0]state;reg [30:0] count;reg [7:0] data;assign led rx_data; reg [7:0] …

《UNIX高级环境编程》 -- apue.h

在看《UNIX高级环境编程》这本书的时候,会遇到一个问题就是这个”apue.h”,这个是作者为了编写代码方便封装了一个库,我们可以使用下面的方式解决这个问题,让我们的代码可以像作者一样去使用,这样的话,我们就可以好好研…

mysql 多少个数据库_mysql数据库的几个基本概念

1、表数据库表是一系列二维数组的集合,用来存储数据和操作数据的逻辑结构。行是记录,列是字段,每一列表示记录的一个属性,都有相应的描述信息。2、数据类型:数据类型决定了数据在计算机中的存储格式,代表不…

教孩子正确对待分数

期末考试各科成绩渐渐公布了,小丽迫不及待地跑到办公室向老师打听分数。看到自己那一科成绩好时欣喜若狂,看到差的则懊悔不已。如果你的孩子也象小丽一样视考分为命根,该如何教孩子正确对待分数?让她从考分的困惑中解放出来?●考前给孩子制…

canvas初尝试

最近学习了canvas,就拿它做了这么个小东西,感觉已经爱上canvas了。上代码 /* * auhor : 开发部-前端组-李鑫超 * property { tableData : {Array} 表格数据 add v-1.0.0 } * property { columData : {Array} 表头数据 add v-1.0.0 } * property { me…

模板1.0 -- 模板基本原理

为什么需要模板 我们经常有这样的一种使用的情形,就是我们可能需要设计一个函数,然后函数的参数可能是整形的,也可能是浮点型的,还有可能是其他的类型的,这个时候如果对于每一个类型都写一个函数,未免有点…

[置顶] 我的GB28181标准开发里程碑——基于eXosip的IPC端与SPVMN注册成功

昨天编译搭建好eXosip的开发环境后,今天完成了SIP注册功能,里程碑一战啊!加油加油,成功就在眼前! 今天基于eXosip做了一个IPC客户端,成功与公安部的SPVMN视频监控联网调测软件自测工具进行注册交互&#xf…

mysql如何避免特殊字符查询_如何避免MySQL中的特殊字符?

慕的地10843我已经用Java开发了自己的MySQL转义方法(如果对任何人都有用的话)。请参阅下面的类代码。警告:如果启用了任何_反斜杠_转义SQL模式,则出错。private static final HashMap sqlTokens;private static Pattern sqlTokenPattern;static{ …

visio 2010 修改 默认字体 字号大小 方法

哈哈,我这是标题党,先给大家泼个冷水。Visio2010 并不支持对一次性地修改绘图中所有图形的字体大小!但可以有一个比较笨的方法解决。1.新建一个模具2.将常用的图形放到这个模具中3.对每个图形进行编辑4.对这个形状的字体,字号进行…

[BZOJ3329] Xorequ

题解: 网上的方法基本是建立在发现临位不能相等的基础上的 这个很好证。。 但是不利用这个特征也是可以的 x^2x3x 我们考虑二进制的前i位,我们会发现3x最多涉及到了前i2位 于是我们可以记录一下前i位的3x的i1,i2位的状态,以及第i位填了什么 因…

Asp.net中时间格式化的几种方法

1. 数据控件绑定时格式化日期方法:<asp:BoundColumn DataField"AddTime" HeaderText"添加时间" DataFormatString"{0:yyyy-MM-dd HH:mm}></asp:BoundColumn><asp:BoundField DataField"AddTime" HeaderText"添加时间&q…

centos设置网络自动启动

问题描述 centos7虚拟机如何设置开机自启动网络设置 解决方法 切换到root用户进入到网络设置的目录下面cd /etc/sysconfig/network-scripts/当前目录下面有一个类似于ifcfg-ens33&#xff0c;使用vim打开文件进行编辑&#xff0c;将ONBOOTno修改成为yes就可以了

mysql删除原则_MySQL数据库的增删选查

数据库是专门存储数据对象的容器&#xff0c;这里的数据对象包括表、视图、触发器、存储过程等&#xff0c;其中表是最基本的数据对象。创建数据库在 MySQL 数据库中存储数据对象之前&#xff0c;先要创建好数据库。语法&#xff1a;create database [if not exists] [[default…

ubuntu网卡配置

1、dhcp自动获取 sudo vi /etc/network/interfaces auto eth0 iface eth0 inet dhcp 设置生效: sudo /etc/init.d/networking restart 或 sudo dhclient eth0 2、静态IP地址 sudo vi /etc/network/interfaces auto eth0 iface eth0 inet static address 192.168.3.90 netmask 2…

自动化运维工具----ansible

自动化运维工具----ansible ansible是新出现的运维工具是基于Python研发的糅合了众多老牌运维工具的优点实现了批量操作系统配置、批量程序的部署、批量运行命令等功能。 主要模块以及功能&#xff1a; 1 command 2 user 3 group 4 cron 5 copy 6 file 7 ping 8 yum 9 service …

【内核】嵌入式linux内核的五个子系统

Perface Linux内核主要由进程调度&#xff08;SCHED&#xff09;、内存管理&#xff08;MM&#xff09;、虚拟文件系统&#xff08;VFS&#xff09;、网络接口&#xff08;NET&#xff09;和进程间通信&#xff08;IPC&#xff09;5个子系统组成&#xff0c;如图1所示。 图1 Li…

git用户文档1 — git基础

1. git基础 1.1 分布式 我们把远端仓库(云端的仓库)称为repo&#xff0c;repo必须有一个master分支&#xff0c;就是主分支。 repo除了有一个master分支&#xff0c;还有很多其他的分支&#xff0c;若干个分支之间存储的数据一版都是不一样的本地可以git clone下来repo的mast…

MySQL5.7的date类型_Mysql5.7 虚拟列数据类型为DATE时,如何存入数据?

表结构&#xff1a;v_date为虚拟列CREATE TABLE test ( json TEXT NULL, date DATETIME NULL DEFAULT NULL, v_date DATE AS (json_extract(json,$.date)) VIRTUAL)COMMENT测试表\r\nCOLLATEutf8mb4_general_ciENGINEInnoDB;插入&#xff1a;INSERT INTO test (json) …

找出字符串中所有数字

刚才网友在SKYPE问Insus.NET一个问题&#xff0c;在MS SQL中&#xff0c;怎样找出一个字符串所有数字。 Insus.NET使用较简单与平常的方法&#xff0c;就是使用循环的方法&#xff0c;循环字符串中每一个字符&#xff0c;并插入至一个表变量中。然后再SELECT这个表变量&#xf…

Safair 浏览器cllick事件不生效或者需要双击才生效

针对Safair 浏览器cllick事件不生效或者需要双击才生效的解决方案。 方法一&#xff1a;给元素加上cursor: pointer样式。&#xff08;不生效&#xff09; 方法二&#xff1a;ios事件机制不一样&#xff0c;将click事件改为mousedown或其他事件即可解决。&#xff08;需要双击&…

springboot mysql行锁_SpringBoot基于数据库实现简单的分布式锁

本文介绍SpringBoot基于数据库实现简单的分布式锁。1.简介分布式锁的方式有很多种&#xff0c;通常方案有&#xff1a;基于mysql数据库基于redis基于ZooKeeper网上的实现方式有很多&#xff0c;本文主要介绍的是如果使用mysql实现简单的分布式锁&#xff0c;加锁流程如下图&…

简单shell

执行脚本结果重定向 sh hah.sh hello 1>>/home/qiso/job.log 2>&1 上面这句话的意思是 首先通过sh执行脚本hah.sh&#xff0c;其中执行这个脚本的时候&#xff0c;需要传入参数&#xff0c;参数是hello&#xff0c; 1表示的是标准输出&#xff0c;以上脚本执行…

个人随笔、收藏——(包括技术、设计思想等)

1、开源自动化工具 Sahi、Selenium、AutoIt Sahi&#xff0c;是一个用于Web应用程序的自动测试工具。Sahi运行为一个代理服务器&#xff0c;必须把浏览器的代理设置为Sahi服务器。 然后Sahi注入javascript来访问Web页面中的元素。Sahi支持Http与Https并且独立于Web站点或Web应用…

安装QCreator2.5+Qt4.8.2+MinGW_gcc_4.4

QCreator最近升级了。正好想试试新功能&#xff0c;所以把原来安装的QCreator2.3.1Qt4.7.1卸载了。安装新的版本。具体步骤如下&#xff1a; 1# 下载QCreator2.5version。 2# 下载Qt4.8.2version。 3# 根据Qt官网给的链接&#xff0c;下载MinGW-gcc440_1&#xff08;因为从QCre…

第一次结对作业

211606368林书浩 211606352陈彬 一、预估与实际 PSP2.1Personal Software Process Stages预估耗时&#xff08;分钟&#xff09;实际耗时&#xff08;分钟&#xff09;Planning计划• Estimate• 估计这个任务需要多少时间3540Development开发• Analysis• 需求分析 (包括学习…

mysql如何根据业务分表设计_mysql分表分库的应用场景和设计方式

很多朋友在论坛和留言区域问mysql在什么情况下才需要进行分库分表&#xff0c;以及采用何种设计方式才是最优的选择&#xff0c;根据这些问题&#xff0c;小编为大家整理了关于MySQL分库分表的应用场景和最优的设计方式举例。一. 分表场景&#xff1a;对于大型的互联网应用来说…

简单protobuf

protobuf的数据类型&#xff0c;有最简单的那种数据类型&#xff0c;就是一个文件中&#xff0c;定义了一个message 可以在一个文件中定义两个message&#xff0c;两个message之间是没有关联的可以在一个文件中&#xff0c;定义两个message&#xff0c;其中一个是简单的&#x…

迭代器、生成器

迭代器 lst range(10) #生成一个枚举列表 从0-9 itr iter(lst) #生成一个迭代器 itr.next() #访问迭代器方法 遍历迭代器 try:while True:val itr.next()print val except StopIteration:pass 注意&#xff1a; 1、如果对list dict tuple 用for遍历&#xff0c;则for内部自动…

Linq 无法删除尚未附加的实体的问题

Linq删除个集合数据, 刚开始用的注释掉的那行, 会提示"无法删除尚未附加的实体"错误, 使用Attach方法依然不行. 想想以前用过DeleteAllOnSubmit没啥问题哈, 估计是_db对象的引用问题, 换了种写法就OK了. //删掉所有工作组部门关联 //wgdrLst Wor…

从云端到边缘 AI推动FPGA应用拓展

近日&#xff0c;全球最大的FPGA厂商赛灵思宣布收购深鉴科技的消息&#xff0c;引发人工智能芯片行业热议&#xff0c;这也是首起中国AI芯片公司被收购的案例。值得注意的是&#xff0c;收购深鉴科技的赛灵思在2018年下半年重点发展方面是汽车自动驾驶。 FPGA市场的竞争正在发生…