spring components actuator (1): usages

查看可以看哪些信息:

http://localhost:8080/actuator

{
“_links”: {
“self”: {
“href”: “http://localhost:8080/actuator”,
“templated”: false
},
“health”: {
“href”: “http://localhost:8080/actuator/health”,
“templated”: false
},
“health-path”: {
“href”: “http://localhost:8080/actuator/health/{*path}”,
“templated”: true
}
}
}

完整的可以参考:
https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints

提供哪些,需要配置:
management:
endpoints:
web:
exposure:
include: info,health,prometheus

配置了include,则需要显式显示配置所有的。例如,之前提到的默认的health也需要配置下,否则访问404

Health check的返回和常见配置:

http://localhost:8080/actuator/health

{“status”:”UP”}

Metrics:

查看可以看哪些:

http://localhost:8080/actuator/metrics/http.server.requests

{
“names”: [
“http.server.requests”,
“jvm.buffer.count”,
“jvm.buffer.memory.used”,
“jvm.buffer.total.capacity”,
“jvm.classes.loaded”,
“jvm.classes.unloaded”,
“jvm.gc.live.data.size”,
“jvm.gc.max.data.size”,
“jvm.gc.memory.allocated”,
“jvm.gc.memory.promoted”,
“jvm.gc.pause”,
“jvm.memory.committed”,
“jvm.memory.max”,
“jvm.memory.used”,
“jvm.threads.daemon”,
“jvm.threads.live”,
“jvm.threads.peak”,
“jvm.threads.states”,
“logback.events”,
“process.cpu.usage”,
“process.start.time”,
“process.uptime”,
“system.cpu.count”,
“system.cpu.usage”,
“tomcat.sessions.active.current”,
“tomcat.sessions.active.max”,
“tomcat.sessions.alive.max”,
“tomcat.sessions.created”,
“tomcat.sessions.expired”,
“tomcat.sessions.rejected”
]
}

具体某项查看:

http://localhost:8080/actuator/metrics/http.server.requests

{
“name”: “http.server.requests”,
“description”: null,
“baseUnit”: “seconds”,
“measurements”: [
{
“statistic”: “COUNT”,
“value”: 84.0
},
{
“statistic”: “TOTAL_TIME”,
“value”: 0.33151280000000005
},
{
“statistic”: “MAX”,
“value”: 0.024693
}
],
“availableTags”: [
{
“tag”: “exception”,
“values”: [
“None”
]
},
{
“tag”: “method”,
“values”: [
“GET”
]
},
{
“tag”: “uri”,
“values”: [
“/actuator/health”,
“/actuator”,
“/actuator/metrics”,
“/**”
]
},
{
“tag”: “outcome”,
“values”: [
“CLIENT_ERROR”,
“SUCCESS”
]
},
{
“tag”: “status”,
“values”: [
“404”,
“200”
]
}
]
}

输出metric:

management.metrics.export.influx.uri=https://influx.example.com:8086

参考https://emacsist.github.io/2018/08/07/springboot%E7%BB%93%E5%90%88influxdb%E6%94%B6%E9%9B%86%E7%9B%91%E6%8E%A7%E7%BB%9F%E8%AE%A1%E4%BF%A1%E6%81%AF/

logger:

http://localhost:8080/actuator/loggers 获取所有log配置
http://localhost:8080/actuator/loggers/{name} 获取某个logger,例如root

发送一个POST请求到http://localhost:8080/actuator/loggers/root,加入如下参数

{
“configuredLevel”: “DEBUG”
}

这个功能对于线上问题的排查非常有用。

一些有用的文档:https://docs.spring.io/spring-boot/docs/2.5.3/actuator-api/pdf/spring-boot-actuator-web-api.pdf

dynamodb analyst (1)- how to implement “part” update

设置一个attribute为null(或有时候没有设置)时,保存数据(org.springframework.data.repository.CrudRepository#save)的执行行为:

一般情况下,会走入下面的分支:

com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.SaveObjectHandler#onNullNonKeyAttribute


@Override
protected void onNullNonKeyAttribute(String attributeName) {
/*
* If UPDATE_SKIP_NULL_ATTRIBUTES or APPEND_SET is
* configured, we don't delete null value attributes.
*/
if (getLocalSaveBehavior() == SaveBehavior.UPDATE_SKIP_NULL_ATTRIBUTES
|| getLocalSaveBehavior() == SaveBehavior.APPEND_SET) {
return;
}

else {
/* Delete attributes that are set as null in the object. */
getAttributeValueUpdates()
.put(attributeName,
new AttributeValueUpdate()
.withAction("DELETE"));
}
}

因为默认保存行为为:SaveBehavior.UPDATE.所以其实会删掉对应的attribute的值,而不是不管之前attribute是否有值,从这点看,试图通过部分attribute设置非Null值、部分attribute设置Null来达到“部分”(patch)更新是做不到的。

仔细查阅上面代码,反过来说明只要修改默认保存行为为UPDATE_SKIP_NULL_ATTRIBUTES,就可以忽略Null值。

副作用:假设一个值之前有值,后来想改成Null,那就实现不了了。所以如果使用UPDATE_SKIP_NULL_ATTRIBUTES,用户场景不能有这种。

实际上,在不修改默认保存方法的情况下,还有另外一种实现“部分”更新的方法,就是提供另外一个专门的entity对象,去除不想更新的attributes。这样也可以实现部分更新。

另外要注意批量Save其实是直接覆盖:

批量save:

com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#batchWrite

本质上用的是PUT:

for ( Object toWrite : objectsToWrite ) { 

//*******

requestItems.add(tableName, new WriteRequest(new PutRequest(transformAttributes(parameters))));
}

而普通的save:
com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper#save

默认用的不是PUT.


        boolean usePut = (finalConfig.getSaveBehavior() == SaveBehavior.CLOBBER
                         || finalConfig.getSaveBehavior() == SaveBehavior.PUT)
                         || anyKeyGeneratable(model, object, finalConfig.getSaveBehavior());

        SaveObjectHandler saveObjectHandler;

        if (usePut) {
              //默认不走入这个分支。


所以:
BATCH SAVE其实是直接覆盖,SAVE可以选择直接覆盖还是部分更新(Update)。个人觉得这个行为不好,不一致。
追根溯源: 批量BatchWriteItemRequest是com.amazonaws.services.dynamodbv2.model.WriteRequest的批量,这个类只接受PUT和DELETE两种Request作为构造器参数。

   public WriteRequest(PutRequest putRequest) {
        setPutRequest(putRequest);
    }

   public WriteRequest(DeleteRequest deleteRequest) {
        setDeleteRequest(deleteRequest);
   }