chicc999 / iris

High performance message queue

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 4195328: 1936289140 - discarded

small-carbon opened this issue · comments

20:46:41.135 [IoLoopGroup - 1] [DefaultConnectionHandler.java:63] ERROR com.cy.iris.commons.network.handler.DefaultConnectionHandler - Adjusted frame length exc eeds 4195328: 1936289140 - discarded io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 4195328: 1936289140 - discarded at io.netty.handler.codec.LengthFieldBasedFrameDecoder.fail(LengthFieldBasedFrameDecoder.java:499) ~[netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.handler.codec.LengthFieldBasedFrameDecoder.failIfNecessary(LengthFieldBasedFrameDecoder.java:477) ~[netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:403) ~[netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:343) ~[netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411) ~[netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248) ~[netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:373) [netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359) [netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:351) [netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334) [netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:373) [netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359) [netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926) [netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129) [netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:651) [netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:574) [netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:488) [netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:450) [netty-all-4.1.6.Final.jar:4.1.6.Final] at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873) [netty-all-4.1.6.Final.jar:4.1.6.Final] at java.lang.Thread.run(Thread.java:662) [na:1.6.0_45] 20:46:43.946 [IoLoopGroup - 1] [DefaultConnectionHandler.java:40] DEBUG com.cy.iris.commons.network.handler.DefaultConnectionHandler - 连接 [id: 0xddf6b808, L:nul l ! R:/127.0.0.1:63146] 断开

本系统支持的最大数据包请设置nettyConfig的frameMaxSize参数,默认4 * 1024 * 1024+1024。建议实际应用中经常出现2M以上的数据包,应该重新设计通信协议,支持流式接收,数据包应用层做分包(chunk)处理。

我是通过c++来发送的socket通讯
`
#include <windows.h>
#include <winsock.h>
#include

using namespace std;

#pragma comment(lib, "wsock32.lib")

#define CS_ERROR 1
#define CS_OK 0

void sError(char*);

int main()
{

WORD version;
WSADATA wsaData;
int rVal=0;

version = MAKEWORD(1,1);

WSAStartup(version,(LPWSADATA)&wsaData);

LPHOSTENT hostEntry;

//store information about the server
hostEntry = gethostbyname("127.0.0.1");

if(!hostEntry)
{
	sError("Failed gethostbyname()");
	//WSACleanup();
	return CS_ERROR;
}

//create the socket
SOCKET theSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

if(theSocket == SOCKET_ERROR)
{
	sError("Failed socket()");
	return CS_ERROR;
}

//Fill in the sockaddr_in struct
SOCKADDR_IN serverInfo;

serverInfo.sin_family = PF_INET;
serverInfo.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list);

serverInfo.sin_port = htons(50088);

rVal=connect(theSocket,(LPSOCKADDR)&serverInfo, sizeof(serverInfo));
if(rVal==SOCKET_ERROR)
{
	sError("Failed connect()");
	return CS_ERROR;
}

char *buf = "simple";
char* message = "3";

rVal = send(theSocket, message, strlen(message), 0);

if(rVal == SOCKET_ERROR)
{
	sError("Failed send()");
	return CS_ERROR;
}


closesocket(theSocket);
cout << "closing client"<< endl;
WSACleanup();

return CS_OK;

}

void sError(char *str)
{
MessageBox(NULL, str, "SOCKET ERROR", MB_OK);
WSACleanup();
}
`

1.严格按照协议来传输 2.必须使用大端序

frameMaxSize 属性似乎没有地方进行设置过

通过定义protobuf来实现对象传输,符合“通信协议格式”进行传输

// See README.txt for information and build instructions.

package tutorial;

option java_package = "com.cy.iris.commons.network.protobuf";
option java_outer_classname = "GetClusterMessage";

enum HeaderType {
    REQUEST = 0;
    RESPONSE = 1;
    MESSAGE = 2;                   // Used for messages which are signed but opaque
    CONFIG = 3;                    // Used for messages which express the channel config
    CONFIG_UPDATE = 4;             // Used for transactions which update the channel config
}

// These status codes are intended to resemble selected HTTP status codes
enum Status {
    UNKNOWN = 0;
    SUCCESS = 200;
    BAD_REQUEST = 400;
    FORBIDDEN = 403;
    NOT_FOUND = 404;
    REQUEST_ENTITY_TOO_LARGE = 413;
    INTERNAL_SERVER_ERROR = 500;
    SERVICE_UNAVAILABLE = 503;
	// 发送消息
	PUT_MESSAGE = 1;
	// 取消息
	GET_MESSAGE = 2;
	// 取消息应答
	GET_MESSAGE_ACK = 102;
	// 消费应答消息
	ACK_MESSAGE = 3;
	// 重试消息
	RETRY_MESSAGE = 4;
	// 存放重试消息
	PUT_RETRY = 5;
	// 获取重试消息
	GET_RETRY = 6;
	// 获取重试消息应答
	GET_RETRY_ACK = 106;
	// 更新重试消息
	UPDATE_RETRY = 7;
	// 获取重试条数
	GET_RETRY_COUNT = 8;
	// 获取重试条数应答
	GET_RETRY_COUNT_ACK = 108;
	// 事务准备
	PREPARE = 10;
	// 事务提交
	COMMIT = 11;
	// 事务回滚
	ROLLBACK = 12;
	// 心跳
	HEARTBEAT = 30;
	// 获取集群
	GET_CLUSTER = 31;
	// 获取集群应答
	GET_CLUSTER_ACK = 131;
	// 获取生产健康状况
	GET_PRODUCER_HEALTH = 32;
	// 获取消费健康状况
	GET_CONSUMER_HEALTH = 37;
	// 增加连接
	ADD_CONNECTION = 33;
	// 删除连接
	REMOVE_CONNECTION = 133;
	// 增加生产者
	ADD_PRODUCER = 34;
	// 增加生产者
	REMOVE_PRODUCER = 134;
	// 删除消费者
	ADD_CONSUMER = 35;
	// 删除消费者
	REMOVE_CONSUMER = 135;
	// 客户端性能
	CLIENT_PROFILE = 36;
	// 客户端性能应答
	CLIENT_PROFILE_ACK = 136;
	// 复制身份
	IDENTITY = 50;
	// 获取复制偏移量
	GET_OFFSET = 51;
	// 获取复制偏移量应答
	GET_OFFSET_ACK = 151;
	// 获取复制日志
	GET_JOURNAL = 52;
	// 获取复制日志应答
	GET_JOURNAL_ACK = 152;
	// 复制日志
	UPDATE_JOURNAL = 53;
	// 复制日志应答
	UPDATE_JOURNAL_ACK = 153;
	// Slave在线命令
	ONLINE = 54;
	// 投票选举master
	VOTE = 55;
	// 复制同步方式
	UPDATE_SYNC_MODE = 56;
	// 复制增量命令
	INCREMENTAL = 57;
	// 复制增量应答
	INCREMENTAL_ACK = 157;
	// 同步消费位置
	GET_CONSUMER_OFFSET = 58;
	// 同步消费位置确认
	GET_CONSUMER_OFFSET_ACK = 158;
	// 获取checksum
	GET_CHECKSUM = 60;
	// 获取checksum应答
	GET_CHECKSUM_ACK = 160;
	// 获取chunk
	GET_CHUNK = 61;
	// 获取chunk的应答
	GET_CHUNK_ACK = 161;
	// 获取元数据
	GET_META_DATA = 62;
	// 获取元数据应答
	GET_META_DATA_ACK = 162;
	//下发Agent的系统指令
	SYSTEM_COMMAND = 83;
	// 布尔应答
	BOOLEAN_ACK = 100;
}

// Header is a generic replay prevention and identity message to include in a signed payload
message Header {

    required int32 type = 1; 

    // Version indicates message protocol version
    optional bytes version = 2;

    optional int64 time = 3;

    optional int32 request_id = 4;
	
    optional int32 status = 5;

    optional string error = 6;

    optional string typeString = 7;

    optional int32 length = 8;
}

// Command is a common structure to be used to encode block command
message Command {
	// 头部
    required Header header = 1;
}

message GetCluster {
	// 头部
    repeated Header header = 1;
    required string app = 2; // The position in the blockchain
    optional string client_id = 3; // The hash of the previous block header
    optional bytes data_center = 4; // The hash of the BlockData, by MerkleTree
}

C++ 端

    rVal=connect(theSocket,(LPSOCKADDR)&serverInfo, sizeof(serverInfo));
    if(rVal==SOCKET_ERROR)
    {
		sError("Failed connect()");
		return CS_ERROR;
    }	
    string msg;
    tutorial::GetCluster cluster;
    cluster.set_app("APP");
    cluster.set_data_center("1");
    cluster.set_client_id("y134huihuew");
	
    tutorial::Header* header = cluster.add_header();
    header->set_type(31); 
    header->set_version("1");
	
    cluster.SerializeToString(&msg);
    sprintf(buf, "%s", msg.c_str());
    rVal = send(theSocket, buf, sizeof(buf), 0);

结果还是报错
io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 4195328: 168101923 - discarded

不好意思,看到了frameMaxSize 设置的地方

好的。。用protobuf的话不用自己进行序列化和反序列化了,可以把encode和decode模块用protobuf的序列化和反序列化代替。具体可以参考netty in action 相关章节。或者也可以传输协议简化为4字节长度+内容,然后在业务层调用protobuf对byte[]直接反序列化。

我指的通信格式是指补充在readme里面的,如果你要使用protobuf,请继承NettyTransport类并重写handler()方法,去掉LengthFieldBasedFrameDecoder,CommandEncoder,CommandDecoder,换成protobuf的编解码实现。

有邮箱没,后续可能还会有关问题咨询,谢谢

忙起来可能回复会相对久,一般不超过24小时 ^_^

好的

改了编码格式:

image

出现了如下错误:
image

网上说,解析式报错:Protocol message contained an invalid tag (zero)
原因:待解析的二进制数据中不全是pb二进制数据,可能还有其它内容,例如二进制数据头部约定的错误信息长度、错误信息字符串内容等。
还是没有头绪,不知道哪个地方出了问题

终于调通了 @chicc999

关于并发量有做个测试吗,5W的并发量,这个能承受吗,如果不能承受的话,需要怎么调整呢

没有做过并发测试。。。实际上这个项目才刚刚起步,连业务都没跑通,只有个网络的架子。。。最大并发量多少主要看你业务的复杂度和机器配置吧。

后面会有什么计划吗

我这两天写个简单的benchmark做性能测试的架子吧,然后1.0版本如果时间多,预计今年完成。。。看上去工作量还挺大的,毕竟业余时间写写

1.0的话主要做消息队列的主干功能,就是存储,消费以及主从多备份。完成broker,api client,shell client以及控制台。
2.0的话做一些功能特性,例如延迟消费,消息过滤,负载均衡,消息回溯,消费轨迹等等,再加上一些辅助监控功能,控制台台加上业务监控以及报警这些。
3.0的话尝试自己实现协调器包括分布式锁这些功能,替换掉zk

目前就是这样打算的,不过看上去要很久呢

@majianxiong @chicc999

frameMaxSize
您好! 请问这个参数frameMaxSize 在哪设置啊?我也遇到了相同的错误!

可以试下 NettyConfig 的 setFrameMaxSize 方法。服务端和客户端都要设置。