一些EOS的RPC API接口示例

一些EOS的RPC API的示例,大家可以参考一下。

1. GET /v1/chain/get_info

响应:

{
    "server_version": "cd979827",
    "head_block_num": 110572,
    "last_irreversible_block_num": 110571,
    "last_irreversible_block_id": "0001afeb67d2503b93e64f2e34631691989bad886dcc85777995df4aece774fc",
    "head_block_id": "0001afec64eec39550853d2e032633b1c4f987ad22f343e76cafbf8f9e6e36b4",
    "head_block_time": "2018-05-25T13:44:42",
    "head_block_producer": "eosio",
    "virtual_block_cpu_limit": "104857600000",
    "virtual_block_net_limit": 1048576000,
    "block_cpu_limit": 104857500,
    "block_net_limit": 1048576
}

2. POST /v1/chain/abi_json_to_bin

请求:

{  
   "code":"eosio.token",
   "action":"transfer",
   "authorization":[  
      {  
         "actor":"tester",
         "permission":"active"
      }
   ],
   "args":{  
      "from":"tester",
      "to":"user",
      "quantity":"1.0000 EOS",
      "memo":"transfer"
   }
}

响应:

{
    "binargs": "000000005c95b1ca00000000007015d6102700000000000004454f5300000000087472616e73666572"
}

3. POST /v1/chain/get_block

请求:

{"block_num_or_id":100}

响应:

{  
   "timestamp":"2018-05-24T09:12:56.000",
   "producer":"eosio",
   "confirmed":0,
   "previous":"0000006328fadd5333bfb80ecd21646448d3858b40c0816b01b986318455943f",
   "transaction_mroot":"0000000000000000000000000000000000000000000000000000000000000000",
   "action_mroot":"4a60d816edd825751b3e364fe56e6d578f9f30852c00546117167eb5f954d540",
   "schedule_version":0,
   "new_producers":null,
   "header_extensions":[  

   ],
   "producer_signature":"SIG_K1_KiC8vBhqSArKqMS82RByKsepYagHEoa4wAi6AdMSntCaFqhZhg96Q3FCfgp9AGVhqCxnzi1LA4tA4KXrEPZx9ToWEpAZW9",
   "transactions":[  

   ],
   "block_extensions":[  

   ],
   "id":"00000064c400d036822f7d2e2fee71c47b645a07fbcb6c0491cd69d3d25dc4f8",
   "block_num":100,
   "ref_block_prefix":779956098
}

4. POST /v1/chain/get_account

请求:

{"account_name":tester}

响应:

{  
   "account_name":"tester",
   "privileged":false,
   "last_code_update":"1970-01-01T00:00:00.000",
   "created":"2018-05-24T09:14:09.000",
   "ram_quota":-1,
   "net_weight":-1,
   "cpu_weight":-1,
   "net_limit":{  
      "used":-1,
      "available":-1,
      "max":-1
   },
   "cpu_limit":{  
      "used":-1,
      "available":-1,
      "max":-1
   },
   "ram_usage":2852,
   "permissions":[  
      {  
         "perm_name":"active",
         "parent":"owner",
         "required_auth":{  
            "threshold":1,
            "keys":[  
               {  
                  "key":"EOS5T6V7jXaxweNW5eEA8EmHx6dBVEhrKesPRQWxKdqCazmphJJNK",
                  "weight":1
               }
            ],
            "accounts":[  

            ],
            "waits":[  

            ]
         }
      },
      {  
         "perm_name":"owner",
         "parent":"",
         "required_auth":{  
            "threshold":1,
            "keys":[  
               {  
                  "key":"EOS5T6V7jXaxweNW5eEA8EmHx6dBVEhrKesPRQWxKdqCazmphJJNK",
                  "weight":1
               }
            ],
            "accounts":[  

            ],
            "waits":[  

            ]
         }
      }
   ],
   "total_resources":null,
   "delegated_bandwidth":null,
   "voter_info":null
}

5. POST /v1/chain/get_currency_balance

请求:

{  
   "account":"tester",
   "code":"eosio.token",
   "symbol":"EOS"
}

响应:

[
    "10017.6146 EOS"
]

6. POST /v1/chain/abi_bin_to_json

请求:

{  
   "code":"eosio.token",
   "a
<think> 我们正在处理一个gRPC服务中的异常:`java.lang.IllegalStateException: Stream 5 sent too many headers EOS: false`。这个异常发生在Netty的HTTP/2层,表明在同一个流(Stream 5)上尝试发送了过多的头部帧(HEADERS frame)。根据HTTP/2协议,每个流只允许发送一个HEADERS帧(以及可选的CONTINUATION帧)。重复发送HEADERS帧会导致此异常。 ### 错误原因分析 1. **协议违规**:在同一个gRPC流上,尝试多次发送响应头。在gRPC中,每个调用(即每个流)应该只发送一次头部(包含在初始的HEADERS帧中),后续的数据应当通过DATA帧传输。 2. **多线程问题**:可能由于多线程同时操作同一个响应流,导致多个线程都尝试发送头部。 3. **异常处理路径中重复发送头部**:在处理请求时,如果发生错误,可能会在多个错误处理分支中尝试发送错误响应头部,导致重复发送。 4. **gRPC流生命周期管理不当**:例如,在流已经关闭(由于错误或完成)后,仍然尝试发送数据或头部。 ### 高性能多线程架构解决方案 不考虑现有架构,我们设计一个高性能且线程安全的gRPC服务框架。核心目标是避免重复发送头部,同时最大化并发处理能力。 #### 1. **单次头部发送保证** - 每个gRPC流响应必须确保只发送一次头部。这可以通过状态机来实现: ```java class StreamState { private final AtomicBoolean headersSent = new AtomicBoolean(false); private final StreamObserver<Response> responseObserver; public void sendHeaders(Response response) { if (headersSent.compareAndSet(false, true)) { // 实际发送头部(包含在第一个响应中) responseObserver.onNext(response); } } public void sendData(Response dataResponse) { // 如果头部还没发送,则先发送头部(但注意:gRPC中头部是由框架自动发送的) // 实际上,在gRPC中,我们通常不直接控制头部的发送,所以这里需要重新考虑。 } } ``` - 但实际上,在gRPC中,头部的发送是由框架自动完成的。当我们第一次调用`onNext`时,框架会发送头部(如果还未发送),然后发送数据。但是,如果我们尝试在同一个流上多次调用`onNext`,它不会重复发送头部。那么为什么会出现这个错误? #### 重新审视gRPC的头部发送机制 在gRPC中,服务器端实现一个RPC方法时,我们通过`responseObserver`发送响应。对于一元调用(Unary Call),我们调用一次`onNext`(可选)和一次`onCompleted`。对于流式调用,我们可以多次调用`onNext`。但是,每次调用`onNext`并不会发送HEADERS帧,而是发送DATA帧。HEADERS帧只会在流开始时发送一次。 因此,出现重复发送头部的错误,可能是由于以下原因: - **手动干预了gRPC的头部传输**:例如,在拦截器(Interceptor)或自定义ServerCall中,错误地多次发送了头部。 - **Netty底层处理异常**:可能是由于并发操作导致Netty内部状态混乱。 #### 2. **并发控制与状态管理** - 每个gRPC流应该由一个线程处理,或者通过严格的线程封闭(Thread Confinement)来避免并发访问同一个流。但是,gRPC的`StreamObserver`并不是线程安全的,因此必须确保对同一个`StreamObserver`的调用是串行的。 - 然而,在实际应用中,我们可能希望多个线程能够同时处理同一个流上的消息(例如,一个线程生产数据,另一个线程发送)。为了解决这个问题,我们可以引入一个串行器(Serializer): ```java class SerializingStreamObserver<T> implements StreamObserver<T> { private final Executor executor; private final StreamObserver<T> delegate; private final Queue<T> queue = new ConcurrentLinkedQueue<>(); private final AtomicBoolean isSending = new AtomicBoolean(false); public SerializingStreamObserver(Executor executor, StreamObserver<T> delegate) { this.executor = executor; this.delegate = delegate; } @Override public void onNext(T value) { queue.offer(value); trySend(); } private void trySend() { if (isSending.compareAndSet(false, true)) { executor.execute(() -> { try { T item; while ((item = queue.poll()) != null) { delegate.onNext(item); } } finally { isSending.set(false); // 检查是否在释放锁期间有新元素加入 if (!queue.isEmpty()) { trySend(); } } }); } } // ... 类似处理 onError 和 onCompleted } ``` - 这个串行器确保了对底层`StreamObserver`的调用是串行的,即使多个线程调用`onNext`。 #### 3. **避免在拦截器中重复发送头部** - 如果使用了gRPC拦截器,确保在拦截器中不要多次调用`start`方法(该方法会发送头部): ```java public class MyInterceptor implements ServerInterceptor { @Override public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall( ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) { // 不要在这里多次调用call.sendHeaders() return next.startCall(new ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(call) { @Override public void sendHeaders(Metadata responseHeaders) { // 确保只发送一次 super.sendHeaders(responseHeaders); } }, headers); } } ``` #### 4. **异常处理** - 在异常处理中,确保只发送一次错误响应(包括头部): ```java @Override public void onError(Throwable t) { if (state.compareAndSet(State.OPEN, State.CLOSED_WITH_ERROR)) { delegate.onError(t); } else { // 已经关闭,忽略 } } ``` #### 5. **Netty配置优化** - 调整Netty的HTTP/2设置,确保能够处理高并发流: ```java NettyServerBuilder.forPort(port) .maxConcurrentCallsPerConnection(10000) .flowControlWindow(NettyChannelBuilder.DEFAULT_FLOW_CONTROL_WINDOW) .keepAliveTime(30, TimeUnit.SECONDS) .permitKeepAliveWithoutCalls(true) .build(); ``` #### 6. **监控与调试** - 使用Netty日志:设置`io.netty`和`io.grpc`的日志级别为DEBUG,以便跟踪帧的发送。 - 使用JFR(Java Flight Recorder)捕获事件:特别是HTTP/2相关事件,查看是否有异常的帧发送。 ### 总结 该异常的根本原因是违反了HTTP/2协议:在同一个流上发送了多个HEADERS帧。解决方案包括: 1. **确保每个流只发送一次头部**:通过状态机控制。 2. **保证对同一个流的调用串行化**:使用串行器包装`StreamObserver`。 3. **检查拦截器和自定义ServerCall**:避免手动多次发送头部。 4. **优化Netty配置**:提高并发处理能力。 ### 相关问题 1. gRPC中如何保证`StreamObserver`的线程安全? 2. 如何设计高性能的gRPC流式服务? 3. 如何监控和调试gRPC的HTTP/2传输层问题? 4. 在gRPC拦截器中,正确发送响应头部的实践是什么? </think> ### gRPC中出现 `java.lang.IllegalStateException: Stream 5 sent too many headers` 的原因与高性能解决方案 #### 一、根本原因分析 1. **HTTP/2协议冲突** 在HTTP/2协议中,每个流(Stream)**只能发送一个HEADERS帧**(RFC 7540
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值