平台配置日志输出和推送到APM与LogStash

场景描述

目前设计器镜像启动后日志文件为out.log,是启动脚本中定向输出了(>>)out.log文件。实际项目可能:

  • 日志输出到特定目录的特定文件名中
  • 指定以日志保留策略(单个文件大小和文件保留个数)
  • 日志输出到APM工具中(如skywalking)
  • 日志推送到LogStash

日志自定义输出

不定向输出,采用自己配置的方式,与标准的SpringBoot工程配置日志一样。两种方式(都是Spring提供的方式):

方式一

bootstrap.yml 里面可以按profiles指定logback的配置文件,具体文件名和文件输入在logback里面进行配置,跟通用的logback配置一致. 例如:

logging:
  config: classpath:logback-pre.xml

方式二

resources的根目录,直接配置 logback-spring.xml, 启动会自动加载。

日志自定义场景

配置日志推送到LogStash

    <!--配置日志推送到LogStash-->
    <contextListener class="pro.shushi.pamirs.demo.core.config.DemoLogbackFiledConfig"/>
    <appender name="LogStash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>127.0.0.1:4560</destination>
        <!-- encoder必须配置,有多种可选 -->
        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder">
            <!--  SkyWalking插件, log加tid-->
            <provider class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.logstash.TraceIdJsonProvider" />
            <!--在生成的json中会加这些字段-->
            <customFields>
                {"app.name":"pamirs-demo", "app.type":"Microservice", "platform":"pamirs", "env":"dev"}
            </customFields>
            <timeZone>Asia/Shanghai</timeZone>
            <writeVersionAsInteger>true</writeVersionAsInteger>
            <providers>
                <pattern>
                    <pattern>
                        <!--动态的变量-->
                        {
                        "ip": "%{ip}",
                        "server.name": "%{server.name}",
                        "logger_name": "%logger"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>

skywalking的日志rpc上传

    <!-- skywalking的日志rpc上传 -->
    <appender name="SkyWalkingLogs" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
                <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            </layout>
        </encoder>
    </appender>

完整的代码示例

  • Logback自定义字段
package pro.shushi.pamirs.demo.core.config;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.LoggerContextListener;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.spi.ContextAwareBase;
import ch.qos.logback.core.spi.LifeCycle;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 *  Logback自定义字段
 *
 * @author wx@shushi.pro
 * @date 2024/4/17
 */
public class DemoLogbackFiledConfig extends ContextAwareBase implements LoggerContextListener, LifeCycle {

    private boolean started = false;

    @Override
    public boolean isResetResistant() {
        return false;
    }

    @Override
    public void onStart(LoggerContext loggerContext) {
    }

    @Override
    public void onReset(LoggerContext loggerContext) {
    }

    @Override
    public void onStop(LoggerContext loggerContext) {
    }

    @Override
    public void onLevelChange(Logger logger, Level level) {
    }

    @Override
    public void start() {
        if (started) {
            return;
        }
        Context context = getContext();
        // 机器名称
        context.putProperty("server.name", getHostName());
        // 机器IP地址
        context.putProperty("ip", getHostAddress());
        started = true;
    }

    @Override
    public void stop() {
    }

    @Override
    public boolean isStarted() {
        return false;
    }

    private String getHostName() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return "";
    }

    private String getHostAddress() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return "";
    }
}
  • logback-dev.xml完整内容
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 日志输出格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="%d |-%p [%tid] %class:%line - %m%n"/>

    <!-- 控制台日志 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <pattern>${CONSOLE_LOG_PATTERN}</pattern><!-- 此处设置输出格式 -->
            </layout>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
    </appender>

    <!-- 文件日志 -->
    <appender name="fileLogger"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>/Users/wangxian/logs/pamirs-demo.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>/Users/wangxian/logs/pamirs-demo-%d-%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- 日志文件的最多存储64MB -->
                <maxFileSize>500MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
           <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <pattern>${CONSOLE_LOG_PATTERN}</pattern><!-- 此处设置输出格式 -->
            </layout>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
    </appender>

    <!--配置日志推送到LogStash-->
    <contextListener class="pro.shushi.pamirs.demo.core.config.DemoLogbackFiledConfig"/>
    <appender name="LogStash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>127.0.0.1:4560</destination>
        <!-- encoder必须配置,有多种可选 -->
        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder">
            <!--  SkyWalking插件, log加tid-->
            <provider class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.logstash.TraceIdJsonProvider" />
            <!--在生成的json中会加这些字段-->
            <customFields>
                {"app.name":"pamirs-demo", "app.type":"Microservice", "platform":"pamirs", "env":"dev"}
            </customFields>
            <timeZone>Asia/Shanghai</timeZone>
            <writeVersionAsInteger>true</writeVersionAsInteger>
            <providers>
                <pattern>
                    <pattern>
                        <!--动态的变量-->
                        {
                        "ip": "%{ip}",
                        "server.name": "%{server.name}",
                        "logger_name": "%logger"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>

    <!-- skywalking的日志rpc上传 -->
    <appender name="SkyWalkingLogs" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
                <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            </layout>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="LogStash"/>
        <appender-ref ref="SkyWalkingLogs"/>
    </root>

    <!-- Nacos的心跳检测日志级别设置 (会自动继承root 的appender) -->
    <logger name="com.alibaba" level="ERROR">
    </logger>
    <!-- xxl-job心跳检查日志级别 -->
    <logger name="com.xxl.job.core.thread" level="ERROR"/>
</configuration>
  • 分为debug、info、warn、error四种类型的日志信息,分别保存到此四个文件夹中,并按大小和日期进行归档
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->

<!-- 根节点<configuration>,包含下面三个属性:-->
<!-- scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。-->
<!-- scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。-->
<!-- debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。-->
<configuration>
   <contextName>dimples-logback</contextName>
   <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
   <property name="log.path" value="C:/springboot-log/logs" />

   <!-- 彩色日志 -->
   <!-- 彩色日志依赖的渲染类 -->
   <conversionRule conversionWord="clr"
      converterClass="org.springframework.boot.logging.logback.ColorConverter" />
   <conversionRule conversionWord="wex"
      converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
   <conversionRule conversionWord="wEx"
      converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
   <!-- 彩色日志格式 -->
   <property name="CONSOLE_LOG_PATTERN"
      value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
   <property name="log.colorPattern" value="%magenta(%d{yyyy-MM-dd HH:mm:ss}) %highlight(%-5level) %boldCyan([${springAppName:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]) %yellow(%thread) %green(%logger) %msg%n"/>
   <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level [${springAppName:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}] %thread %logger %msg%n"/>
   <!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%i索引【从数字0开始递增】,,, -->
   <!-- appender是configuration的子节点,是负责写日志的组件。 -->
   <!-- ConsoleAppender:把日志输出到控制台 -->
   <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
      <encoder>
         <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
         <!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
         <charset>UTF-8</charset>
      </encoder>
   </appender>

   <!-- 时间滚动输出 level为 DEBUG 日志 -->
   <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <!-- 正在记录的日志文件的路径及文件名 -->
      <file>${log.path}\debug/log_debug.log</file>
      <!--日志信息输出格式-->
      <encoder>
         <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
         <charset>UTF-8</charset> <!-- 设置字符集 -->
      </encoder>
      <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
         <!-- 日志归档 -->
         <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd-HH}.%i.log</fileNamePattern>
         <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
         </timeBasedFileNamingAndTriggeringPolicy>
         <!--日志文件保留天数-->
         <maxHistory>15</maxHistory>
      </rollingPolicy>
      <!-- 此日志文件只记录debug级别的 -->
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <level>debug</level>
         <onMatch>ACCEPT</onMatch>
         <onMismatch>DENY</onMismatch>
      </filter>
   </appender>

   <!-- 时间滚动输出 level为 INFO 日志 -->
   <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <!-- 正在记录的日志文件的路径及文件名 -->
      <file>${log.path}\info/log_info.log</file>
      <!--日志信息输出格式-->
      <encoder>
         <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
         <charset>UTF-8</charset>
      </encoder>
      <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
         <!-- 每天日志归档路径以及格式 -->
         <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd-HH}.%i.log</fileNamePattern>
         <timeBasedFileNamingAndTriggeringPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
         </timeBasedFileNamingAndTriggeringPolicy>
         <!--日志文件保留天数-->
         <maxHistory>15</maxHistory>
      </rollingPolicy>
      <!-- 此日志文件只记录info级别的 -->
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <level>info</level>
         <onMatch>ACCEPT</onMatch>
         <onMismatch>DENY</onMismatch>
      </filter>
   </appender>

   <!-- 时间滚动输出 level为 WARN 日志 -->
   <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <!-- 正在记录的日志文件的路径及文件名 -->
      <file>${log.path}\warn/log_warn.log</file>
      <!--日志信息输出格式-->
      <encoder>
         <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
         <charset>UTF-8</charset> <!-- 此处设置字符集 -->
      </encoder>
      <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
         <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd-HH}.%i.log</fileNamePattern>
         <timeBasedFileNamingAndTriggeringPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
         </timeBasedFileNamingAndTriggeringPolicy>
         <!--日志文件保留天数-->
         <maxHistory>30</maxHistory>
      </rollingPolicy>
      <!-- 此日志文件只记录warn级别的 -->
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <level>warn</level>
         <onMatch>ACCEPT</onMatch>
         <onMismatch>DENY</onMismatch>
      </filter>
   </appender>
   <!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
   <!--             2.如果日期没有发生变化,但是当前日志的文件大小超过1KB时,对当前日志进行分割 重命名-->
   <!-- 时间滚动输出 level为 ERROR 日志 -->
   <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <!-- 正在记录的日志文件的路径及文件名 -->
      <file>${log.path}\error/log_error.log</file>
      <!--日志信息输出格式-->
      <encoder>
         <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
         <charset>UTF-8</charset> <!-- 此处设置字符集 -->
      </encoder>
      <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
         <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd-HH}.%i.log</fileNamePattern>
         <timeBasedFileNamingAndTriggeringPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100MB</maxFileSize>
         </timeBasedFileNamingAndTriggeringPolicy>
         <!--日志文件保留天数-->
         <maxHistory>30</maxHistory>
      </rollingPolicy>
      <!-- 此日志文件只记录ERROR级别的 -->
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
         <level>ERROR</level>
         <onMatch>ACCEPT</onMatch>
         <onMismatch>DENY</onMismatch>
      </filter>
   </appender>
   <!--开发环境:打印控制台-->
   <!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
   <!-- com.dimples.springboot.biz为业务逻辑根包,也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG -->
   <!-- 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE  -->
   <springProfile name="dev">
      <logger name="com.dimples.springboot.biz" level="debug" />
   </springProfile>
   <!-- 控制台输出日志级别 -->
   <root level="info">
      <appender-ref ref="CONSOLE" />
      <appender-ref ref="DEBUG_FILE" />
      <appender-ref ref="INFO_FILE" />
      <appender-ref ref="WARN_FILE" />
      <appender-ref ref="ERROR_FILE" />
   </root>

   <!--生产环境:输出到文件-->
   <!--<springProfile name="pro">-->
   <!--<root level="info">-->
   <!--<appender-ref ref="CONSOLE" />-->
   <!--<appender-ref ref="DEBUG_FILE" />-->
   <!--<appender-ref ref="INFO_FILE" />-->
   <!--<appender-ref ref="ERROR_FILE" />-->
   <!--<appender-ref ref="WARN_FILE" />-->
   <!--</root>-->
   <!--</springProfile>-->
</configuration>

Oinone社区 作者:望闲原创文章,如若转载,请注明出处:https://doc.oinone.top/install/7370.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
望闲的头像望闲数式管理员
上一篇 2024年5月18日 pm3:14
下一篇 2024年5月18日 pm4:45

相关推荐

  • 如何通过自定义支持excel导出的动态表头

    介绍 本文需要阅读过前置文档如何自定义Excel导出功能,动态表头的功能在前置文档的基础上做的进一步扩展,本文未提到的部分都参考这个前置文档。 在日常的业务开发中,我们在导出的场景会遇到需要设置动态表头的场景,比如统计商品在最近1个月的销量,固定表头列为商品的名称等基础信息,动态表头列为最近一个月的日期,在导出的时候设置每个日期的销量,本文将通过此业务场景提供示例代码。 1.自定义导出任务模型 package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.file.api.model.ExcelExportTask; import pro.shushi.pamirs.meta.annotation.Model; @Model.model(DemoItemDynamicExcelExportTask.MODEL_MODEL) @Model(displayName = "商品-Excel动态表头导出任务") public class DemoItemDynamicExcelExportTask extends ExcelExportTask { public static final String MODEL_MODEL = "demo.DemoItemDynamicExcelExportTask"; } 2.自定义导出任务处理数据的扩展点 package pro.shushi.pamirs.demo.core.excel.exportdemo.extPoint; import org.springframework.stereotype.Component; import pro.shushi.pamirs.core.common.FetchUtil; import pro.shushi.pamirs.core.common.cache.MemoryIterableSearchCache; import pro.shushi.pamirs.demo.api.model.DemoItem; import pro.shushi.pamirs.file.api.config.FileConstant; import pro.shushi.pamirs.file.api.context.ExcelDefinitionContext; import pro.shushi.pamirs.file.api.enmu.ExcelTemplateTypeEnum; import pro.shushi.pamirs.file.api.entity.EasyExcelCellDefinition; import pro.shushi.pamirs.file.api.extpoint.impl.ExcelExportSameQueryPageTemplate; import pro.shushi.pamirs.file.api.model.ExcelExportTask; import pro.shushi.pamirs.file.api.model.ExcelWorkbookDefinition; import pro.shushi.pamirs.file.api.util.ExcelFixedHeadHelper; import pro.shushi.pamirs.file.api.util.ExcelHelper; import pro.shushi.pamirs.file.api.util.ExcelTemplateInit; import pro.shushi.pamirs.framework.common.entry.TreeNode; import pro.shushi.pamirs.meta.annotation.ExtPoint; import pro.shushi.pamirs.meta.api.CommonApiFactory; import pro.shushi.pamirs.meta.api.core.orm.ReadApi; import pro.shushi.pamirs.meta.api.core.orm.systems.relation.RelationReadApi; import pro.shushi.pamirs.meta.api.dto.config.ModelConfig; import pro.shushi.pamirs.meta.api.dto.config.ModelFieldConfig; import pro.shushi.pamirs.meta.api.session.PamirsSession; import pro.shushi.pamirs.meta.enmu.TtypeEnum; import pro.shushi.pamirs.meta.util.FieldUtils; import java.util.*; @Component public class DemoItemDynamicExportExtPoint extends ExcelExportSameQueryPageTemplate<DemoItem> implements ExcelTemplateInit { public static final String TEMPLATE_NAME ="商品动态导出"; @Override public List<ExcelWorkbookDefinition> generator() { ExcelFixedHeadHelper excelFixedHeadHelper = ExcelHelper.fixedHeader(DemoItem.MODEL_MODEL,TEMPLATE_NAME) .createBlock(TEMPLATE_NAME, DemoItem.MODEL_MODEL) .setType(ExcelTemplateTypeEnum.EXPORT); return Collections.singletonList(excelFixedHeadHelper.build()); } public static void buildHeader(ExcelFixedHeadHelper excelFixedHeadHelper) { excelFixedHeadHelper.addColumn("name","名称") .addColumn("cateName","类目") .addColumn("searchFrom","搜索来源") .addColumn("description","描述") .addColumn("itemPrice","单价") .addColumn("inventoryQuantity","库存"); } @Override @ExtPoint.Implement(expression = "context.model == \"" + DemoItem.MODEL_MODEL+"\" && context.name == \"" +TEMPLATE_NAME+"\"" ) public List<Object> fetchExportData(ExcelExportTask exportTask, ExcelDefinitionContext context) { List<Object> result = super.fetchExportData(exportTask,context); Object block = result.get(0); if (block instanceof ArrayList) { ((List<Object>) block).forEach(o -> { if (o instanceof DemoItem) { DemoItem item = (DemoItem) o; // TODO 设置动态表头部分字段的值 item.get_d().put("2024-09-10", "1111"); item.get_d().put("2024-09-11", "2222"); }…

    2024年9月11日
    2.7K00
  • nginx如何配置后端服务的负载均衡

    要在Nginx中实现对同一套服务部署两遍并且按比例分配请求,你可以利用Nginx的负载均衡功能。具体做法如下: 步骤 1: 配置 upstream 首先,在Nginx的配置文件(通常是/etc/nginx/nginx.conf或/etc/nginx/sites-available/default,具体路径可能因系统而异)中定义一个upstream块,列出你的两个服务实例。这里假设你的两个服务实例运行在相同的主机上,但监听不同的端口,例如8080和8081。 http { upstream backend { server 192.168.1.100:8091 weight=1; server 192.168.1.101:8091 weight=1; } # … } 在这个例子中,weight=1表示两个服务实例具有相同的权重,Nginx会尽量以1:1的比例分配请求给这两个实例。 步骤 2: 配置 location 或 server 块 接着,在配置文件中找到或添加一个server块,然后在其中的location指令内指定使用刚刚定义的upstream。 server { listen 80; server_name your.domain.com; location / { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } 这里的proxy_pass http://backend;告诉Nginx将请求转发到名为backend的upstream定义的服务器列表中。 步骤 3: 重启Nginx 最后,保存配置文件并重启Nginx以使更改生效。 sudo nginx -t # 先测试配置是否正确 sudo systemctl restart nginx # 或者 service nginx restart,取决于你的系统 注意事项 确保你的两个服务实例是完全独立且状态同步的,以避免数据不一致或服务故障。 使用weight参数可以调整分配策略,如果你想改变分配比例,可以通过修改weight值来实现。 考虑到高可用性,还可以配置max_fails和fail_timeout等参数来处理失败的后端连接。

    2024年6月5日
    1.2K00
  • 自定义RSQL占位符(placeholder)及在权限中使用

    1 自定义RSQL占位符常用场景 统一的数据权限配置 查询表达式的上下文变量扩展 2 自定义RSQL的模板 /** * 演示Placeholder占位符基本定义 * * @author Adamancy Zhang at 13:53 on 2024-03-24 */ @Component public class DemoPlaceHolder extends AbstractPlaceHolderParser { private static final String PLACEHOLDER_KEY = "${thisPlaceholder}"; /** * 占位符 * * @return placeholder */ @Override public String namespace() { return PLACEHOLDER_KEY; } /** * 占位符替换值 * * @return the placeholder replace to the value */ @Override protected String value() { return PamirsSession.getUserId().toString(); } /** * 优先级 * * @return execution order of placeholders, ascending order. */ @Override public Integer priority() { return 0; } /** * 是否激活 * * @return the placeholder is activated */ @Override public Boolean active() { return true; } } 注意事项 在一些旧版本中,priority和active可能不起作用,为保证升级时不受影响,请保证该属性配置正确。 PLACEHOLDER_KEY变量表示自定义占位符使用的关键字,需按照所需业务场景的具体功能并根据上下文语义正确定义。 为保证占位符可以被正确替换并执行,所有占位符都不应该出现重复,尤其是不能与系统内置的重复。 3 占位符使用时的优先级问题 多个占位符在进行替换时,会根据优先级按升序顺序执行,如需要指定替换顺序,可使用Spring的Order注解对其进行排序。 import org.springframework.core.annotation.Order; @Order(0) 4 Oinone平台内置的占位符 占位符 数据类型 含义 备注 ${currentUser} String 当前用户ID 未登录时无法使用 ${currentRoles} Set<String> 当前用户的角色ID集合 未登录时无法使用 5 如何覆盖平台内置的占位符? 通过指定占位符的优先级,并定义相同的namespace可优先替换。 6 如何定义会话级别的上下文变量? 在上述模板中,我们使用的是Oinone平台内置的上下文变量进行演示,通常情况下,我们需要根据实际业务场景增加上下文变量,以此来实现所需功能。 下面,我们将根据当前用户获取当前员工ID定义该上下文变量进行演示。 /** * 员工Session * * @author Adamancy Zhang at 14:33 on 2024-03-24 */ @Component public class EmployeeSession implements HookBefore { private static final String SESSION_KEY = "CUSTOM_EMPLOYEE_ID"; @Autowired private DemoEmployeeService demoEmployeeService; public static String getEmployeeId() { return PamirsSession.getTransmittableExtend().get(SESSION_KEY);…

    2024年3月24日
    1.3K00
  • DsHint(指定数据源)和BatchSizeHint(指定批次数量)

    概述和使用场景 DsHintApi ,强制指定数据源, BatchSizeHintApi ,强制指定查询批量数量 API定义 DsHintApi public static DsHintApi model(String model/**模型编码*/) { // 具体实现 } public DsHintApi(Object dsKey/***数据源名称*/) { // 具体实现 } BatchSizeHintApi public static BatchSizeHintApi use(Integer batchSize) { // 具体实现 } 使用示例 1、【注意】代码中使用 try-with-resources语法; 否则可能会出现数据源错乱 2、DsHintApi使用示例包裹在try里面的所有查询都会强制使用指定的数据源 // 使用方式1: try (DsHintApi dsHintApi = DsHintApi.model(PetItem.MODEL_MODEL)) { List<PetItem> items = demoItemDAO.customSqlDemoItem(); PetShopProxy data2 = data.queryById(); data2.fieldQuery(PetShopProxy::getPetTalents); } // 使用方式2: try (DsHintApi dsHintApi = DsHintApi.use("数据源名称")) { List<PetItem> items = demoItemDAO.customSqlDemoItem(); PetShopProxy data2 = data.queryById(); data2.fieldQuery(PetShopProxy::getPetTalents); } 3、BatchSizeHintApi使用示例包裹在try里面的所有查询都会按照指定的batchSize进行查询 // 查询指定每次查询500跳 try (BatchSizeHintApi batchSizeHintApi = BatchSizeHintApi.use(500)) { PetShopProxy data2 = data.queryById(); data2.fieldQuery(PetShopProxy::getPetTalents); } // 查询指定不分页(batchSize=-1)查询。 请注意,你必须在明确不需要分页查询的情况下使用;如果数据量超大不分页可能会卡死。默认不指定分页数的情况下下平台会进行分页查询 try (BatchSizeHintApi batchSizeHintApi = BatchSizeHintApi.use(-1)) { PetShopProxy data2 = data.queryById(); data2.fieldQuery(PetShopProxy::getPetTalents); }

    2024年5月18日
    1.2K00
  • Oinone支持的操作系统和中间件

    Oinone支持的操作系统和中间件 操作系统 操作系统 支持版本 说明 银河麒麟-飞腾版 V10 支持Java和go环境即可; Java要求jdk1.8 (1.8_221+); 低于1.8_221版本需要覆盖掉jce 银河麒麟-鲲鹏版 V10 统信服务器操作系统 V4.0 CentOS/Ubuntu/Debian 7,8,9 其他兼容的Linux系统 能安装Docker或运行go和Java环境即可 Windows Server 能安装Docker或运行go和Java环境即可 数据库 数据库类型 支持版本 说明 MySQL 5.7.x、8.0.x MySQL协议相关的,如:MariaDB,TiDB,PolarDB等。推荐使用8.0.X 达梦数据库(Dameng) 7.6、8.1 PostgreSQL 14.x 华为GaussDB/openGauss 5.x SQL Server 2017 人大金仓/电科金仓 9 Kingbase CDN CDN类型 服务 OSS 阿里云OSS UPYUN 又拍云 MINIO MinIO HUAWEI_OBS 华为云OBS TENCENT_COS 腾讯云COS LOCAL NGINX文件存储 可自定义方式进行扩展 应用服务器 应用服务器 支持版本/说明 Tomcat 主流版本都支持 TongWeb 东方通web服务器 SpringBoot内嵌Tomcat 原生的启动方式: java -jar的方式启动 Jetty 主流版本都支持 其他Java web服务器 支持标准Servlet规范和JavaEE规范的应用服务器 消息队列 消息队列 支持版本/说明 RocketMQ 4.x,推荐4.7+ Kafka 2.x, 推荐 2.5+ Rabbitmq 5.x, 推荐5.7+ 可自定义方式进行扩展 注册中心和配置中心 类型 支持版本/说明 Nacos 1.4.1 + 和 2.x都可以; 支持ACL时,必须是1.4.1以上 Zookeeper 3.4.x, 3,5,x 其他基础 类型 支持版本/说明 Java(jdk) 1.8_221+,低于这个版本需要覆盖JCE Reids 4.x、5.x Nginx 版本无特殊要求 Elasticsearch(ES) 7.x, 8.x ,推荐8.x SpringBoot 2.3.8.Release

    2025年3月19日
    1.1K00

Leave a Reply

登录后才能评论