Sentinel学习笔记(六)

Sentinel +InfluxDb 监控数据持久化

InfluxDb简单介
InfluxDB是一个开源分布式时序、事件和指标数据库。使用 Go 语言编写,无需外部依赖。
应用:性能监控,应用程序指标,物联网传感器数据和实时分析等的后端存储。

  • 强大的类SQL语法
  • -内置http支持,使用http读写
  • -基于事件:它支持任意的事件数据
  • -无结构(无模式):可以是任意数量的列
  • -可度量性:你可以实时对大量数据进行计算
  • 持续高并发写入、无更新、数据压缩存储、低查询延时
  • 支持min, max, sum, count, mean, median 等一系列函数
  • 基于时间序列,支持与时间有关的相关函数(如最大,最小,求和等)
    详细内容请参考一下链接
    https://jasper-zhang1.gitbooks.io/influxdb/content/
    进入正题
    1 sentinel-dashboard 添加influxBb依赖包以及简单配置
<dependency>
    <groupId>org.influxdb</groupId>
    <artifactId>influxdb-java</artifactId>
    <version>2.16</version>
</dependency>
<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>
spring.influx.url=http://localhost:8086
#spring.influx.user=root
#spring.influx.password=root

InfluxDb安装后默认账号密码都是root,(默认的情况可以不配置账号密码)
2 创建InfluxDbMetricEntity

@Measurement(name="${spring.influx.measurement:resources_metrics}", database = "${spring.influx.db:sentinel_log}")
public class InfluxDbMetricEntity {
//    @Column(name="id")
    private Long id;
    @Column(name="gmtCreate")
    private Long gmtCreate;
//    @Column(name="gmtModified")
    private Date gmtModified;
    @Column(name="app", tag = true)
    private String app;
    /**
     * 监控信息的时间戳
     */
    @TimeColumn
    @Column(name="time")
    private Instant time;
    @Column(name="resource", tag = true)
    private String resource;
    @Column(name="passQps")
    private Long passQps;
    @Column(name="successQps")
    private Long successQps;
    @Column(name="blockQps")
    private Long blockQps;
    @Column(name="exceptionQps")
    private Long exceptionQps;

    /**
     * summary rt of all success exit qps.
     */
    @Column(name="rt")
    private double rt;

    /**
     * 本次聚合的总条数
     */
    @Column(name="count")
    private int count;
//    @Column(name="resourceCode")
    private int resourceCode;

    public static InfluxDbMetricEntity copyOf(InfluxDbMetricEntity oldEntity) {
        InfluxDbMetricEntity entity = new InfluxDbMetricEntity();
        entity.setId(oldEntity.getId());
        entity.setGmtCreate(oldEntity.getGmtCreate());
        entity.setGmtModified(oldEntity.getGmtModified());
        entity.setApp(oldEntity.getApp());
        entity.setTime(oldEntity.getTime());
        entity.setResource(oldEntity.getResource());
        entity.setPassQps(oldEntity.getPassQps());
        entity.setBlockQps(oldEntity.getBlockQps());
        entity.setSuccessQps(oldEntity.getSuccessQps());
        entity.setExceptionQps(oldEntity.getExceptionQps());
        entity.setRt(oldEntity.getRt());
        entity.setCount(oldEntity.getCount());
        entity.setResource(oldEntity.getResource());
        return entity;
    }

    public synchronized void addPassQps(Long passQps) {
        this.passQps += passQps;
    }

    public synchronized void addBlockQps(Long blockQps) {
        this.blockQps += blockQps;
    }

    public synchronized void addExceptionQps(Long exceptionQps) {
        this.exceptionQps += exceptionQps;
    }

    public synchronized void addCount(int count) {
        this.count += count;
    }

    public synchronized void addRtAndSuccessQps(double avgRt, Long successQps) {
        this.rt += avgRt * successQps;
        this.successQps += successQps;
    }

    /**
     * {@link #rt} = {@code avgRt * successQps}
     *
     * @param avgRt      average rt of {@code successQps}
     * @param successQps
     */
    public synchronized void setRtAndSuccessQps(double avgRt, Long successQps) {
        this.rt = avgRt * successQps;
        this.successQps = successQps;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getGmtCreate() {
        return gmtCreate;
    }

    public void setGmtCreate(Long gmtCreate) {
        this.gmtCreate = gmtCreate;
    }

    public Date getGmtModified() {
        return gmtModified;
    }

    public void setGmtModified(Date gmtModified) {
        this.gmtModified = gmtModified;
    }

    public String getApp() {
        return app;
    }

    public void setApp(String app) {
        this.app = app;
    }

    public Instant getTime() {
        return time;
    }

    public void setTime(Instant time) {
        this.time = time;
    }

    public String getResource() {
        return resource;
    }

    public void setResource(String resource) {
        this.resource = resource;
        this.resourceCode = resource.hashCode();
    }

    public Long getPassQps() {
        return passQps;
    }

    public void setPassQps(Long passQps) {
        this.passQps = passQps;
    }

    public Long getBlockQps() {
        return blockQps;
    }

    public void setBlockQps(Long blockQps) {
        this.blockQps = blockQps;
    }

    public Long getExceptionQps() {
        return exceptionQps;
    }

    public void setExceptionQps(Long exceptionQps) {
        this.exceptionQps = exceptionQps;
    }

    public double getRt() {
        return rt;
    }

    public void setRt(double rt) {
        this.rt = rt;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public int getResourceCode() {
        return resourceCode;
    }

    public Long getSuccessQps() {
        return successQps;
    }

    public void setSuccessQps(Long successQps) {
        this.successQps = successQps;
    }

    @Override
    public String toString() {
        return "MetricEntity{" +
            "id=" + id +
            ", gmtCreate=" + gmtCreate +
            ", gmtModified=" + gmtModified +
            ", app='" + app + '\'' +
            ", time=" + time +
            ", resource='" + resource + '\'' +
            ", passQps=" + passQps +
            ", blockQps=" + blockQps +
            ", successQps=" + successQps +
            ", exceptionQps=" + exceptionQps +
            ", rt=" + rt +
            ", count=" + count +
            ", resourceCode=" + resourceCode +
            '}';
    }

    /**
     * 将metric实体类转为InfluxDb实体写入时序库
     * @param oldEntity
     * @return
     */
    public static InfluxDbMetricEntity convert(MetricEntity oldEntity) {
        InfluxDbMetricEntity entity = new InfluxDbMetricEntity();
        entity.setId(oldEntity.getId());
        entity.setGmtCreate(oldEntity.getGmtCreate().getTime());
        entity.setGmtModified(oldEntity.getGmtModified());
        entity.setApp(oldEntity.getApp());
        entity.setTime(oldEntity.getTimestamp().toInstant());
        entity.setResource(oldEntity.getResource());
        entity.setPassQps(oldEntity.getPassQps());
        entity.setBlockQps(oldEntity.getBlockQps());
        entity.setSuccessQps(oldEntity.getSuccessQps());
        entity.setExceptionQps(oldEntity.getExceptionQps());
        entity.setRt(oldEntity.getRt());
        entity.setCount(oldEntity.getCount());
        entity.setResource(oldEntity.getResource());
        return entity;
    }

    /**
     * 将InfluxDb实体类转为metric实体读取到控制台
     * @return
     */
    public MetricEntity toMetricEntity() {
        MetricEntity entity = new MetricEntity();
        entity.setId(this.getId());
        entity.setGmtCreate(new Date(this.getGmtCreate()));
        entity.setGmtModified(this.getGmtModified());
        entity.setApp(this.getApp());
        entity.setTimestamp(new Date(this.getTime().toEpochMilli()));
        entity.setResource(this.getResource());
        entity.setPassQps(this.getPassQps());
        entity.setBlockQps(this.getBlockQps());
        entity.setSuccessQps(this.getSuccessQps());
        entity.setExceptionQps(this.getExceptionQps());
        entity.setRt(this.getRt());
        entity.setCount(this.getCount());
        entity.setResource(this.getResource());
        return entity;
    }
}

3 创建InfluxDbMetricsRepository 实现MetricsRepository, InitializingBean

/**
 * 实现MetricsRepository将InfluxDb定义为存储库
 * 实现InitializingBean运用spring的自动装配
 * @author tom
 */
@Repository
public class InfluxDbMetricsRepository implements MetricsRepository<MetricEntity>, InitializingBean {

    private static final Logger log = LoggerFactory.getLogger(InfluxDbMetricsRepository.class);
    private InfluxDB influxDB;
    private String database;
    private String measurement;
    private InfluxDBResultMapper resultMapper = new InfluxDBResultMapper();

    public InfluxDbMetricsRepository(InfluxDB influxDB, @Value("${spring.influx.db:sentinel_log}") String database
            , @Value("${spring.influx.measurement:resources_metrics}") String measurement) {
        this.influxDB = influxDB;
        this.database = database;
        this.measurement = measurement;
    }

    @Override
    public void save(MetricEntity metric) {
        try {
            Point.Builder builder = Point.measurement(measurement);
            builder.addFieldsFromPOJO(InfluxDbMetricEntity.convert(metric));
            influxDB.write(builder.build());
            log.debug("metric save => {}", metric);
        } catch (Exception e) {
            log.error("metric save error", e);
        }
    }

    @Override
    public void saveAll(Iterable<MetricEntity> metrics) {
        try {
            Iterator<MetricEntity> iter = metrics.iterator();
            while (iter.hasNext()) {
                influxDB.write(Point.measurement(measurement).addFieldsFromPOJO(InfluxDbMetricEntity.convert(iter.next())).build());
            }
            influxDB.flush();
            log.debug("metric saveAll => {}", metrics);
        } catch (Exception e) {
            log.error("metric saveAll error", e);
        }
    }

    @Override
    public List<MetricEntity> queryByAppAndResourceBetween(String app, String resource, long startTime, long endTime) {
        //注意string参数必须用单引号标注!!!! 并且双引号不行!不加也不行!
        QueryResult result = influxDB.query(new Query(String.format("select * from %s where app='%s' and resource='%s' and gmtCreate >= %s and gmtCreate <= %s",
                this.measurement, app, resource, startTime, endTime)));
        log.debug("metric queryByAppAndResourceBetween => {}", result);
        List<InfluxDbMetricEntity> list = this.resultMapper.toPOJO(result, InfluxDbMetricEntity.class, this.measurement);
        return list.stream().map(m -> m.toMetricEntity()).collect(Collectors.toList());
    }

    @Override
    public List<String> listResourcesOfApp(String app) {
        long period = System.currentTimeMillis() - 1000 * 60 * 15;
        QueryResult result = influxDB.query(new Query(String.format("select * from %s where app = '%s' and gmtCreate > %s"
                , this.measurement, app, period)));
        log.debug("metric listResourcesOfApp => {}", result);
        List<InfluxDbMetricEntity> rs = this.resultMapper.toPOJO(result, InfluxDbMetricEntity.class, this.measurement);
        if (CollectionUtils.isEmpty(rs)) {
            return Lists.newArrayList();
        }
        Map<String, InfluxDbMetricEntity> resourceCount = new HashMap<>(32);
        for (InfluxDbMetricEntity metricEntity : rs) {
            String resource = metricEntity.getResource();
            if (resourceCount.containsKey(resource)) {
                InfluxDbMetricEntity oldEntity = resourceCount.get(resource);
                oldEntity.addPassQps(metricEntity.getPassQps());
                oldEntity.addRtAndSuccessQps(metricEntity.getRt(), metricEntity.getSuccessQps());
                oldEntity.addBlockQps(metricEntity.getBlockQps());
                oldEntity.addExceptionQps(metricEntity.getExceptionQps());
                oldEntity.addCount(1);
            } else {
                resourceCount.put(resource, InfluxDbMetricEntity.copyOf(metricEntity));
            }
        }
        return resourceCount.entrySet()
                .stream()
                .sorted((o1, o2) -> {
                    InfluxDbMetricEntity e1 = o1.getValue();
                    InfluxDbMetricEntity e2 = o2.getValue();
                    int t = e2.getBlockQps().compareTo(e1.getBlockQps());
                    if (t != 0) {
                        return t;
                    }
                    return e2.getPassQps().compareTo(e1.getPassQps());
                })
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
    }

    /**
     *  bean初始化时
     *  自动创建数据库以及measourement
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.hasLength(this.database, "influxDB database invalid!");
        Assert.hasLength(this.measurement, "influxDB measurement invalid!");

        QueryResult rs = this.influxDB.query(new Query("show databases"));
        log.debug("influxDB database check => {}", rs);
        if (rs.hasError()) {
            throw new InfluxDBException(rs.getError());
        }
        if (databaseNotExist(rs)) {
            rs = this.influxDB.query(new Query("create database " + this.database));
            log.info("create influxDB database => {} result => {}", this.database, rs);
        }

        this.influxDB.setDatabase(this.database);
        this.influxDB.enableBatch();
        log.info("influxDB setDatabase => {}", this.database);
    }

    private boolean databaseNotExist(QueryResult rs) {
        return !rs.getResults().get(0).getSeries().get(0).getValues()
                .stream().flatMap(list -> list.stream()).anyMatch(d -> d.toString().equals(this.database));
    }
}

4 在MetricController注入influxDbMetricsRepository

@Autowired
@Qualifier("influxDbMetricsRepository")
private MetricsRepository<MetricEntity> metricStore;

完成以上操作就可以将监控数据持久化到InfluxDb中啦,监控数据,结合grafana或者Chronograf可以将监控数据做成炫酷的图表展示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值