消息网关内部采用MySQL
进行消息持久化,需要大量的I/O开销
,因此在高并发请求下会成为系统瓶颈,亟需一种高吞吐量的替代方案。
这里主要思考了2种解决方案:
寻找一种MySQL
的替代方案。由于MySQL
是基于B-Tree
的,考虑性能提升的话,需要采用基于LSM-Tree
的方案设计的数据库
B-Tree
vs LSM-Tree
,分别适合读多和写多的场景放弃以DB
进行数据持久化的方案,转而采用ES
等其他引擎。这里又可以进一步细化为2种方式,分别为
ES-Template
,将数据存储到ES
中log
中,通过中间件将log
中的信息同步至ES
其中,第一种方案需要引入新的依赖,同时在有新租户接入时面临比较大的代码编写任务;而第二种方案仅需配置logback.xml
,在有新tenant接入时,采用扩展的方式就可以很好的完成对接。
这里需要着重考虑的一点是,写入不同的log文件时,是否可以采用对先用代码无侵入的解决方案?
答案是:javaagent
<configuration>
<property name="LOG_DIR" value="resource/log-save"/>
<property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %msg%n"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<target>System.outtarget>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}pattern>
encoder>
appender>
<appender name="tenant_A" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/tenantA.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/tenantA_%d{yyyy-MM-dd}.log.%i.gzfileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>50MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>10maxHistory>
rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}pattern>
encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARNlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<appender name="tenant_B" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/tenantB.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/tenantB_%d{yyyy-MM-dd}.log.%i.gzfileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>50MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>10maxHistory>
rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}pattern>
encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARNlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<appender name="tenant_Default" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/tenantDefault.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/tenantDefault_%d{yyyy-MM-dd}.log.%i.gzfileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>50MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>10maxHistory>
rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}pattern>
encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARNlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender" >
<discardingThreshold>0discardingThreshold>
<queueSize>512queueSize>
<neverBlock>trueneverBlock>
<appender-ref ref="tenant_A" />
<appender-ref ref="tenant_B" />
<appender-ref ref="tenant_Default" />
appender>
<root level="info">
<level>infolevel>
<appender-ref ref="ASYNC"/>
<appender-ref ref="tenant_A"/>
<appender-ref ref="tenant_B"/>
<appender-ref ref="tenant_Default"/>
root>
<logger name="com.example.logback.domain.factory.DefaultLogger" level="warn" additivity="false">
<level value="warn"/>
<appender-ref ref="tenant_Default"/>
logger>
<logger name="com.example.logback.domain.factory.TenantALogger" level="warn" additivity="false">
<level value="warn"/>
<appender-ref ref="tenant_A"/>
logger>
<logger name="com.example.logback.domain.factory.TenantBLogger" level="warn" additivity="false">
<level value="warn"/>
<appender-ref ref="tenant_B"/>
logger>
configuration>
这部分很多,参考我的另一篇文章:
https://www.yuque.com/docs/share/205ed300-cb08-4929-8cb4-7d61631fd152?# 《2022-02-18【agent代理】》
一波三折的一次实践。
首先,晒出最终的filebeat
配置:
###################### Filebeat Configuration Example #########################
# This file is an example configuration file highlighting only the most common
# options. The filebeat.full.yml file from the same directory contains all the
# supported options with more comments. You can use it as a reference.
#
# You can find the full configuration reference here:
# https://www.elastic.co/guide/en/beats/filebeat/index.html
#=========================== Filebeat prospectors =============================
filebeat.inputs:
# Each - is a prospector. Most options can be set at the prospector level, so
# you can use different prospectors for various configurations.
# Below are the prospector specific configurations.
- type: log
enabled: true
# Paths that should be crawled and fetched. Glob based paths.
paths:
- /home/admin/koms/log2/error.log
json.keys_under_root: true
json.overwrite_keys: true
tags: ["error"]
- type: log
enabled: true
# Paths that should be crawled and fetched. Glob based paths.
paths:
- /home/logback/resource/log-save/tenantA.log
json.keys_under_root: true
json.overwrite_keys: true
tags: ["tenantA"]
- type: log
enabled: true
# Paths that should be crawled and fetched. Glob based paths.
paths:
- /home/logback/resource/log-save/tenantB.log
json.keys_under_root: true
json.overwrite_keys: true
tags: ["tenantB"]
- type: log
enabled: true
# Paths that should be crawled and fetched. Glob based paths.
paths:
- /home/logback/resource/log-save/tenantDefault.log
json.keys_under_root: true
json.overwrite_keys: true
tags: ["tenantDefault"]
# - /home/admin/koms/log2/info.log
#- c:\programdata\elasticsearch\logs\*
# Exclude lines. A list of regular expressions to match. It drops the lines that are
# matching any regular expression from the list.
#exclude_lines: ["^DBG"]
# Include lines. A list of regular expressions to match. It exports the lines that are
# matching any regular expression from the list.
#include_lines: ["^ERR", "^WARN", "^INFO"]
# Exclude files. A list of regular expressions to match. Filebeat drops the files that
# are matching any regular expression from the list. By default, no files are dropped.
#exclude_files: [".gz$"]
# Optional additional fields. These field can be freely picked
# to add additional information to the crawled log files for filtering
#fields:
# level: debug
# review: 1
### Multiline options
# Mutiline can be used for log messages spanning multiple lines. This is common
# for Java Stack Traces or C-Line Continuation
# The regexp Pattern that has to be matched. The example pattern matches all lines starting with [
# multiline.pattern: '^\[[0-9]{4}-[0-9]{2}-[0-9]{2}'
# Defines if the pattern set under pattern should be negated or not. Default is false.
# multiline.negate: true
# Match can be set to "after" or "before". It is used to define if lines should be append to a pattern
# that was (not) matched before or after or as long as a pattern is not matched based on negate.
# Note: After is the equivalent to previous and before is the equivalent to to next in Logstash
# multiline.match: after
# multiline.max_lines: 2000
#================================ General =====================================
# The name of the shipper that publishes the network data. It can be used to group
# all the transactions sent by a single shipper in the web interface.
#name:
# The tags of the shipper are included in their own field with each
# transaction published.
#tags: ["service-X", "web-tier"]
# Optional fields that you can specify to add additional information to the
# output.
#fields:
# env: staging
#================================ Outputs =====================================
# Configure what outputs to use when sending the data collected by the beat.
# Multiple outputs may be used.
#-------------------------- Elasticsearch output ------------------------------
output.elasticsearch:
# Array of hosts to connect to.
hosts: ["xxxx:9200"]
indices:
- index: "filebeat-error-%{+yyyy.MM.dd}"
when.contains:
tags: "error"
- index: "tenanta-%{+yyyy.MM.dd}"
when.contains:
tags: "tenantA"
- index: "tenantb-%{+yyyy.MM.dd}"
when.contains:
tags: "tenantB"
- index: "tenantdefault-%{+yyyy.MM.dd}"
when.contains:
tags: "tenantDefault"
# Optional protocol and basic auth credentials.
#protocol: "https"
#username: "elastic"
#password: "123456"
#----------------------------- Logstash output --------------------------------
#output.logstash:
# The Logstash hosts
#hosts: ["localhost:5044"]
# Optional SSL. By default is off.
# List of root certificates for HTTPS server verifications
#ssl.certificate_authorities: ["/etc/pki/root/ca.pem"]
# Certificate for SSL client authentication
#ssl.certificate: "/etc/pki/client/cert.pem"
# Client Certificate Key
#ssl.key: "/etc/pki/client/cert.key"
#================================ Logging =====================================
# Sets log level. The default log level is info.
# Available log levels are: critical, error, warning, info, debug
#logging.level: debug
# At debug level, you can selectively enable logging only for some components.
# To enable all selectors use ["*"]. Examples of other selectors are "beat",
# "publish", "service".
#logging.selectors: ["*"]
一开始启动时一直报错下面这个错误,检索到的资料都说是配置文件写法问题。
Exiting: No modules or prospectors enabled and configuration reloading disabled. What files do you want me to watch?
最终发现,并不是写法问题,而是由于filebeat版本过低导致的。上面的写法需要filebeat-6.x,而测试环境使用的还是5.x版本。
果断升级了新版本后,启动成功。
在filebeat向es创建索引的过程中,还出现了一些问题,那就是es中的索引不能有大写字母,所以修改了一下配置文件的index字段信息。
按照上述方法得到的es查询日志如下,不是很直观,因此需要format后进行便捷的查询