当前位置:首页>python>Python gRPC 从入门到进阶:高效微服务通信的完整指南

Python gRPC 从入门到进阶:高效微服务通信的完整指南

  • 2026-07-01 09:23:20
Python gRPC 从入门到进阶:高效微服务通信的完整指南

作者:IT策士

10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在公众号、今日头条持续发布最新文章,助你少走弯路。

前言

在微服务架构中,服务间的通信效率直接影响着整个系统的性能。想象一下,如果你的电商订单系统每秒需要调用上千次库存服务,那种传统的 JSON 文本传输会带来多大的性能损耗?这正是 gRPC 要解决的核心问题。

gRPC 由 Google 开发,是一个高性能、开源的远程过程调用框架。与传统的 REST API 不同,gRPC 基于 HTTP/2 协议,使用 Protocol Buffers 作为序列化格式,将数据体积压缩 3-10 倍,同时支持双向流通信、连接多路复用等高级特性-42。Netflix、Square、Google 等顶级公司已大规模用 gRPC 替代 REST,用于内部微服务通信-42。

本文将带你从零开始掌握 Python 中的 gRPC 开发技术,从环境搭建到生产级实践,每一个示例都可以直接运行,适合新手入门和进阶开发者参考。

一、环境准备:从零搭建 gRPC 开发环境

首先安装核心依赖:

# 安装 gRPC 核心库和编译工具
pip install grpcio grpcio-tools protobuf

安装完成后,验证版本:

python -c "import grpc; print(f'gRPC 版本:{grpc.__version__}')"

控制台输出:

新手常见坑:import grpc 时不能写成 import grpcio。Python 中没有叫 grpc 的官方包,grpcio 安装后暴露的顶层模块名是 grpc,这个细节经常让新手困惑-。

二、入门实战:构建第一个 gRPC 服务

2.1 定义 .proto 文件

gRPC 的核心思想是契约优先——先定义好服务接口,再由框架自动生成代码。接口定义使用 Protocol Buffers 语法。

// hello.proto
syntax = "proto3";

package hello;

// 定义问候服务
service Greeter {
// 一元 RPC:客户端发送一个请求,服务端返回一个响应
rpc SayHello(HelloRequest)returns(HelloReply);
}

// 请求消息
message HelloRequest {
string name = 1;
}

// 响应消息
message HelloReply {
string message = 1;
}

语法要点解析

  • syntax = "proto3":使用 Proto3 语法,这是目前推荐的标准版本-38
  • message:定义数据结构,每个字段后有唯一的编号(tag),用于二进制编码时识别字段-38
  • service:定义 RPC 方法签名,指定输入输出类型-39
  • 字段编号从 1 开始递增,不可重复,建议预留部分编号便于后续扩展

2.2 编译生成 Python 代码

使用 protoc 编译器将 .proto 文件编译为 Python 代码:

python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. hello.proto

控制台输出(成功时无报错):

这个命令会在当前目录下生成两个文件-7:

  • hello_pb2.py:包含消息类的序列化/反序列化代码
  • hello_pb2_grpc.py:包含服务基类(Servicer)和客户端桩代码(Stub)

组件分工表

2.3 实现服务端

服务端的核心任务是实现 .proto 中定义的服务接口并启动 gRPC 服务器-7。

# server.py
import grpc
from concurrent import futures
import hello_pb2
import hello_pb2_grpc

classGreeterServicer(hello_pb2_grpc.GreeterServicer):
"""实现 .proto 中定义的 Greeter 服务"""

defSayHello(self, request, context):
# request.name 来自客户端发送的 HelloRequest
        print(f"[服务端] 收到请求,name={request.name}")
return hello_pb2.HelloReply(
            message=f"你好,{request.name}!这里是 gRPC 服务端 "
        )

defserve():
# 创建 gRPC 服务器,最大工作线程数 10
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))

# 将服务实现注册到服务器
    hello_pb2_grpc.add_GreeterServicer_to_server(GreeterServicer(), server)

# 监听端口(insecure 表示不使用 TLS,仅供开发测试)
    server.add_insecure_port('[::]:50051')

    print("[服务端] gRPC 服务已启动,监听端口 50051...")
    server.start()
    server.wait_for_termination()

if __name__ == '__main__':
    serve()

2.4 实现客户端

客户端的任务是通过 Stub(桩)调用远程服务方法,就像调用本地函数一样自然-7。

# client.py
import grpc
import hello_pb2
import hello_pb2_grpc

defrun():
# 建立与服务器的连接(insecure 开发模式)
with grpc.insecure_channel('localhost:50051'as channel:
# 创建客户端桩(Stub)
        stub = hello_pb2_grpc.GreeterStub(channel)

# 构造请求并调用远程方法
        response = stub.SayHello(hello_pb2.HelloRequest(name="小明"))

        print(f"[客户端] 收到响应: {response.message}")

if __name__ == '__main__':
    run()

2.5 运行测试

打开两个终端,分别运行服务端和客户端。

终端 1 — 服务端:

终端 1 输出:

[服务端] gRPC 服务已启动,监听端口 50051...
[服务端] 收到请求,name=小明

终端 2 — 客户端:

终端 2 输出:

[客户端] 收到响应: 你好,小明!这里是 gRPC 服务端 

恭喜!你已经成功构建了第一个 gRPC 服务 。

三、深入理解:四种通信模式全解析

gRPC 基于 HTTP/2,支持四种通信模式-16。下面逐一实战演示。

3.1 定义流式 .proto 文件

// streaming.proto
syntax = "proto3";

package streaming;

service DataService {
// 1. 一元 RPC:一问一答(上面已讲)
rpc UnaryCall(DataRequest)returns(DataResponse);

// 2. 服务端流式:客户端发一次,服务端持续推送
rpc ServerStreaming(DataRequest)returns(stream DataResponse);

// 3. 客户端流式:客户端持续发送,服务端汇总一次
rpc ClientStreaming(stream DataRequest)returns(DataResponse);

// 4. 双向流式:双方都可随时发送
rpc BidirectionalStreaming(stream DataRequest)returns(stream DataResponse);
}

message DataRequest {
string message = 1;
    int32 sequence = 2;  // 序号,用于追踪数据流顺序
}

message DataResponse {
string message = 1;
    int32 sequence = 2;
}

语法要点:stream 关键字是流式模式的核心声明。出现在返回类型前表示服务端流式,出现在参数类型前表示客户端流式,两边都有则是双向流式-19。

首先编译生成代码:

python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. streaming.proto

3.2 模式一:服务端流式(Server Streaming)

适用场景:股票实时行情推送、日志监控、大文件下载。服务端逐个发送数据块,客户端逐个读取,内存占用极低-19。

# server_streaming_server.py
import grpc
import time
from concurrent import futures
import streaming_pb2
import streaming_pb2_grpc

classDataServiceServicer(streaming_pb2_grpc.DataServiceServicer):

defServerStreaming(self, request, context):
"""服务端流式:收到一个请求后,持续推送多条数据"""
        print(f"[服务端] 收到流式请求: {request.message},开始推送数据...")

for i in range(5):
            response = streaming_pb2.DataResponse(
                message=f"服务端推送第 {i+1} 条数据",
                sequence=i + 1
            )
            print(f"[服务端] 推送 #{i+1}")
yield response
            time.sleep(0.5)  # 模拟数据生成延迟

        print("[服务端] 推送完成")

defserve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    streaming_pb2_grpc.add_DataServiceServicer_to_server(DataServiceServicer(), server)
    server.add_insecure_port('[::]:50052')
    server.start()
    print("[服务端流式] 服务已启动,监听端口 50052...")
    server.wait_for_termination()

if __name__ == '__main__':
    serve()
# server_streaming_client.py
import grpc
import streaming_pb2
import streaming_pb2_grpc

defrun():
with grpc.insecure_channel('localhost:50052'as channel:
        stub = streaming_pb2_grpc.DataServiceStub(channel)

        request = streaming_pb2.DataRequest(message="请推送数据")
        print("[客户端] 发送请求,等待服务端推送...")

# responses 是一个迭代器,逐个接收服务端推送的数据
        responses = stub.ServerStreaming(request)
for resp in responses:
            print(f"[客户端] 收到 #{resp.sequence}{resp.message}")

if __name__ == '__main__':
    run()

控制台输出 — 服务端:

[服务端流式] 服务已启动,监听端口 50052...
[服务端] 收到流式请求: 请推送数据,开始推送数据...
[服务端] 推送 
#1
[服务端] 推送 #2
[服务端] 推送 #3
[服务端] 推送 #4
[服务端] 推送 #5
[服务端] 推送完成

控制台输出 — 客户端:

[客户端] 发送请求,等待服务端推送...
[客户端] 收到 #1: 服务端推送第 1 条数据
[客户端] 收到 #2: 服务端推送第 2 条数据
[客户端] 收到 #3: 服务端推送第 3 条数据
[客户端] 收到 #4: 服务端推送第 4 条数据
[客户端] 收到 #5: 服务端推送第 5 条数据

核心要点:服务端使用 yield 逐个生成响应,客户端通过 for-in 循环逐条接收,无需等待全部数据到达。

3.3 模式二:客户端流式(Client Streaming)

适用场景:物联网设备批量上报传感器数据、日志采集、大文件上传-19。

# client_streaming_server.py
import grpc
from concurrent import futures
import streaming_pb2
import streaming_pb2_grpc

classDataServiceServicer(streaming_pb2_grpc.DataServiceServicer):

defClientStreaming(self, request_iterator, context):
"""客户端流式:接收客户端持续发送的多条数据,汇总后返回一条结果"""
        total = 0
        messages = []

for request in request_iterator:
            total += 1
            messages.append(request.message)
            print(f"[服务端] 收到 #{request.sequence}{request.message}")

# 汇总返回
        result = streaming_pb2.DataResponse(
            message=f"共收到 {total} 条数据: {'; '.join(messages)}",
            sequence=total
        )
        print(f"[服务端] 汇总完成,返回结果")
return result

defserve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    streaming_pb2_grpc.add_DataServiceServicer_to_server(DataServiceServicer(), server)
    server.add_insecure_port('[::]:50053')
    server.start()
    print("[客户端流式] 服务已启动,监听端口 50053...")
    server.wait_for_termination()

if __name__ == '__main__':
    serve()
# client_streaming_client.py
import grpc
import time
import streaming_pb2
import streaming_pb2_grpc

defgenerate_requests():
"""生成器函数:逐个产生要发送的请求"""
    data_list = ["传感器-温度:25.3°C""传感器-湿度:68%""传感器-气压:1013hPa"]
for i, data in enumerate(data_list):
yield streaming_pb2.DataRequest(message=data, sequence=i + 1)
        time.sleep(0.3)  # 模拟采集间隔
        print(f"    [生成器] 已产生第 {i+1} 条数据")

defrun():
with grpc.insecure_channel('localhost:50053'as channel:
        stub = streaming_pb2_grpc.DataServiceStub(channel)

        response = stub.ClientStreaming(generate_requests())
        print(f"\n[客户端] 收到汇总响应: {response.message}")

if __name__ == '__main__':
    run()

控制台输出 — 服务端:

[客户端流式] 服务已启动,监听端口 50053...
[服务端] 收到 #1: 传感器-温度:25.3°C
[服务端] 收到 #2: 传感器-湿度:68%
[服务端] 收到 #3: 传感器-气压:1013hPa
[服务端] 汇总完成,返回结果

控制台输出 — 客户端:

[生成器] 已产生第 1 条数据
[生成器] 已产生第 2 条数据
[生成器] 已产生第 3 条数据

[客户端] 收到汇总响应: 共收到 3 条数据: 传感器-温度:25.3°C; 传感器-湿度:68%; 传感器-气压:1013hPa

核心要点:客户端用 yield 生成器逐个发送请求,服务端通过迭代 request_iterator 逐个接收,汇总后一次性返回结果。

3.4 模式三:双向流式(Bidirectional Streaming)

适用场景:实时聊天、语音识别、在线游戏同步——双方可以随时、独立地发送数据-19。

# bidirectional_server.py
import grpc
import time
from concurrent import futures
import streaming_pb2
import streaming_pb2_grpc

classDataServiceServicer(streaming_pb2_grpc.DataServiceServicer):

defBidirectionalStreaming(self, request_iterator, context):
"""双向流式:一边接收客户端消息,一边主动推送响应"""
        print("[服务端] 双向流通信已建立,等待客户端消息...")

for request in request_iterator:
            print(f"[服务端] 收到 #{request.sequence}{request.message}")

# 收到一条消息后,立即回复两条
yield streaming_pb2.DataResponse(
                message=f"回声: {request.message}",
                sequence=request.sequence * 100 + 1
            )
yield streaming_pb2.DataResponse(
                message=f"确认收到第 {request.sequence} 条消息",
                sequence=request.sequence * 100 + 2
            )

defserve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    streaming_pb2_grpc.add_DataServiceServicer_to_server(DataServiceServicer(), server)
    server.add_insecure_port('[::]:50054')
    server.start()
    print("[双向流式] 服务已启动,监听端口 50054...")
    server.wait_for_termination()

if __name__ == '__main__':
    serve()
# bidirectional_client.py
import grpc
import time
import threading
import streaming_pb2
import streaming_pb2_grpc

defrun():
with grpc.insecure_channel('localhost:50054'as channel:
        stub = streaming_pb2_grpc.DataServiceStub(channel)

defgenerate_messages():
"""在另一个线程中发送消息"""
            messages = ["你好服务端!""这是第二条消息""再见!"]
for i, msg in enumerate(messages):
yield streaming_pb2.DataRequest(message=msg, sequence=i + 1)
                time.sleep(1)
                print(f"    [发送线程] 已发送第 {i+1} 条: {msg}")

# 调用双向流 RPC
        responses = stub.BidirectionalStreaming(generate_messages())

        print("[客户端] 开始接收服务端响应...")
for resp in responses:
            print(f"[客户端] 收到 #{resp.sequence}{resp.message}")

if __name__ == '__main__':
    run()

控制台输出 — 服务端:

[双向流式] 服务已启动,监听端口 50054...
[服务端] 双向流通信已建立,等待客户端消息...
[服务端] 收到 #1: 你好服务端!
[服务端] 收到 #2: 这是第二条消息
[服务端] 收到 #3: 再见!

控制台输出 — 客户端:

[客户端] 开始接收服务端响应...
[客户端] 收到 #101: 回声: 你好服务端!
[客户端] 收到 #102: 确认收到第 1 条消息
    [发送线程] 已发送第 1 条: 你好服务端!
[客户端] 收到 #201: 回声: 这是第二条消息
[客户端] 收到 #202: 确认收到第 2 条消息
    [发送线程] 已发送第 2 条: 这是第二条消息
[客户端] 收到 #301: 回声: 再见!
[客户端] 收到 #302: 确认收到第 3 条消息
    [发送线程] 已发送第 3 条: 再见!

核心要点:双向流式模式下,客户端和服务端可以同时发送和接收数据,实现了真正的全双工通信。收到一条消息后,可以回复多条(本例中回复了 2 条)。

3.5 四种模式对比总结

四、进阶应用:生产级 gRPC 服务的关键技术

前面已经掌握了 gRPC 的基本用法,但要构建生产级服务,还需要掌握以下几个关键技术。

4.1 拦截器:横切逻辑的优雅实现

拦截器是 gRPC 的"中间件"机制,可以在不修改业务代码的情况下,统一处理日志、认证、监控等横切关注点-。

# interceptor_server.py
import grpc
from concurrent import futures
import time
import hello_pb2
import hello_pb2_grpc

classLoggingInterceptor(grpc.ServerInterceptor):
"""自定义日志拦截器:记录每次 RPC 调用的耗时"""

defintercept_service(self, continuation, handler_call_details):
        start_time = time.time()

# 调用实际的 RPC 处理方法
        response = continuation(handler_call_details)

        elapsed = (time.time() - start_time) * 1000
        method = handler_call_details.method
        print(f"[拦截器] {method} 调用完成,耗时 {elapsed:.2f}ms")

return response

classGreeterServicer(hello_pb2_grpc.GreeterServicer):
defSayHello(self, request, context):
return hello_pb2.HelloReply(
            message=f"你好,{request.name}!"
        )

defserve():
# 在创建服务器时传入拦截器
    server = grpc.server(
        futures.ThreadPoolExecutor(max_workers=10),
        interceptors=[LoggingInterceptor()]  # 注入拦截器
    )

    hello_pb2_grpc.add_GreeterServicer_to_server(GreeterServicer(), server)
    server.add_insecure_port('[::]:50055')
    server.start()
    print("[拦截器示例] 服务已启动...")
    server.wait_for_termination()

if __name__ == '__main__':
    serve()

客户端(使用之前的 client.py 修改端口为 50055):

# interceptor_client.py
import grpc
import hello_pb2
import hello_pb2_grpc

defrun():
with grpc.insecure_channel('localhost:50055'as channel:
        stub = hello_pb2_grpc.GreeterStub(channel)
        response = stub.SayHello(hello_pb2.HelloRequest(name="小明"))
        print(f"[客户端] 收到: {response.message}")

if __name__ == '__main__':
    run()

控制台输出 — 服务端:

[拦截器示例] 服务已启动...
[拦截器] /hello.Greeter/SayHello 调用完成,耗时 0.03ms

4.2 错误处理与状态码

gRPC 提供了丰富的状态码体系,远比 HTTP 状态码更精确-58。不应一律返回 INTERNAL 错误,而应使用语义明确的状态码。

# error_handling_server.py
import grpc
from concurrent import futures
import hello_pb2
import hello_pb2_grpc

classGreeterServicer(hello_pb2_grpc.GreeterServicer):
defSayHello(self, request, context):
# 参数校验
ifnot request.name:
            context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
            context.set_details('name 参数不能为空')
return hello_pb2.HelloReply()

# 模拟权限检查
if request.name == "admin":
            context.set_code(grpc.StatusCode.PERMISSION_DENIED)
            context.set_details('不允许使用 admin 身份')
return hello_pb2.HelloReply()

# 模拟资源不存在
if request.name == "notfound":
            context.abort(grpc.StatusCode.NOT_FOUND, '该用户不存在')

return hello_pb2.HelloReply(
            message=f"你好,{request.name}!调用成功"
        )

defserve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    hello_pb2_grpc.add_GreeterServicer_to_server(GreeterServicer(), server)
    server.add_insecure_port('[::]:50056')
    server.start()
    print("[错误处理示例] 服务已启动...")
    server.wait_for_termination()

if __name__ == '__main__':
    serve()
# error_handling_client.py
import grpc
import hello_pb2
import hello_pb2_grpc

defcall_with_name(stub, name):
"""封装调用逻辑,统一处理 RPC 错误"""
try:
        response = stub.SayHello(
            hello_pb2.HelloRequest(name=name),
            timeout=2.0# 设置 2 秒超时
        )
        print(f"[客户端] name='{name}' -> {response.message}")
except grpc.RpcError as e:
        print(f"[客户端] name='{name}' -> "
f"状态码: {e.code()}, 详情: {e.details()}")

defrun():
with grpc.insecure_channel('localhost:50056'as channel:
        stub = hello_pb2_grpc.GreeterStub(channel)

        call_with_name(stub, "小明")       # 正常
        call_with_name(stub, "")           # 参数为空
        call_with_name(stub, "admin")      # 权限不足
        call_with_name(stub, "notfound")   # 资源不存在

if __name__ == '__main__':
    run()

控制台输出 — 客户端:

[客户端] name='小明' -> 你好,小明!调用成功
[客户端] name='' -> 状态码: StatusCode.INVALID_ARGUMENT, 详情: name 参数不能为空
[客户端] name='admin' -> 状态码: StatusCode.PERMISSION_DENIED, 详情: 不允许使用 admin 身份
[客户端] name='notfound' -> 状态码: StatusCode.NOT_FOUND, 详情: 该用户不存在

常用状态码速查

4.3 HTTP/2 连接复用(Keep-Alive)与超时配置

生产环境中,长连接的管理直接影响资源利用率和故障恢复速度。

# keepalive_server.py
import grpc
from concurrent import futures
import hello_pb2
import hello_pb2_grpc

classGreeterServicer(hello_pb2_grpc.GreeterServicer):
defSayHello(self, request, context):
# 获取请求超时时间
        deadline = context.time_remaining()
if deadline:
            print(f"[服务端] 距离超时还有 {deadline:.2f} 秒")
return hello_pb2.HelloReply(message=f"你好,{request.name}!")

defserve():
    server = grpc.server(
        futures.ThreadPoolExecutor(max_workers=10),
        options=[
# HTTP/2 Keep-Alive:定期发送 PING 帧保持连接
            ('grpc.keepalive_time_ms'10000),       # 每 10 秒发送 PING
            ('grpc.keepalive_timeout_ms'5000),     # PING 超时 5 秒则断开
            ('grpc.keepalive_permit_without_calls'True),
            ('grpc.http2.max_pings_without_data'0),
        ]
    )
    hello_pb2_grpc.add_GreeterServicer_to_server(GreeterServicer(), server)
    server.add_insecure_port('[::]:50057')
    server.start()
    print("[Keep-Alive 示例] 服务已启动...")
    server.wait_for_termination()

if __name__ == '__main__':
    serve()
# keepalive_client.py
import grpc
import hello_pb2
import hello_pb2_grpc

defrun():
# 配置客户端侧 HTTP/2 Keep-Alive
    channel = grpc.insecure_channel(
'localhost:50057',
        options=[
            ('grpc.keepalive_time_ms'10000),
            ('grpc.keepalive_timeout_ms'5000),
            ('grpc.http2.min_time_between_pings_ms'5000),
            ('grpc.keepalive_permit_without_calls'True),
        ]
    )

    stub = hello_pb2_grpc.GreeterStub(channel)
    response = stub.SayHello(
        hello_pb2.HelloRequest(name="小明"),
        timeout=1.0# 单次调用超时 1 秒
    )
    print(f"[客户端] 收到: {response.message}")
    channel.close()

if __name__ == '__main__':
    run()

控制台输出 — 服务端:

[Keep-Alive 示例] 服务已启动...
[服务端] 距离超时还有 0.99 秒

五、gRPC vs REST:何时选择 gRPC?

这个话题是新手最容易纠结的。核心区分点在于使用场景-41-42:

选择 gRPC 的场景

  • 微服务间高并发、低延迟通信
  • 实时数据推送(股票、监控、聊天)
  • 多语言技术栈的服务间调用
  • 需要严格 API 契约管理的大型分布式系统

选择 REST 的场景

  • 浏览器直连(无 gRPC-Web 中间件时)
  • 对外的公共 API(兼容性优先)
  • 中小型项目,简单 CRUD 操作
  • 团队缺乏 gRPC 经验的学习过渡期

六、常见问题与避坑指南

6.1 AttributeError: module 'grpc' has no attribute 'server'

错误原因:把 grpc 和 grpcio 搞混了。Python 里没有叫 grpc 的官方包,你需要 pip install grpcio,但 import 时写的是 import grpc——grpc 是 grpcio 安装后暴露的顶层模块名-。

解决方案

pip install grpcio   # 正确安装
import grpc   # 正确导入——grpc 是 grpcio 安装后暴露的顶层模块名

6.2 端口冲突

# 检查端口是否被占用
lsof-i :50051
kill-9 <PID>

6.3 .proto 文件不生效

每次修改 .proto 文件后,记得重新编译:

# 先删除旧的生成文件
rm*_pb2.py *_pb2_grpc.py
# 再重新编译
python-m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. hello.proto

6.4 生产环境使用 TLS

生产环境务必使用 TLS 加密通信,替换 add_insecure_port 为:

# 读取证书
withopen('server.key''rb'as f:
    private_key = f.read()
withopen('server.crt''rb'as f:
    certificate_chain = f.read()

# 创建 SSL 凭证
server_credentials = grpc.ssl_server_credentials([(private_key, certificate_chain)])

# 使用安全端口
server.add_secure_port('[::]:50051', server_credentials)

七、总结与学习路线图

本文核心要点回顾

  • gRPC 的优势
    :HTTP/2 + Protobuf 带来高性能、双向流通信和跨语言支持
  • 开发流程
    :定义 .proto → 编译生成代码 → 实现服务端 → 编写客户端
  • 四种通信模式
    :一元 RPC、服务端流式、客户端流式、双向流式
  • 生产级实践
    :拦截器、错误处理、超时控制、TLS 加密

学习路径建议

  1. 入门
    :跑通文中的 Hello gRPC 示例(第 2 节),理解协议栈与编译流程
  2. 巩固
    :实现四种流式模式(第 3 节),掌握 yield 和迭代器模式
  3. 进阶
    :添加拦截器(日志/认证/限流)、配置健康检查和服务配置-56
  4. 生产
    :集成 TLS 加密、实现智能重试策略和负载均衡-56
  5. 深化
    :异步 gRPC(grpc.aio)、与 FastAPI 混合部署、Service Mesh 集成

延伸阅读

  • gRPC 官方文档
    :https://grpc.io/docs/languages/python/ — 最权威的参考资料
  • Protocol Buffers 规范
    :https://protobuf.dev/programming-guides/proto3/ — Proto3 完整语法
  • gRPC 服务配置指南
    :https://grpc.org.cn/docs/guides/service-config/ — 超时、重试、负载均衡配置

gRPC 的学习曲线比 REST 稍高,但它在性能上的回报是巨大的。掌握 gRPC,你将能够构建出真正高性能的分布式系统。如果你在实践过程中遇到任何问题,欢迎在评论区留言交流!

还可以去公众号、今日头条搜索「IT策士」,一起升级 IT 思维 !

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-03 11:16:50 HTTP/2.0 GET : https://f.mffb.com.cn/a/493485.html
  2. 运行时间 : 0.078047s [ 吞吐率:12.81req/s ] 内存消耗:4,519.54kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=eeec96e08b14a09a26ca79d423ba4eb7
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000586s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000825s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000348s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000276s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000496s ]
  6. SELECT * FROM `set` [ RunTime:0.000193s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000564s ]
  8. SELECT * FROM `article` WHERE `id` = 493485 LIMIT 1 [ RunTime:0.000573s ]
  9. UPDATE `article` SET `lasttime` = 1783048610 WHERE `id` = 493485 [ RunTime:0.000692s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.000216s ]
  11. SELECT * FROM `article` WHERE `id` < 493485 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000389s ]
  12. SELECT * FROM `article` WHERE `id` > 493485 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000347s ]
  13. SELECT * FROM `article` WHERE `id` < 493485 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000726s ]
  14. SELECT * FROM `article` WHERE `id` < 493485 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.005933s ]
  15. SELECT * FROM `article` WHERE `id` < 493485 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.001253s ]
0.079612s