# aliyun-log-producer-java
**Repository Path**: mirrors_aliyun/aliyun-log-producer-java
## Basic Information
- **Project Name**: aliyun-log-producer-java
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-08-08
- **Last Updated**: 2025-11-01
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Aliyun LOG Java Producer(废弃)
[](https://travis-ci.org/aliyun/aliyun-log-producer-java)
[](/LICENSE)
[README in English](/README.md)
该项目已不再维护,请使用新版 [Aliyun LOG Java Producer](https://github.com/aliyun/aliyun-log-producer)。
## 功能特点
* 提供异步的发送接口,线程安全。
* 可以添加多个Project的配置。
* 用于发送的网络 I/O 线程数量可以配置。
* merge成的包的日志数量以及大小都可以配置。
* 内存使用可控,当内存使用达到用户配置的阈值时,Producer 的 send 接口会阻塞,直到有空闲的内存可用。
## 功能优势
* 客户端日志不落盘:既数据产生后直接通过网络发往服务端。
* 客户端高并发写入:例如一秒钟会有百次以上写操作。
* 客户端计算与 I/O 逻辑分离:打印日志不影响计算耗时。
在以上场景中,Aliyun LOG Java Producer 会简化您程序开发的步骤,您无需关心日志采集细节实现、也不用担心日志采集会影响您的业务正常运行,大大降低数据采集门槛。

以上各种接入方式的对比:
| 接入方式 |
优点/缺点 |
针对场景 |
| 日志落盘 + Logtail |
日志收集与打日志解耦,无需修改代码 |
常用场景 |
| syslog + Logtail |
性能较好(80MB/S),日志不落盘,需支持 syslog 协议 |
syslog 场景 |
| SDK 直发 |
不落盘,直接发往服务端,需要处理好网络 IO 与程序 IO 之间的切换 |
日志不落盘 |
| Aliyun LOG Java Producer |
不落盘,异步合并发送服务端,吞吐量较好 |
日志不落盘,客户端 QPS 高 |
## 配置步骤
Aliyun LOG Java Producer 配置分为以下几个步骤:
### 1. maven 工程中引入依赖
```
com.google.protobuf
protobuf-java
2.5.0
com.aliyun.openservices
aliyun-log
0.6.27
com.aliyun.openservices
log-loghub-producer
0.1.16
```
### 2. 程序中配置 ProducerConfig
配置格式如下,参数取值见本文档中参数取值部分。
```
public class ProducerConfig {
//被缓存起来的日志的发送超时时间,如果缓存超时,则会被立即发送,单位是毫秒
public int packageTimeoutInMS = 3000;
//每个缓存的日志包中包含日志数量的最大值,不能超过4096
public int logsCountPerPackage = 4096;
//每个缓存的日志包的大小的上限,不能超过3MB,单位是字节
public int logsBytesPerPackage = 3 * 1024 * 1024;
//单个producer实例可以使用的内存的上限,单位是字节
public int memPoolSizeInByte = 100 * 1024 * 1024;
//当指定以shardhash的方式发送日志时,这个参数需要被设置,否则不需要关心。后端merge线程会将映射到同一个shard的数据merge在一起,而shard关联的是一个hash区间,
//producer在处理时会将用户传入的hash映射成shard关联hash区间的最小值。每一个shard关联的hash区间,producer会定时从loghub拉取,该参数的含义是每隔shardHashUpdateIntervalInMS毫秒,
//更新一次shard的hash区间。
public int shardHashUpdateIntervalInMS = 10 * 60 * 1000;
//如果发送失败,重试的次数,如果超过该值,就会将异常作为callback的参数,交由用户处理。默认 10 次,重试时间间隔采用指数退避算法,即第一次间隔 1 秒,第二次 2 秒,第三次 4 秒,最长间隔为 512 秒。重试 10 次总耗时 1023 秒。
public int retryTimes = 10;
//protobuf
public String logsFormat = "protobuf";
//IO线程池最大线程数量
public int maxIOThreadSizeInPool = 8;
//userAgent
public String userAgent = "loghub-producer-java";
}
```
### 3. 继承 ILogCallback
使用 callback 主要为了处理日志发送的结果,结果包括发送成功和发生异常。您也可以选择不处理,这样就不需要继承 ILogCallback。
## 参数说明
| 参数 |
参数说明 |
取值 |
| packageTimeoutInMS |
指定被缓存日志的发送超时时间,如果缓存超时,则会被立即发送。 |
整数形式,单位为毫秒。 |
| logsCountPerPackage |
指定每个缓存的日志包中包含日志数量的最大值。 |
整数形式,取值为1~4096。 |
| logsBytesPerPackage |
指定每个缓存的日志包的大小上限。 |
整数形式,取值为1~3145728(3M),单位为字节。 |
| memPoolSizeInByte |
指定单个Producer实例可以使用的内存的上限。 |
整数形式,单位为字节。 |
| maxIOThreadSizeInPool |
指定I/O线程池最大线程数量,主要用于发送数据到日志服务。 |
整数形式。 |
| shardHashUpdateIntervalInMS |
指定更新Shard的Hash区间的时间间隔,当指定shardhash的方式发送日志时,需要设置此参数。 后端merge线程会将映射到同一个Shard的数据merge在一起,而Shard关联的是一个Hash区间,Producer在处理时会将用户传入的Hash映射成Shard关联Hash区间的最小值。每一个Shard关联的Hash区间,Producer会定时从LogHub拉取。 |
整数形式。 |
| retryTimes |
如果发送失败,重试的次数,如果超过该值,就会将异常作为callback的参数,交由用户处理。默认 10 次,重试时间间隔采用指数退避算法,即第一次间隔 1 秒,第二次 2 秒,第三次 4 秒,最长间隔为 512 秒。重试 10 次总耗时 1023 秒。您可以通过调整重试次数,控制重试总耗时。
|
整数形式。 |
## 使用实例
项目中提供了名为`ProducerSample`和`CallbackSample`的实例。
[ProducerSample.java](/src/main/java/com/aliyun/openservices/log/producer/sample/ProducerSample.java)
[CallbackSample.java](/src/main/java/com/aliyun/openservices/log/producer/sample/CallbackSample.java)
## 权限控制
想要通过 Aliyun LOG Java Producer 向 logstore 中写入数据,需要为使用的账号设置如下权限,设置方法请参考[RAM文档](https://help.aliyun.com/document_detail/57445.html):
| Action |
Resource |
| log:PostLogStoreLogs |
acs:log:${regionName}:${projectOwnerAliUid}:project/${projectName}/logstore/${logstoreName} |
## 错误诊断
如果您发现数据没有写入日志服务,可通过如下步骤进行错误诊断。
1. 检查您项目中引入的 protobuf-java,aliyun-log,log-loghub-producer 这三个 jar 包的版本是否和文档中`maven 工程中引入依赖`部分列出的 jar 包版本一致。
2. 继承 ILogCallback 类,查看 onCompletion 方法的参数:PutLogsResponse respone,LogException e。后台线程在尝试发送数据后,不论成功或失败,都会回调该方法,通过查看上述参数您可以获得数据发送失败的原因。
```
static private class TestCallback extends ILogCallback {
@Override
public void onCompletion(PutLogsResponse response, LogException e) {
System.out.println(response);
System.out.println(e);
}
}
```
3. 如果您发现并没有回调 ILogCallback 的 onCompletion 方法,请检查在您的程序退出之前是否有调用 producer.flush() 和 producer.close() 方法。因为数据发送是由后台线程异步完成的,为了防止缓存在内存里的少量数据丢失,建议您在程序退出之前务必调用 producer.flush() 和 producer.close() 方法。
4. log-loghub-producer 会把运行过程中的关键行为日志通过 slf4j 进行输出,您可以在程序中配置好相应的日志实现框架,打开 DEBUG 级别的日志,观察 log-loghub-producer。
5. 如果通过上述步骤仍然没有解决您的问题请联系我们。
## 常见问题
**Q**: Aliyun LOG Java Producer 依赖 Aliyun LOG Java SDK,而 Aliyun LOG Java SDK 依赖了 2.5.0 版本的 protobuf 库,如果该版本的 protobuf 与用户应用程序中自身带的 protobuf 库冲突怎么办?
**A**: 可以使用 Aliyun LOG Java SDK 提供的一个特殊版本,maven 配置如下:
```
com.aliyun.openservices
aliyun-log
0.6.24
jar-with-dependencies
com.google.protobuf
protobuf-java
com.aliyun.openservices
log-loghub-producer
0.1.16
com.google.protobuf
protobuf-java
com.aliyun.openservices
aliyun-log
```
**Q**: 何时调用 producer 的 `flush()` 方法和 `close()` 方法?
**A**:进程在运行过程中一般不需要用户主动调用 `flush()` 方法,后台线程会按一定的策略异步地将数据写往日志服务。只有当进程将要退出之前,需要用户依次调用 `flush()` 方法和 `close()` 方法,以防止缓存在内存中的数据丢失。
**A**: 一个 producer 实例所创建的线程情况如下
**Q**: 使用 producer 向 log service 写数据,PutLogsResponse 返回如下错误信息:error:PostBodyInvalid, upload data time must greater than 0 。
**A**: 某个被发送的 LogItem 的 mLogTime 属性被设置成了0。
**Q**: 如何运行 unit test?
**A**: 编辑文件 `.test_env_rc`,填写 project1、endpoint1 等值,然后运行下列命令
```
source .test_env_rc
mvn clean test
```
**Q**: 如果写入数据的时候不想指定 topic,调用 `send()` 方法时 topic 该如何指?
**A**: 不要将 topic 设成 null,而是设置成 ""。
**Q**: `send()` 接口中 shardHash 的作用?
**A**: 一个 logstore 包含多个 shard。shardHash 决定了这个 logItem 应该位于哪个 shard 上。
https://help.aliyun.com/document_detail/28976.html
**Q**: 一个 producer 实例,会额外创建哪些线程?
**A**: 一个 producer 实例所创建的线程情况如下
| 线程类型 |
线程名格式 |
数量 |
描述 |
| ControlThread |
log-producer-control-worker-{N} |
2 |
1. 用于将超时 package 提交到内部阻塞队列。2. 用于控制 shardHash 更新时间。 |
| IOThread |
log-producer-io-thread |
1 |
从阻塞队列中获取数据然后提交至内部线程池。 |
| IOWorkerThread |
log-producer-io-worker-{N} |
最多 ProducerConfig.maxIOThreadSizeInPool 个 |
线程池中真正用来发送数据的线程。 |
**Q**: 一个进程需要创建多少个 producer?
**A**: producer 的方法是线程安全的,一般情况一个进程的所有线程共用一个 producer。
**Q**:写数据时,服务端返回如下错误 aliyun.openservices.log.exception.LogException: Write quota exceed: qps: 517?
**A**:超过了 project 写入次数的限制(默认情况下,每个 project 每分钟最多允许60万次写入),说明您的一个 package 所包含的 logItem 过少,检查 packageTimeoutInMS、 logsCountPerPackage 等参数是否设置过低。
**Q**:手动分裂 shard 后,原来 shard 变成只读了,需要重启写入程序吗?
**A**:不需要。服务端会自动将待写入的数据路由到新分裂出来的两个可写的 shard 上。
**Q**:producer 会缓存待发送的数据,并将数据合并成 package 后批量发往服务端。什么样的数据有机会合并在相同的 package 里?
**A**:有相同 project,logStore,topic,shardHash,source 的数据会被合并在一起。
**Q**:producer 在网络发生异常的情况下会如何处理待发送的数据?
**A**:在 0.1.17 及之后的版本中,producer 会在遇到`RequestError`、`Unauthorized`、`WriteQuotaExceed`、`InternalServerError`、`ServerBusy`这些错误时进行重试,最多重试`retryTimes`次,若仍没有成功,会将异常信息作为参数传递给用户定义的回调函数。重试的时间间隔由 1 秒开始指数递增,最大为 512 秒。如果您使用默认的`retryTimes`,在遇到上述错误后最多重试 1023 秒。建议您不要在 callback 里不要进行重试,将重试的任务交给 producer 处理,因为在 callback 里重试可能导致死锁。
**Q**:producer 能否保证日志上传顺序?即先发送的日志排先写入服务端?
**A**:producer 异步多线程发送顺序,无法保证日志上传顺序。
**Q**:producer 支持通过 HTTPS 发送日志吗?
**A**:支持。将`ProjectConfig.endpoint`设置成`https://`即可。
**Q**:日志写入失败,错误信息为 `InvalidLogSize, logItems' length exceeds maximum limitation : 40960 lines, ...`?
**A**:在 `0.1.13` 及之前版本如果您调用 send() 方法时传入的 logItems 过长(超过了 40960 条),producer 又不会对原始 logItems 切割,导致抛出该异常。为了解决该问题,您可以将 producer 升级到 `0.1.14` 版本,如果您无法升级 producer 版本,需要您在调用 send() 接口前控制 logItems 长度。
## Aliyun LOG Java SDK
若 producer 提供的接口满足不了您的日志采集需求,您可以基于 [Aliyun Log Java SDK](https://github.com/aliyun/aliyun-log-java-sdk),开发适合您的应用场景的日志采集API。
## 联系我们
- [阿里云LOG官方网站](https://www.aliyun.com/product/sls/)
- [阿里云LOG官方论坛](https://yq.aliyun.com/groups/50)
- 阿里云官方技术支持:[提交工单](https://workorder.console.aliyun.com/#/ticket/createIndex)
## 贡献者
[@zzboy](https://github.com/zzboy)对项目作了很大贡献。
感谢[@zzboy](https://github.com/zzboy)的杰出工作。