Go语言实战-nginx日志处理之MongoDB篇

Go语言实战-nginx日志处理之MongoDB篇,第1张

前面已经对nginx日志进行了分析处理,多个go程同时insert数据到MySQL,这对MySQL来说无疑是一次高并发

// 起5个go程,解析nginx的mq,并存入到mysql
go worker("worker1", mq, db)
go worker("worker2", mq, db)
go worker("worker3", mq, db)
go worker("worker4", mq, db)
go worker("worker5", mq, db)

针对这种高并发、海量的数据,存储到MongoDB是一个不错的选择

实践出真理,这里只改了前面代码的存储部分

// 将异常的nginx日志写入logs_info_exception表
db.Create(&infoException)

// 异常访问,存MySQL改成存MongoDB

// 将异常的nginx日志写入mongodb集合
collection.InsertOne(context.TODO(), infoException)
// 将正常的nginx日志写入logs_info表
db.Create(&info)

// 正常访问,存MySQL改成存MongoDB

// 将正常的nginx日志写入mongodb集合
collection.InsertOne(context.TODO(), info)

完整代码

package main

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type LogsInfo struct {
	Ip        string
	Time      int64
	Method    string
	Path      string
	Protocol  string
	Status    int
	Size      int
	Referer   string
	UserAgent string
}

type LogsInfoException struct {
	Ip    string
	Time  int64
	Other string
}

func connMongo() *mongo.Collection {
	// 设置客户端连接配置, mongodb://用户名:密码@host:port/数据库
	clientOptions := options.Client().ApplyURI("mongodb://root:root123@localhost:27017/admin")

	// 连接到MongoDB
	client, err := mongo.Connect(context.TODO(), clientOptions)
	if err != nil {
		log.Fatal(err)
	}

	// 检查连接
	err = client.Ping(context.TODO(), nil)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Connected to MongoDB!")

	// 指定获取要操作的数据集
	return client.Database("test").Collection("nginx_log")
}

func main() {

	start := time.Now()

	// 连接mongodb
	collection := connMongo()

	mq := make(chan string, 50)  // 存放消息,用来给多个go程消费
	signal := make(chan bool, 2) // 读取文件结束标志

	// 注塑主进程,防止主进程exit
	forever := make(chan bool)

	// 起5个go程,解析nginx的mq,并存入到mongodb
	go worker("worker1", mq, collection)
	go worker("worker2", mq, collection)
	go worker("worker3", mq, collection)
	go worker("worker4", mq, collection)
	go worker("worker5", mq, collection)

	// 起一个go程,用来读取nginx
	go task(mq, signal)

	// 主进程退出检测
	go func(signal chan bool, mq chan string, forever chan bool) {
		for {
			if len(signal) == 1 && len(mq) == 0 {
				forever <- true
			}
		}
	}(signal, mq, forever)

	// 优雅退出
	<-forever

	fmt.Println("cost:", time.Since(start).Seconds(), "s")

}

// task
// read log file
// 日志文件一般都比较大,很难一次性读取到内存中
// 这里是一行一行读取,并将每一行string放入mq通道中
func task(mq chan string, signal chan bool) error {

	// read log file
	filePath := "log/access.log"
	f, err := os.Open(filePath)
	defer f.Close()
	if err != nil {
		log.Panic(err)
		return err
	}
	buf := bufio.NewReader(f)

	count := 0
	for {
		if count > 1000 { // 加个条件方便测试数据量
			signal <- true
			return nil
		}
		line, _, err := buf.ReadLine()
		if err != nil {
			if err == io.EOF {
				signal <- true
				return nil
			}
			signal <- true
			return err
		}

		body := strings.TrimSpace(string(line))
		mq <- body
		log.Println("task: ", count)

		count += 1

		// 每次读取后,都检查一下mq通道的容量,如果容量达到一般,则sleep,将时间片交给其他go程
		// 达到容量的阈值,以及sleep的时间,要根据自己的电脑配置计算的出
		// 比如,处理10000个mq,就可以大概计算出处理1个mq所需要的的时间
		if len(mq) > 25 {
			time.Sleep(10 * time.Millisecond)
		}
	}
}

// consumer
// parse and write
func worker(workerName string, mq chan string, collection *mongo.Collection) {
	count := 0
	for d := range mq {
		parse(d, collection)
		count++
		log.Println(workerName, ": ", count)
	}
}

// parse and write
func parse(str string, collection *mongo.Collection) {
	// 每行nginx格式:ip 访问时间 访问方式 访问路径 协议 状态码 数据大小 referer user-agent
	re := `^([\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}) - - \[(.*)\] "([^\s]+) ([^\s]+) ([^\s]+?)" ([\d]{3}) ([\d]{1,9}) "([^"]*?)" "([^"]*?)"`
	reg := regexp.MustCompile(re)

	parseInfo := reg.FindStringSubmatch(str)

	// 匹配不到正常的格式,那么这条访问记录很可能有问题
	// 异常nginx处理
	if len(parseInfo) == 0 {
		re1 := `^([\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}) - - \[(.*)\] (.*)`
		reg1 := regexp.MustCompile(re1)
		parseInfo1 := reg1.FindStringSubmatch(str)
		if len(parseInfo1) == 0 {
			return
		}

		t1, _ := time.Parse("02/Jan/2006:15:04:05 -0700", parseInfo1[2])
		infoException := LogsInfoException{
			Ip:    parseInfo1[1],
			Time:  t1.Unix(),
			Other: parseInfo1[3],
		}

		// 将异常的nginx日志写入mongodb集合
		collection.InsertOne(context.TODO(), infoException)
		return
	}

	t, _ := time.Parse("02/Jan/2006:15:04:05 -0700", parseInfo[2])
	status, _ := strconv.Atoi(parseInfo[6])
	size, _ := strconv.Atoi(parseInfo[7])

	//
	info := LogsInfo{
		Ip:        parseInfo[1],
		Time:      t.Unix(),
		Method:    parseInfo[3],
		Path:      parseInfo[4],
		Protocol:  parseInfo[5],
		Status:    status,
		Size:      size,
		Referer:   parseInfo[8],
		UserAgent: parseInfo[9],
	}

	// 将正常的nginx日志写入mongodb集合
	collection.InsertOne(context.TODO(), info)
}

有兴趣的可以进行MongoDB VS MySQL,从读写速度、连接数等维度对比分析,自由发挥了

项目代码已放码云

欢迎分享,转载请注明来源:内存溢出

原文地址:http://outofmemory.cn/langs/995718.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-21
下一篇2022-05-21

随机推荐

  • 纽芬兰纪念大学与阿萨巴斯卡大学哪个好

      纽芬兰纪念大学学校简介立思辰留学360介绍,是纽芬兰省唯一的综合性公立大学,是加拿大的顶尖大学之一,是一所拥有6个分院的世界著名大学。现在学生近19000名,其中研究生3200多。由五个校区,大学

    2022-07-05
    300
  • 尼亚加拉学院位置要求

    立思辰留学360介绍,尼亚加拉学院建于1967年,是由加拿大安大略省政府和尼亚加拉地区政府共同兴建的公立学院,也是中国教育部重点推荐的加拿大著名公立学院(参见中国教育部监管网站)。作为加拿大安大略省办

    2022-07-05
    300
  • 2017年sunway双威大学生活费用多吗

    立思辰留学360介绍,双威大学成立于1986年,是马来西亚规模比较大的学府,早创期以双联课程开始,经过这些年的努力耕耘,如今已经发展成为盛名远播的双威大学学院,卓越学术水平广受好评及认可。每年有来自1

    2022-07-05
    300
  • 瑟里胡学校好不好

    据立思辰河南留学360邹思君老师介绍,瑟里胡学校(Solihull School)成立于1560年。最初由St Mary和St Katherine教会的捐助,在St Alphege教区教堂成立的。学校

    2022-07-05
    300
  • 碧差汶皇家大学

    碧差汶皇家大学好不好立思辰留学360介绍,碧差汶皇家大学距离Muang市3公里,位于沙拉武里-Lomsak的高速公路上。它的前身是1973年9月29日教育部授权成立的碧差汶师范学院。校园占地

    2022-07-05
    300
  • 泰国法政大学留学条件

    泰国国立法政大学立思辰留学360介绍,泰国国立法政大学始创于1933年,1934年时被批准成为法学与政治学方面的“开放大学”。1952年,正式成为泰国国立法政大学,并于1960年结束她的开放大学的历史

    2022-07-05
    300
  • 朱拉隆功大学本科专业

      朱拉隆功大学专业信息本科专业课程硕士专业课程博士专业课程留学360,隶属于上海叁陆零教育投资有限公司(中国A股上市公司立思辰:代码:300010旗下全资子公司),主要从事互联网留学办理、教育投资、

    2022-07-05
    300
  • 四色菊皇家大学介绍

    四色菊皇家大学介绍四色菊皇家大学坐落在历史悠久的文化名城四色菊市。学校占地总面积约250英亩,校园林木葱郁、风景秀丽。四色菊皇家大学始建于1997年,其前身是四色菊皇家学院,由当时四色菊市的国

  • 亚洲理工学院申请攻略

    亚洲理工学院简介立思辰留学360介绍,亚洲理工学院(AsianInstituteofTechnology,简称AIT),始创于1959年,当时是东盟为了促进亚洲高级工程方面的教育而成立的,1967年1

    2022-07-05
    300

发表评论

登录后才能评论

评论列表(0条)

    保存