elk实践

news2024/9/27 17:26:29

1、背景

鉴于现在项目中的日志比较乱,所以建议使用现在较为流行的elk收集日志并展示;

2下载、配置与启动

在下载 Elastic 产品 | Elastic 官网下载filebeat、logstash、elasticSearch、kibana 版本要一致 本人测试用的7.14 mac版本 实际生产使用7.14 linux版本

2.1Filebeat:

tar -zxvf filebeat-7.14.0-darwin-x86_64.tar.gz

Cd filebeat-7.14.0-darwin-x86_64

配置:filebeat.yml

- type: log
  enabled: true
  paths:
    - /Users/admin/IdeaProjects/maijia-tebu/log/info/*.log
    - /Users/admin/IdeaProjects/taosj-aliexpress-data/log/*/*.log
  multiline.pattern: '^[0-9][0-9][0-9][0-9]'
  multiline.negate: true
  multiline.match: after
output.logstash:
  hosts: ["localhost:5044”]

sudo chown root:root /Users/admin/IdeaProjects/maijia-tebu/log/info root:为执行用户

sudo chown root filebeat.yml

测试配置 ./filebeat test config -e

sudo ./filebeat -e

配置说明:

Paths:后面可以配置多个目录,配置的目录不会去递归,只会在最后的子目录里面寻找.log的文件;

multiline:以 '^[0-9][0-9][0-9][0-9]' 格式后面的识别为一行,这样报错等信息就在一行了;

output.logstash:logstash的地址;

sudo chown admin:admin /Users/admin/IdeaProjects/maijia-tebu/log/info admin:为执行用户 给log目录设置权限

sudo chown root filebeat.yml 给配置文件权限

./filebeat test config -e 测试配置

sudo ./filebeat -e 启动

2.2Logstash:

tar -zxvf logstash-7.14.0-darwin-x86_64.tar.gz

Cd logstash-7.14.0

配置:

Vi ./config/logstash-test.conf

input {
  beats {
    port => 5044  
  }
}
filter{
   dissect {
      mapping => {
        "message" => "%{log_time}|%{ip}|%{serverName}|%{profile}|%{level}|%{logger}|%{thread}|%{traceId}|%{msg}" //与项目中的日志输出格式相对应
     }
   }
   date{
      match => ["log_time", "yyyy-MM-dd HH:mm:ss.SSS"]
      target => "@timestamp"
   }
}
output {
  elasticsearch {
    hosts => ["localhost:9200"]
    index => "logs-%{+YYYY.MM.dd}"  //创建索引的格式
  }
}

sudo ./bin/logstash -f config/logstash-test.conf

2.3elaticSearch:

tar -zxvf elasticsearch-7.14.0-darwin-x86_64.tar.gz

Cd elasticsearch-7.14.0

Sodu ./bin/elasticSearch

检查服务:curl http://127.0.0.1:9200

2.4kibana

tar -zxvf kibana-7.14.0-darwin-x86_64.tar.gz

Cd kibana-7.14.0-darwin-x86_64

配置:如果es与kibana不在同一台服务器,在config/kibana.yml,添加 elasticsearch.url: "http://ip:port"

Sudo ./bin/kibana

检查:浏览器打开http://127.0.0.1:5601

3、新建jar

新建jar包  写一些工具类

3.1Snowflake

import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
import com.baomidou.mybatisplus.core.toolkit.SystemClock;

import java.io.Serializable;
import java.util.Date;
public class Snowflake implements Serializable {
    private static final long serialVersionUID = 1L;

    private final long twepoch;

    private final long workerIdBits = 5L;

    private final long dataCenterIdBits = 5L;
    // 最大支持数据中心节点数0~31,一共32个
    @SuppressWarnings({"PointlessBitwiseExpression", "FieldCanBeLocal"})
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);

    @SuppressWarnings({"PointlessBitwiseExpression", "FieldCanBeLocal"})

    private final long maxDataCenterId = -1L ^ (-1L << dataCenterIdBits);

    // 序列号12位
    private final long sequenceBits = 12L;

    // 机器节点左移12位
    private final long workerIdShift = sequenceBits;

    // 数据中心节点左移17位
    private final long dataCenterIdShift = sequenceBits + workerIdBits;

    // 时间毫秒数左移22位
    private final long timestampLeftShift = sequenceBits + workerIdBits + dataCenterIdBits;

    @SuppressWarnings({"PointlessBitwiseExpression", "FieldCanBeLocal"})

    private final long sequenceMask = -1L ^ (-1L << sequenceBits);// 4095

    private final long workerId;

    private final long dataCenterId;

    private final boolean useSystemClock;

    private long sequence = 0L;

    private long lastTimestamp = -1L;

    /**
     * 构造
     *
     * @param workerId     终端ID
     * @param dataCenterId 数据中心ID
     */
    public Snowflake(long workerId, long dataCenterId) {
        this(workerId, dataCenterId, false);

    }

    /**
     * 构造
     *
     * @param workerId         终端ID
     * @param dataCenterId     数据中心ID
     * @param isUseSystemClock 是否使用{@link SystemClock} 获取当前时间戳
     */
    public Snowflake(long workerId, long dataCenterId, boolean isUseSystemClock) {
        this(null, workerId, dataCenterId, isUseSystemClock);

    }

    /**
     * @param epochDate        初始化时间起点(null表示默认起始日期),后期修改会导致id重复,如果要修改连workerId dataCenterId,慎用
     * @param workerId         工作机器节点id
     * @param dataCenterId     数据中心id
     * @param isUseSystemClock 是否使用{@link SystemClock} 获取当前时间戳
     * @since 5.1.3
     */
    public Snowflake(Date epochDate, long workerId, long dataCenterId, boolean isUseSystemClock) {
        if (null != epochDate) {
            this.twepoch = epochDate.getTime();

        } else {
// Thu, 04 Nov 2010 01:42:54 GMT

            this.twepoch = 1288834974657L;

        }

        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(format("worker Id can't be greater than {} or less than 0", maxWorkerId));

        }

        if (dataCenterId > maxDataCenterId || dataCenterId < 0) {
            throw new IllegalArgumentException(format("datacenter Id can't be greater than {} or less than 0", maxDataCenterId));

        }

        this.workerId = workerId;

        this.dataCenterId = dataCenterId;

        this.useSystemClock = isUseSystemClock;

    }

    /**
     * 根据Snowflake的ID,获取机器id
     *
     * @param id snowflake算法生成的id
     * @return 所属机器的id
     */

    public long getWorkerId(long id) {
        return id >> workerIdShift & ~(-1L << workerIdBits);

    }

    /**
     * 根据Snowflake的ID,获取数据中心id
     *
     * @param id snowflake算法生成的id
     * @return 所属数据中心
     */

    public long getDataCenterId(long id) {
        return id >> dataCenterIdShift & ~(-1L << dataCenterIdBits);

    }

    /**
     * 根据Snowflake的ID,获取生成时间
     *
     * @param id snowflake算法生成的id
     * @return 生成的时间
     */

    public long getGenerateDateTime(long id) {
        return (id >> timestampLeftShift & ~(-1L << 41L)) + twepoch;

    }

    /**
     * 下一个ID
     *
     * @return ID
     */

    public synchronized long nextId() {
        long timestamp = genTime();

        if (timestamp < lastTimestamp) {
            if (lastTimestamp - timestamp < 2000) {
// 容忍2秒内的回拨,避免NTP校时造成的异常

                timestamp = lastTimestamp;

            } else {
// 如果服务器时间有问题(时钟后退) 报错。

                throw new IllegalStateException(format("Clock moved backwards. Refusing to generate id for {}ms", lastTimestamp - timestamp));

            }

        }

        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & sequenceMask;

            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);

            }

        } else {
            sequence = 0L;

        }

        lastTimestamp = timestamp;

        return ((timestamp - twepoch) << timestampLeftShift) | (dataCenterId << dataCenterIdShift) | (workerId << workerIdShift) | sequence;

    }

    /**
     * 下一个ID(字符串形式)
     *
     * @return ID 字符串形式
     */
    public String nextIdStr() {
        return Long.toString(nextId());

    }

// ------------------------------------------------------------------------------------------------------------------------------------ Private method start

    /**
     * 循环等待下一个时间
     *
     * @param lastTimestamp 上次记录的时间
     * @return 下一个时间
     */

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = genTime();

// 循环直到操作系统时间戳变化

        while (timestamp == lastTimestamp) {
            timestamp = genTime();

        }

        if (timestamp < lastTimestamp) {
// 如果发现新的时间戳比上次记录的时间戳数值小,说明操作系统时间发生了倒退,报错

            throw new IllegalStateException(

                    format("Clock moved backwards. Refusing to generate id for {}ms", lastTimestamp - timestamp));

        }

        return timestamp;

    }

    /**
     * 生成时间戳
     *
     * @return 时间戳
     */

    private long genTime() {
        return this.useSystemClock ? SystemClock.now() : System.currentTimeMillis();

    }

    public  String format(String target, Object... params) {
        return target.contains("%s") && ArrayUtils.isNotEmpty(params) ? String.format(target, params) : target;
    }
}

3.2 TraceIdAdvice


import com.alibaba.dubbo.rpc.RpcContext;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.MDC;

/**  * 类 描 述:traceId切面
*/
public class TraceIdAdvice implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        String tid = MDC.get("traceId");
        String rpcTid = RpcContext.getContext().getAttachment("traceId");

        if (tid != null) {
            RpcContext.getContext().setAttachment("traceId", tid);
        } else {
            if (rpcTid != null) {
                MDC.put("traceId",rpcTid);
            }
        }
        Object result = invocation.proceed();
        return result;
    }
}

3.3 TraceIdAdviceConfig


import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/** 
 * 类 描 述:traceId切面动态配置
*/
@Configuration
public class TraceIdAdviceConfig {

    @Value("${traceId.pointcut.property}")
    private String pointcut;

    @Bean
    public AspectJExpressionPointcutAdvisor configurabledvisor() {
        AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
        advisor.setExpression(pointcut);
        advisor.setAdvice(new TraceIdAdvice());
        return advisor;
    }
}

3.4 IPConverterConfig

import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Enumeration;

/**
 * 类 描 述:log打出ip

 */
public class IPConverterConfig extends ClassicConverter {

    private String url;

    @Override
    public String convert(ILoggingEvent iLoggingEvent) {
        try {
            if (url == null){
                String hostAddress = getLocalHostLANAddress().getHostAddress();
                url = hostAddress;
            }
            return url;
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return null;
    }

    // 正确的IP拿法,即优先拿site-local地址
    private static InetAddress getLocalHostLANAddress() throws UnknownHostException{
        try {
            InetAddress candidateAddress = null;
            // 遍历所有的网络接口
            for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements();) {
                NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
                //服务器上eth0才是正确的ip
                if (!"eth0".equals(iface.getName())){
                    continue;
                }
                // 在所有的接口下再遍历IP
                for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) {
                    InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
                    if (!inetAddr.isLoopbackAddress()) {// 排除loopback类型地址
                        if (inetAddr.isSiteLocalAddress()) {
                            // 如果是site-local地址,就是它了
                            return inetAddr;
                        } else if (candidateAddress == null) {
                            // site-local类型的地址未被发现,先记录候选地址
                            candidateAddress = inetAddr;
                        }
                    }
                }
            }
            if (candidateAddress != null) {
                return candidateAddress;
            }
            // 如果没有发现 non-loopback地址.只能用最次选的方案
            InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
            if (jdkSuppliedAddress == null) {
                throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null.");
            }
            return jdkSuppliedAddress;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}

3.5 TraceIdInterceptor

/**
 * 类 描 述:traceId 用于追踪链路

 */
@Slf4j
@Component
public class TraceIdInterceptor implements HandlerInterceptor {

    /*@Autowired
    RedisHelper redisHelper;*/

    Snowflake snowflake = new Snowflake(1,0);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
        String tid = snowflake.nextIdStr();
        MDC.put("traceId",tid);
        RpcContext.getContext().setAttachment("traceId", tid);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView){
        MDC.remove("traceId");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex){}

    //生成导入批次号
    /*public  String getTraceId() {
        String dateString = DateUtils.formatYYYYMMDD(new Date());
        Long incr = redisHelper.incr("taosj-common-traceId" + dateString, 24);
        if (incr == 0) {
            incr = redisHelper.incr("taosj-common-traceId" + dateString, 24);
        }
        DecimalFormat df = new DecimalFormat("000000");
        return dateString + df.format(incr);
    }*/
}

3.6 WebAppConfigurer

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 类 描 述:TODO
 
 */
@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {
    @Autowired
    private TraceIdInterceptor traceIdInterceptor;

    /**
     * 注册拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(traceIdInterceptor).addPathPatterns("/**");
                //.excludePathPatterns("/admin/login")
                //.excludePathPatterns("/admin/getLogin");
        //  - /**: 匹配所有路径
        //  - /admin/**:匹配 /admin/ 下的所有路径
        //  - /admin/*:只匹配 /admin/login,不匹配 /secure/login/tologin ("/*"只匹配一级子目录,"/**"匹配所有子目录)
    }

}

3.7 jar pom

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-core</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
        </dependency>
    </dependencies>

 4、jar包的使用

1、pom文件:

添加自己的jar包

2、启动类增加类扫描:步骤3的包名 

3、配置文件增加切面pointcut配置:例如:traceId.pointcut.property=execution(public * com.taosj.tebu.service..*.*(..)) 自己项目的包名

4、logback-spring文件修改:ip 日志输出格式

<property resource="application.properties"/>

<springProperty scope="context" name="serverName" source="spring.application.name"/>

<conversionRule conversionWord="ip" converterClass="com.taosj.elk.config.IPConverterConfig”/>

<property name="pattern" value="%date{yyyy-MM-dd HH:mm:ss} | %ip | ${serverName} | ${profile} | %highlight(%-5level) | %boldYellow(%thread) | %boldGreen(%logger) | %X{traceId} | %msg%n"/>

<property name="pattern_log" value="%d{yyyy-MM-dd HH:mm:ss.SSS}|%ip|${serverName}|${profile}|%level|%logger|%thread|%X{traceId}|%m%n"/>

应该是把现在正在运行的日志拿过来,所以要把之前的日志删除掉,以及把形成的日志名改掉:

比如<fileNamePattern>${dir}/info/info.%d{yyyy-MM-dd}.%i.log</fileNamePattern> 改成

<fileNamePattern>${dir}/info/info.log.%d{yyyy-MM-dd}.%i</fileNamePattern>

5、springboot项目logback-spring.xml例子

​
<?xml version="1.0" encoding="UTF-8"?>

<configuration>

<springProfile name="dev">

<property name="dir" value="log"/>

</springProfile>

<springProfile name="test">

<property name="dir" value="/data/project/taosj-tebu-web/code/logs"/>

</springProfile>

<springProfile name="pre">

<property name="dir" value="/data/project/taosj-tebu-web/code/logs"/>

</springProfile>

<springProfile name="prod">

<property name="dir" value="/data/project/taosj-tebu-web/code/logs"/>

</springProfile>

<property resource="application.properties"/>

<springProperty scope="context" name="serverName" source="spring.application.name"/>

<conversionRule conversionWord="ip" converterClass="com.taosj.elk.config.IPConverterConfig"/>

<property name="pattern" value="%date{yyyy-MM-dd HH:mm:ss} | %ip | ${serverName} | ${profile} | %highlight(%-5level) | %boldYellow(%thread) | %boldGreen(%logger) | %X{traceId} | %msg%n"/>

<property name="pattern_log" value="%d{yyyy-MM-dd HH:mm:ss.SSS}|%ip|${serverName}|${profile}|%level|%logger|%thread|%X{traceId}|%m%n"/>

<appender name="INFO_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">

<file>${dir}/info/info.log</file>

<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">

<fileNamePattern>${dir}/info/info.log.%d{yyyy-MM-dd}.%i</fileNamePattern>

<maxFileSize>100MB</maxFileSize>

<maxHistory>10</maxHistory>

<totalSizeCap>5GB</totalSizeCap>

</rollingPolicy>

<filter class="com.taosj.bizlogback.LoggerFilter">

<param name="levelMin" value="20000"/>

<param name="levelMax" value="20000"/>

</filter>

<encoder>

<pattern>${pattern_log}</pattern>

<charset>UTF-8</charset>

</encoder>

</appender>

<appender name="DEBUG_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">

<file>${dir}/debug/debug.log</file>

<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">

<fileNamePattern>${dir}/debug/debug.%i.log.%d{yyyy-MM-dd}.%i</fileNamePattern>

<maxFileSize>100MB</maxFileSize>

<maxHistory>10</maxHistory>

<totalSizeCap>5GB</totalSizeCap>

</rollingPolicy>

<filter class="com.taosj.bizlogback.LoggerFilter">

<param name="levelMin" value="10000"/>

<param name="levelMax" value="10000"/>

</filter>

<encoder>

<pattern>${pattern_log}</pattern>

<charset>UTF-8</charset>

</encoder>

</appender>

<appender name="ERROR_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">

<file>${dir}/error/error.log</file>

<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">

<fileNamePattern>${dir}/error/error.log.%d{yyyy-MM-dd}.%i</fileNamePattern>

<maxFileSize>100MB</maxFileSize>

<maxHistory>10</maxHistory>

<totalSizeCap>5GB</totalSizeCap>

</rollingPolicy>

<filter class="com.taosj.bizlogback.LoggerFilter">

<param name="levelMin" value="40000"/>

<param name="levelMax" value="40000"/>

</filter>

<encoder>

<pattern>${pattern_log}</pattern>

<charset>UTF-8</charset>

</encoder>

</appender>

<appender name="BIZ_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">

<file>${dir}/biz/biz.log</file>

<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">

<fileNamePattern>${dir}/biz/biz.log.%d{yyyy-MM-dd}.%i</fileNamePattern>

<maxFileSize>100MB</maxFileSize>

<maxHistory>10</maxHistory>

<totalSizeCap>5GB</totalSizeCap>

</rollingPolicy>

<filter class="com.taosj.bizlogback.LoggerFilter">

<param name="levelMin" value="50000"/>

<param name="levelMax" value="50000"/>

</filter>

<encoder>

<pattern>${pattern_log}</pattern>

<charset>UTF-8</charset>

</encoder>

</appender>

<appender name="console" class="ch.qos.logback.core.ConsoleAppender">

<encoder>

<pattern>${pattern}</pattern>

</encoder>

</appender>

<springProfile name="dev">

<root level="info">

<appender-ref ref="INFO_LOG"/>

<appender-ref ref="ERROR_LOG"/>

<appender-ref ref="DEBUG_LOG"/>

<appender-ref ref="BIZ_LOG"/>

<appender-ref ref="console"/>

</root>

</springProfile>

<springProfile name="prod">

<root level="info">

<appender-ref ref="INFO_LOG"/>

<appender-ref ref="ERROR_LOG"/>

<appender-ref ref="DEBUG_LOG"/>

<appender-ref ref="BIZ_LOG"/>

<appender-ref ref="console"/>

</root>

</springProfile>

<springProfile name="test">

<root level="info">

<appender-ref ref="INFO_LOG"/>

<appender-ref ref="ERROR_LOG"/>

<appender-ref ref="DEBUG_LOG"/>

<appender-ref ref="BIZ_LOG"/>

<appender-ref ref="console"/>

</root>

</springProfile>

<springProfile name="pre">

<root level="info">

<appender-ref ref="INFO_LOG"/>

<appender-ref ref="ERROR_LOG"/>

<appender-ref ref="DEBUG_LOG"/>

<appender-ref ref="BIZ_LOG"/>

<appender-ref ref="console"/>

</root>

</springProfile>

</configuration>

​

7、部署时候的小tip:

7.1:filebeat启动时

nohup ./filebeat & 这样shell关闭了还是会停

nohup ./filebeat & disown 要这样启动

7.2: filebeat推送logstash的地址:

116.62.126.104 35044 可以查看filebeat.yml配置文件

7.4:ip

ip获取的是eth0网卡的ip

7.4:小问题

springmvc项目使用log4j不能一开始就注入servername、ip、profile等信息 所以启动等信息没有这些字段,调用接口等是有这些信息的;springboot项目使用logback没有这个问题

 

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

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

相关文章

甘特图来搞定跨部门协作难的问题!项目经理必备

在很多大的工程项目、IT项目、市场项目中&#xff0c;都会涉及诸多对人员、时间、质量等的控制&#xff0c;这往往需要跨部门协作。但目前大多数企业跨部门协作还是通过微信、口口相传的方式进行&#xff0c;也导致了以下这些问题的频现&#xff1a; 辗转多个群聊提取有用的信息…

笔试强训(三十九)

目录一、选择题二、编程题2.1 字符串计数2.1.1 题目2.1.2 题解一、选择题 &#xff08;1&#xff09;/etc/resolv.conf的用途是&#xff08;C&#xff09; A.邮件服务的配置文件 B.DHCP的设置文件 C.DNS解析的设置文件 D.网络路由的设置文件 &#xff08;2&#xff09;能够pin…

Redis 通用指令

文章目录一、key通用指令1-1 基本操作1-2 时效性控制1-3 查询操作1-4 扩展操作二、数据库通用指令提示&#xff1a;以下是本篇文章正文内容&#xff0c;Redis系列学习将会持续更新 一、key通用指令 ● 特征&#xff1a;key是一个字符串&#xff0c;通过key获取redis中保存的数…

警惕 “格机软件” 格式化手机全字库..不要轻易给不明觉厉的软件给root权限

以前的玩机界中有【锁机】软件。就是你安装一个软件后他会锁住屏幕。导致你无法操作手机。屏幕出现QQ联系方式等 勒索钱财。目前刷机界中的【格机】更胜一筹&#xff0c;直接格式化你手机全部分区没商量............ 警惕&#xff1a;不要给不明觉厉的软件 模块 刷机包等等给r…

Flink的状态持久化和状态后端

状态持久化 检查点的保存离不开 JobManager 和 TaskManager&#xff0c;以及外部存储系统的协调。在应用进行检查点保存时&#xff0c;首先会由 JobManager 向所有 TaskManager 发出触发检查点的命令&#xff1b;TaskManger 收到之后&#xff0c;将当前任务的所有状态进行快照保…

搭建自己Kindle电子书图书馆,并可远程访问

在电子书风靡的时期&#xff0c;大部分人都购买了一本电子书&#xff0c;虽然这本电子书更多的时候是被搁置在储物架上吃灰&#xff0c;或者成为盖泡面的神器&#xff0c;但当亚马逊发布消息将放弃电子书在中国的服务时&#xff0c;还是有些令人惋惜&#xff0c;毕竟谁也不想大…

【虾神白话空间统计】笔记:置信度、零假设、PZ值、随机分布

以下内容摘录节选学习自虾神专栏 很重要的一个概念&#xff1a;在空间统计中&#xff0c;随机和均匀经常是一个意思 一个随机抽样的例子 新版白话空间统计&#xff08;9&#xff09;&#xff1a;置信度的初探 这里面讲经研究&#xff0c;有72%的男生喜欢打篮球&#xff0c;…

【Vue】基础语法(创建项目|数据绑定|事件绑定|声明方法|插值表达式|属性值绑定|循环数组|v-if控制||计算属性|监听器|过滤器)

文章目录1. Vue 思想&#xff1a;2. VUE 的基本使用2.1 创建项目并进行基础测试2.2 数据绑定2.3 事件绑定2.4 声明方法2.5 插值表达式2.6 给任意属性绑定值2.7 v-for 循环数组或对象的使用2.8 v-if 和 v-show 控制是否显示2.9 计算属性和监听器属性2.10 过滤器属性3. 总结 Vue …

智慧工程安监物联网+云平台解决方案-最新全套文件

智慧工程安监物联网云平台解决方案-最新全套文件一、建设背景监管部门所处困境建筑施工业存在难点工程现场安全现象二、建设思路实现目标三、建设方案四、获取 - 物联网全套最新解决方案合集一、建设背景 智慧工地 是指运用 信息化 手段&#xff0c;通过 三维 设计平台对 工程…

Linux发行版---常用命令操作快速熟悉

针对linux发行版&#xff08;如ubuntu、raspian等&#xff09;的基础使用说明&#xff0c;以快速熟悉linux发行版的操作。 一、系统信息 查看处理器架构&#xff1a;arch查看内核版本&#xff1a;cat /proc/version; uname -a查看操作系统版本&#xff1a;head -n 1 /etc/iss…

c语言:初识结构体

初识结构体一.结构体声明1.结构体的概念2.声明二.结构体的基础使用三.结构体变量的定义和初始化一.结构体声明 1.结构体的概念 结构体是一些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量 这里与数组做出区分&#xff1a;数组是一组相同类型元…

上海 Meetup | 一键获取 11 大云原生热门开源项目技术分享入场券

活动介绍 微服务 x 容器开源开发者 Meetup 是由阿里云飞天 club 与云原生应用平台共同打造&#xff0c;面向一线开发者的技术交流活动&#xff0c;整体内容聚焦容器 & 微服务方向&#xff0c;旨在通过热门的开源技术、云原生在企业的应用实践案例、架构设计思维等&#xf…

CopyOnWriteArrayList 是如何保证线程安全的?

本文已收录到 AndroidFamily&#xff0c;技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 提问。 前言 大家好&#xff0c;我是小彭。 在上一篇文章里&#xff0c;我们聊到了ArrayList 的线程安全问题&#xff0c;其中提到了 CopyOnWriteArrayList 的解决方法。那么 CopyOn…

倒计时9天|Zabbix中国峰会15位重磅嘉宾抢先看!

2022Zabbix峰会演讲嘉宾 &#xff08;有奖互动&#xff1a;转发本文或任一讲师海报至朋友圈&#xff0c;保留5分钟&#xff0c;即可获得Zabbix定制周边礼品一份&#xff0c;仅限100份&#xff0c;先到先得&#xff0c;详情联系文末小Z) 第7届Zabbix中国峰会将于12月2-3日举行…

腾讯产品经理的自动化工作流

作为腾讯产品经理的一员&#xff0c;Johnny中扬每天需要面对来自各方繁琐的需求。如何管理好用户需求、并及时规划、完成、反馈&#xff0c;上周中扬和我们分享了他的工作流。如果你也是产品经理&#xff0c;或者对腾讯产品经理的工作日常比较感兴趣&#xff0c;错过了上次的直…

【数据结构】堆的实现

堆1.堆&#xff1a;一种二叉树2.堆的概念及结构3.堆的实现3.1 创建堆的结构3.2 堆的初始化3.3 堆的插入3.4 堆的向上调整法&#xff08;up&#xff09;3.5 打印堆的数据3.6 到这里就可以实现一个基本的堆了3.7 向下调整法down&#xff08;非常重要的一个方法&#xff09;3.8 最…

Java项目:JSP校园运动会管理系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 本项目包含三种角色&#xff1a;运动员、裁判员、管理员&#xff1b; 运动员角色包含以下功能&#xff1a; 运动员登录,个人信息修改,运动成绩…

【网络安全】——sql注入之奇淫巧技bypass(持续更新中)

作者名&#xff1a;Demo不是emo 主页面链接&#xff1a;主页传送门创作初心&#xff1a;舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座右…

微信点餐小程序开发_分享微信点餐小程序可以实现哪些功能

线下餐饮实体店都开始摸索发展网上订餐服务。最多人选择的是入驻外卖平台&#xff0c;但抽成高&#xff0c;推广还要另买流量等问题&#xff0c;也让不少商家入不敷出。在这种情况下&#xff0c;建立自己的微信订餐小程序&#xff0c;做自己的私域流量是另一种捷径。那么&#…

Redis关闭持久化

版本&#xff1a; 7.0.4 一、持久化说明 1、redis默认是开启持久化的 2、默认持久化方式为RDB 二、redis 关闭持久化 关闭 RDB 持久化 1、注释掉原来的持久化规则 # save 3600 1 300 100 60 10000或# save 3600 1 # save 300 100 # save 60 100002、把 save 节点设置为空 s…