Golang日志管理:使用log/slog实现高级功能和性能优化

news2024/10/5 6:49:27

Golang日志管理:使用log/slog实现高级功能和性能优化

    • 简介
    • 基础使用
      • 初始化和配置
      • 日志级别
    • 高级技巧
      • 自定义日志格式器
      • 条件日志处理
    • 实战案例
      • 场景一:API请求日志记录
      • 场景二:错误跟踪和用户通知
    • 性能优化
      • 优化日志记录的性能
        • 异步日志处理
        • 选择合适的日志级别
      • 使用高性能的日志框架
    • 错误处理和调试
      • 利用 `log/slog` 进行有效的错误处理
        • 记录错误信息
        • 使用日志级别区分错误严重性
      • 日志和调试技巧
        • 添加足够的上下文信息
        • 利用日志分析工具
    • 与其他库的集成
      • 集成 `log/slog` 与数据库操作库 `GORM`
        • 设置 `GORM` 的日志接口
      • 集成 `log/slog` 与网络框架 `Gin`

在这里插入图片描述

简介

在现代软件开发中,日志记录是一个不可或缺的部分,它帮助开发者追踪应用行为、调试问题并保持系统的健康。Golang,作为一种高效的编程语言,提供了多种日志记录工具,而 log/slog 库则是其中功能强大且灵活的选择之一。

log/slog 是一个标准的日志库,旨在提供一个简单、模块化且高效的日志解决方案。它支持不同级别的日志记录,如信息、警告和错误等,使得开发者可以根据不同的信息重要性进行适当的记录。此外,slog 的设计允许通过插件扩展其功能,如添加日志处理器、格式化器或是输出目标,从而满足更加复杂的日志管理需求。

使用 log/slog,开发者可以轻松实现日志的定制化处理,从而使得日志系统既能满足性能的需求,也兼顾到操作的便捷性。本文将通过几个章节,详细介绍如何有效地使用 log/slog 来进行日志记录和管理,包括基础的日志设置、高级技巧的应用、以及在实际开发中如何利用这些技巧来解决常见的问题。

接下来的部分,我们将从如何开始使用 log/slog 来进行基本的日志记录讲起,逐步深入到更为复杂的日志处理技巧和性能优化方法。

基础使用

初始化和配置

在 Golang 中使用 log/slog 进行日志记录前,首先需要进行适当的初始化和配置。以下是一个基本的示例,展示了如何快速开始使用 slog 进行日志记录:

package main

import (
    "log"
    "os"
)

func main() {
    // 创建一个日志文件
    file, err := os.OpenFile("app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    // 设置日志输出到文件
    log.SetOutput(file)

    // 设置日志前缀
    log.SetPrefix("INFO: ")
    // 设置日志的格式
    log.SetFlags(log.Ldate | log.Ltime | log.Llongfile)

    log.Println("This is a test log entry")
}

在这个示例中,我们首先创建了一个日志文件 app.log,然后通过 SetOutput 方法将日志输出设置为该文件。同时,我们通过 SetPrefixSetFlags 方法来设置日志条目的前缀和格式,这样可以更清晰地了解日志的来源和上下文。

日志级别

log/slog 默认不区分日志级别,但你可以通过简单的封装来实现这一功能,以便在不同的场景中使用不同级别的日志记录:

package main

import (
    "log"
    "os"
)

const (
    LevelError = iota
    LevelWarning
    LevelInfo
)

func main() {
    file, err := os.OpenFile("app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    logger := log.New(file, "PREFIX: ", log.Ldate|log.Ltime|log.Llongfile)

    // 使用不同的日志级别记录信息
    logError(logger, "This is an error message")
    logWarning(logger, "This is a warning message")
    logInfo(logger, "This is an info message")
}

func logError(logger *log.Logger, msg string) {
    logger.SetPrefix("ERROR: ")
    logger.Println(msg)
}

func logWarning(logger *log.Logger, msg string) {
    logger.SetPrefix("WARNING: ")
    logger.Println(msg)
}

func logInfo(logger *log.Logger, msg string) {
    logger.SetPrefix("INFO: ")
    logger.Println(msg)
}

在上面的代码中,我们定义了三个不同的函数 logErrorlogWarninglogInfo 来分别记录错误、警告和信息级别的日志。通过设置不同的前缀,可以在日志文件中清楚地看到每条日志的重要性级别。

高级技巧

自定义日志格式器

在许多复杂的应用场景中,开发者可能需要对日志的格式进行自定义,以适应特定的监控系统或日志分析工具的需求。log/slog 通过提供灵活的配置选项,允许开发者轻松定义自己的日志格式。下面是一个如何自定义日志格式器的示例:

package main

import (
    "fmt"
    "log"
    "os"
    "time"
)

type customLogger struct {
    logger *log.Logger
}

func newCustomLogger(out *os.File) *customLogger {
    return &customLogger{
        logger: log.New(out, "", 0),
    }
}

func (c *customLogger) Printf(format string, v ...interface{}) {
    c.logger.SetPrefix(fmt.Sprintf("CUSTOM LOG [%s]: ", time.Now().Format(time.RFC3339)))
    c.logger.Printf(format, v...)
}

func main() {
    file, err := os.OpenFile("custom_app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    cLogger := newCustomLogger(file)
    cLogger.Printf("This is a custom log message with dynamic timestamp.")
}

在这个例子中,我们创建了一个 customLogger 类型,它包含一个内嵌的 log.Logger。我们重写了 Printf 方法,使其在每次记录日志时都会添加一个动态时间戳。这种方式使日志输出更加灵活和信息丰富。

条件日志处理

对于大型应用或在特定环境(如生产环境)中运行的应用,可能不需要记录所有日志。在这种情况下,条件日志处理变得尤为重要。以下是如何实现基于条件的日志记录的示例:

package main

import (
    "log"
    "os"
    "runtime"
)

func main() {
    file, err := os.OpenFile("conditional_app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    logger := log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)

    if runtime.GOOS == "linux" {
        logger.Println("This log is only written on Linux systems.")
    } else {
        logger.Println("This log is not written on Linux systems.")
    }
}

这段代码通过检查操作系统类型来决定是否记录特定的日志消息。这种方法在需要根据运行环境调整日志策略时非常有用。

实战案例

场景一:API请求日志记录

在开发Web服务时,记录每个API请求的详细信息对于后期分析和问题定位非常有用。使用 log/slog,我们可以轻松实现这一功能。以下是一个简单的示例,展示如何在一个基于HTTP的服务中记录每个请求的详细日志:

package main

import (
    "log"
    "net/http"
    "os"
)

func main() {
    file, err := os.OpenFile("api_requests.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    logger := log.New(file, "REQUEST: ", log.Ldate|log.Ltime|log.LUTC)

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        logger.Printf("Received request: %s %s from %s", r.Method, r.URL.Path, r.RemoteAddr)
        w.Write([]byte("Hello, world!"))
    })

    log.Println("Starting server on :8080")
    err = http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("Error starting server: ", err)
    }
}

在这个例子中,我们为HTTP服务器的每个请求设置了一个日志记录点。这样,每当接收到一个请求时,都会在日志文件中记录请求的方法、路径和来源地址。

场景二:错误跟踪和用户通知

在复杂的应用中,当错误发生时,及时记录错误信息并通知相关人员是非常重要的。以下是如何使用 log/slog 来实现错误日志记录和邮件通知的示例:

package main

import (
    "log"
    "os"
    "net/smtp"
)

// 配置SMTP服务器信息
const (
    SMTPServer   = "smtp.example.com"
    SMTPPort     = "587"
    SMTPUser     = "your-email@example.com"
    SMTPPassword = "your-password"
)

func notifyByEmail(subject, message string) {
    auth := smtp.PlainAuth("", SMTPUser, SMTPPassword, SMTPServer)
    to := []string{"admin@example.com"}
    msg := []byte("To: admin@example.com\r\n" +
        "Subject: " + subject + "\r\n" +
        "\r\n" +
        message + "\r\n")
    err := smtp.SendMail(SMTPServer+":"+SMTPPort, auth, SMTPUser, to, msg)
    if err != nil {
        log.Println("Error sending email:", err)
    }
}

func main() {
    file, err := os.OpenFile("errors.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    logger := log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)

    // 示例错误情况
    testError := func() {
        defer func() {
            if r := recover(); r != nil {
                errMsg := "Recovered in testError: " + r.(string)
                logger.Println(errMsg)
                notifyByEmail("Error Notification", errMsg)
            }
        }()
        panic("something went wrong")
    }

    testError()
}

这段代码演示了如何在发生未捕获异常时记录详细的错误日志,并通过电子邮件发送通知。通过这种方式,开发者和运维团队可以迅速响应异常情况。

性能优化

优化日志记录的性能

在高并发的应用中,日志记录本身可能成为性能瓶颈。优化日志记录的性能是确保应用整体效率的关键一环。以下是几种提升 log/slog 日志处理性能的方法:

异步日志处理

为了减少日志记录对主应用性能的影响,可以实现异步日志处理。这意味着日志消息将被发送到一个独立的处理队列中,并由另一个线程或进程异步写入到存储系统。这样可以显著减少写日志操作对主业务逻辑的延迟影响。示例如下:

package main

import (
    "log"
    "os"
)

// 日志消息队列
var logQueue chan string

func init() {
    logQueue = make(chan string, 1000) // 创建一个有缓冲的通道
    go func() {
        file, err := os.OpenFile("async_app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
        if err != nil {
            log.Fatal(err)
        }
        defer file.Close()

        logger := log.New(file, "ASYNC: ", log.Ldate|log.Ltime|log.Lshortfile)

        for msg := range logQueue {
            logger.Println(msg)
        }
    }()
}

func logMessage(message string) {
    logQueue <- message // 将消息发送到队列
}

func main() {
    for i := 0; i < 100; i++ {
        logMessage("Log entry number: " + string(i))
    }
}

在这个例子中,我们创建了一个日志消息队列,并通过一个独立的goroutine来处理这些消息。这样,主程序在发送日志消息时只需将消息放入队列,而不需等待日志写入操作完成。

选择合适的日志级别

在开发和测试环境中,记录详细的日志是有帮助的,但在生产环境中,过多的日志记录可能会导致性能下降和存储过载。合理设置日志级别,仅记录必要的信息,是优化日志性能的另一有效手段:

if debugMode {
    log.Println("Detailed debug information.")
}

使用上述条件语句,可以确保只有在调试模式(debugMode为真)下才记录详细的调试信息。

使用高性能的日志框架

虽然 log/slog 提供了基本的日志功能,但在处理极高性能需求时,可能需要考虑更专业的日志框架,如 zapzerolog。这些框架为性能优化提供了更多的配置选项和更高效的实现。

错误处理和调试

利用 log/slog 进行有效的错误处理

错误处理是软件开发中的一个重要方面,良好的错误处理策略不仅可以减少系统的不稳定性,还可以提供必要的信息以便快速定位问题。log/slog 通过提供清晰的日志记录,可以显著提升错误处理的效率。以下是几种使用 log/slog 进行错误处理的方法:

记录错误信息

当捕获到异常或错误时,应该记录详细的错误信息,包括错误发生的时间、位置和可能的原因。这不仅有助于开发者理解错误的性质,也便于后期的问题追踪和解决。

package main

import (
    "log"
    "os"
)

func main() {
    file, err := os.OpenFile("error_handling.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    logger := log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Llongfile)

    // 模拟一个错误情况
    result, err := someFunctionThatMightFail()
    if err != nil {
        logger.Printf("Error occurred: %v", err)
    }
}

func someFunctionThatMightFail() (int, error) {
    return 0, fmt.Errorf("something went wrong")
}

在这个例子中,someFunctionThatMightFail 函数可能会返回错误,我们通过日志记录详细的错误信息,这样有助于后续的问题分析和修复。

使用日志级别区分错误严重性

根据错误的严重性,可以使用不同的日志级别来记录错误。这样做可以使日志更加结构化,便于按严重性进行过滤和查找。

if err != nil {
    if criticalError(err) {
        logger.Fatalf("Critical error occurred: %v", err) // 记录严重错误,并停止程序
    } else {
        logger.Printf("Non-critical error: %v", err) // 记录非严重错误
    }
}

日志和调试技巧

为了更有效地使用日志进行调试,可以采用以下一些技巧:

添加足够的上下文信息

在记录日志时,添加足够的上下文信息是至关重要的。这包括不限于用户ID、操作类型、时间戳等,这些信息可以大大提升日志的用途。

利用日志分析工具

将日志记录到一些支持查询和分析的系统中,如ELK(Elasticsearch, Logstash, Kibana)堆栈,可以更有效地利用日志进行问题定位和性能监测。

与其他库的集成

集成 log/slog 与数据库操作库 GORM

在许多现代应用中,与数据库交互是不可避免的,而将日志库与数据库操作库集成可以帮助开发者更好地监控和调试数据库相关的操作。以下是如何将 log/slog 集成到使用 GORM 的项目中:

设置 GORM 的日志接口

GORM 是一个流行的 Golang ORM(对象关系映射)库,它自带一个灵活的日志接口,允许开发者插入自定义的日志处理逻辑。下面的示例展示了如何利用 log/slog 来记录 GORM 的日志:

package main

import (
    "gorm.io/gorm"
    "gorm.io/driver/sqlite"
    "log"
    "os"
)

func main() {
    // 设置日志文件
    file, err := os.OpenFile("gorm_integration.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    logger := log.New(file, "GORM: ", log.Ldate|log.Ltime|log.Lshortfile)

    // 初始化数据库连接
    db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{
        Logger: customLogger{logger},
    })
    if err != nil {
        logger.Println("Failed to connect to database:", err)
        return
    }

    // 数据库操作示例
    db.AutoMigrate(&Product{}) // 自动迁移模式
    logger.Println("Database migration completed.")
}

// 实现 GORM 的 logger 接口
type customLogger struct {
    *log.Logger
}

func (c customLogger) Printf(format string, args ...interface{}) {
    c.Printf(format, args...)
}

type Product struct {
    gorm.Model
    Code  string
    Price uint
}

在这个例子中,我们定义了一个 customLogger 结构,实现了 GORM 的日志接口。这样,所有 GORM 的日志都会通过我们自定义的 log/slog 记录器进行记录。

集成 log/slog 与网络框架 Gin

Gin 是一个高性能的 HTTP Web 框架,将其与 log/slog 集成可以有效地记录 HTTP 请求和响应数据。以下是集成的基本方法:

package main

import (
    "github.com/gin-gonic/gin"
    "log"
    "os"
)

func main() {
    // 配置日志
    file, err := os.OpenFile("gin_integration.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    logger := log.New(file, "GIN: ", log.Ldate|log.Ltime|log.Llongfile)

    // 创建 Gin 实例
    r := gin.New()
    r.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
        // 自定义 Gin 日志格式
        return logger.Printf("Method: %s, Path: %s, Status: %d, Latency: %s\n",
            param.Method, param.Path, param.StatusCode, param.Latency)
    }))
    r.Use(gin.Recovery())

    // 设置路由
    r.GET("/", func(c *gin.Context) {
        c.String(http.StatusOK, "Hello World")
    })

    // 启动服务器
    r.Run()
}

这段代码通过自定义 Gin 的日志格式器将日志记录到我们指定的文件中。这样做不仅增加了日志的可读性,也使得日志的存储更为灵活。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1643703.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【项目学习01_2024.05.05_Day05】

学习笔记 4.3 接口开发4.3.1 树型表查询4.3.2 开发Mapper4.3.3 开发Service4.3.4 测试Service 4.4 接口测试4.4.1 接口层代码完善4.4.2 测试接口 4.3 接口开发 4.3.1 树型表查询 4.3.2 开发Mapper 在对应的Mapper里定义一个方法 在同名的xml文件里具体定义相应的sql语句 4…

上市公司代理成本数据集(2000-2022年)

01、数据介绍 上市公司的代理成本是指因代理问题所产生的损失&#xff0c;为了解决代理问题所发生的成本。这些成本包括监督成本、约束成本和剩余损失。由于信息的不对称&#xff0c;股东无法知道经理人是在为实现股东收益最大化而努力工作&#xff0c;还是只为满足平稳的投资…

线性数据结构-手写队列-哈希(散列)Hash

什么是hash散列&#xff1f; 哈希表的存在是为了解决能通过O(1)时间复杂度直接索引到指定元素。这是什么意思呢&#xff1f;通过我们使用数组存放元素&#xff0c;都是按照顺序存放的&#xff0c;当需要获取某个元素的时候&#xff0c;则需要对数组进行遍历&#xff0c;获取到指…

定子的检查和包扎及转子的检查

线圈接好后 用摇表测试 线圈和外壳之间的绝缘性&#xff01; 测试通过后进行焊接&#xff01;&#xff0c;焊接的工具在后面的文章中会介绍&#xff01; 焊接好后&#xff0c;包绝缘管。 焊接完成后 进行星型连接&#xff0c;或者三角形连接&#xff01; 白扎带进行绑扎&…

【Android】Android应用性能优化总结

AndroidApp应用性能优化总结 最近大半年的时间里&#xff0c;大部分投在了某国内新能源汽车的某款AndroidApp开发上。 由于该App是该款车上&#xff0c;常用重点应用。所以车厂对应用性能的要求比较高。 主要包括&#xff1a; 应用冷启动达到***ms。应用热(温)启动达到***ms应…

一测知“芯”!芯片测试如何确保电子设备的“心脏”健康?

文章目录 封装&#xff1a;芯片的“铠甲”与“桥梁”测试&#xff1a;芯片质量的“守门员”《芯片封测从入门到精通》亮点内容简介作者简介目录获取方式 在高科技飞速发展的今天&#xff0c;芯片作为电子设备的心脏&#xff0c;承载着计算、控制、存储等核心功能。然而&#xf…

二.数据结构

单链表 数组实现单链表: int head; //head存储这个单链表的头结点 int value[N];//value存储结点的值 int nextt[N];//nextt存储结点的next指针 int id; //id表示当前用到的点的位置 //初始化: void Init(){head-1,id0;//链表的头节点要指向-1,当前结点位置为0 } //在…

python数据分析——在数据分析中有关概率论的知识

参数和统计量 前言一、总体二、样本三、统计抽样四、随机抽样4.1. 抽签法4.2. 随机数法 五、分层抽样六、整群抽样七、系统抽样八、统计参数九、样本统计量十、样本均值和样本方差十一、描述样本集中位置的统计量11.1. 样本均值11.2. 样本中位数11.3. 样本众数 十二、描述样本分…

分层解耦(IOC-DI引入)

目录 一、为什么要解耦 二、示例分析 三、如何解除耦合&#xff1f; 四、控制反转和依赖注入-简述 一、为什么要解耦 内聚&#xff1a;软件中各个功能模块内部的功能联系耦合&#xff1a;衡量软件中各个层/模块之间的依赖、关联的程度软件设计原则&#xff1a;高内聚低耦合…

FilterListener详解

文章目录 MVC模式和三层架构MVC模式三层架构MVC和三层架构 JavaWeb的三大组件Filter概述快速入门过滤器API介绍过滤器开发步骤配置过滤器俩种方式修改idea的过滤器模板 使用细节生命周期拦截路径过滤器链 案例统一解决全站乱码问题登录权限校验验 ServletContextServletContext…

Java项目:基于SSM框架实现的高校专业信息管理系统设计与实现(ssm+B/S架构+源码+数据库+毕业论文+PPT+开题报告)

一、项目简介 本项目是一套基于SSM框架实现的高校专业信息管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、…

基于51单片机PWM控制直流电机—数码管显示

基于51单片机PWM控制直流电机 &#xff08;仿真&#xff0b;程序&#xff0b;设计报告&#xff09; 功能介绍 具体功能&#xff1a; 1.L298驱动直流电机&#xff1b; 2.数码管显示转动方向和PWM占空比&#xff08;0-100%&#xff09;&#xff1b; 3.按键控制PWM占空比来加/…

Centos7网络处理name or service not known

1、编辑->虚拟网络编辑器 2、查看本机的ip 3、 /etc/sysconfig/network-scripts/ 查看文件夹下面的 ifcfg-eth33 后面的33可能不一样 vi /etc/resolv.conf 编辑文件添加以下DNS nameserver 114.114.114.114 4、设置本机的网络 5、ping www.baidu.com 先重启…

交叉导轨维护和保养的方法!

交叉导轨系统作为一种常见的机械传动装置&#xff0c;广泛应用于各种精密机械设备中。为了确保交叉导轨系统的正常运行和延长其使用寿命&#xff0c;定期维护和保养是至关重要的。 1、清洁&#xff1a;定期清理交叉导轨表面的灰尘、油污等杂质&#xff0c;保持其清洁。在清理过…

【C++】详解STL的容器之一:list

目录 简介 初识list 模型 list容器的优缺点 list的迭代器 常用接口介绍 获取迭代器 begin end empty size front back insert push_front pop_front push_back pop_back clear 源代码思路 节点设计 迭代器的设计 list的设计 begin() end() 空构造 ins…

公众号/小程序 开发模式切换

开发公众号/小程序 模式切换 https://ke.qq.com/course/6033257/14616022822424425#term_id106263577

QT5之lambda+内存回收机制

使用lambda需要 配置c11 所以在点.pro文件里面配置添加如下 CONFIG c11 使用到qDebug 打印包含头文件 #include<QDebug> lambda 表达式使用 代替槽如下 #include "mainwidget.h" #include<QPushButton> #include<QDebug> mainWidget::mainWid…

VGA接口驱动与图像显示动态移动(未完)

描述&#xff1a; 实现vga彩条显示&#xff0c;并以彩条为背景&#xff0c;显示一个200x200像素的白色方框&#xff08;可填充任意像素匹配的照片&#xff09;&#xff0c;可以实现如下移动规律&#xff1a; 水平方向和竖直方向的速度一样。当一个方向碰到边框的时候&#xff…

写爬虫代码抓取Asterank中小行星数据

2024年5月4日 问题来源 解决方案 回顾2023年7月14日自己写的爬虫代码 import requests import re import pandas as pd texts[] def getData(page):#每页评论的网址urlhttps://item.jd.com/51963318622.html#comment#添加headers&#xff0c;伪装成浏览器headers{User-Agent:…

Redis(基础指令和五大数据类型)

文章目录 1.基本介绍1.多种数据结构支持2.应用场景 2.Redis安装&#xff08;直接安装到云服务器&#xff09;1.安装gcc1.yum安装gcc2.查看gcc版本 2.将redis6.2.6上传到/opt目录下3.进入/opt目录下然后解压4.进入 redis-6.2.6目录5.编译并安装6.进入 /usr/local/bin 查看是否有…