Nacos源码—9.Nacos升级gRPC分析八

大纲

10.gRPC客户端初始化分析

11.gRPC客户端的心跳机制(健康检查)

12.gRPC服务端如何处理客户端的建立连接请求

13.gRPC服务端如何映射各种请求与对应的Handler处理类

14.gRPC简单介绍

12.gRPC服务端如何处理客户端的建立连接请求

(1)gRPC服务端是如何启动的

(2)connectionId如何绑定Client对象的

(1)gRPC服务端是如何启动的

BaseRpcServer类有一个被@PostConstruct修饰的start()方法,该方法会调用BaseGrpcServer的startServer()方法来启动gRPC服务端。

在BaseGrpcServer的startServer()方法中,首先会调用BaseGrpcServer的addServices()方法添加服务,然后会使用建造者模式通过ServerBuilder创建gRPC框架的Server对象,最后启动gRPC框架的Server服务端,即启动一个NettyServer服务端。

//abstract rpc server.
public abstract class BaseRpcServer {
    ...
    //Start sever. 启动gRPC服务端
    @PostConstruct
    public void start() throws Exception {
        String serverName = getClass().getSimpleName();
        Loggers.REMOTE.info("Nacos {} Rpc server starting at port {}", serverName, getServicePort());

        //调用BaseGrpcServer.startServer()方法启动gRPC服务端
        startServer();

        Loggers.REMOTE.info("Nacos {} Rpc server started at port {}", serverName, getServicePort());
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            Loggers.REMOTE.info("Nacos {} Rpc server stopping", serverName);
            try {
                BaseRpcServer.this.stopServer();
                Loggers.REMOTE.info("Nacos {} Rpc server stopped successfully...", serverName);
            } catch (Exception e) {
                Loggers.REMOTE.error("Nacos {} Rpc server stopped fail...", serverName, e);
            }
        }));
    }
    
    //get service port.
    public int getServicePort() {
        return EnvUtil.getPort() + rpcPortOffset();
    }
    ...
}

//Grpc implementation as a rpc server.
public abstract class BaseGrpcServer extends BaseRpcServer {
    ...
    @Override
    public void startServer() throws Exception {
        final MutableHandlerRegistry handlerRegistry = new MutableHandlerRegistry();
    
        //server interceptor to set connection id. 定义请求拦截器
        ServerInterceptor serverInterceptor = new ServerInterceptor() {
            @Override
            public <T, S> ServerCall.Listener<T> interceptCall(ServerCall<T, S> call, Metadata headers, ServerCallHandler<T, S> next) {
                Context ctx = Context.current()
                    .withValue(CONTEXT_KEY_CONN_ID, call.getAttributes().get(TRANS_KEY_CONN_ID))
                    .withValue(CONTEXT_KEY_CONN_REMOTE_IP, call.getAttributes().get(TRANS_KEY_REMOTE_IP))
                    .withValue(CONTEXT_KEY_CONN_REMOTE_PORT, call.getAttributes().get(TRANS_KEY_REMOTE_PORT))
                    .withValue(CONTEXT_KEY_CONN_LOCAL_PORT, call.getAttributes().get(TRANS_KEY_LOCAL_PORT));
                if (REQUEST_BI_STREAM_SERVICE_NAME.equals(call.getMethodDescriptor().getServiceName())) {
                    Channel internalChannel = getInternalChannel(call);
                    ctx = ctx.withValue(CONTEXT_KEY_CHANNEL, internalChannel);
                }
                return Contexts.interceptCall(ctx, call, headers, next);
            }
        };

        //1.调用BaseGrpcServer.addServices()方法添加服务
        addServices(handlerRegistry, serverInterceptor);

        //2.创建一个gRPC框架的Server对象,使用了建造者模式
        server = ServerBuilder.forPort(getServicePort()).executor(getRpcExecutor())
        .maxInboundMessageSize(getInboundMessageSize()).fallbackHandlerRegistry(handlerRegistry)
        .compressorRegistry(CompressorRegistry.getDefaultInstance())
        .decompressorRegistry(DecompressorRegistry.getDefaultInstance())
        .addTransportFilter(new ServerTransportFilter() {
            @Override
            public Attributes transportReady(Attributes transportAttrs) {
                InetSocketAddress remoteAddress = (InetSocketAddress) transportAttrs.get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR);
                InetSocketAddress localAddress = (InetSocketAddress) transportAttrs.get(Grpc.TRANSPORT_ATTR_LOCAL_ADDR);
                int remotePort = remoteAddress.getPort();
                int localPort = localAddress.getPort();
                String remoteIp = remoteAddress.getAddress().getHostAddress();
                Attributes attrWrapper = transportAttrs.toBuilder()
                    .set(TRANS_KEY_CONN_ID, System.currentTimeMillis() + "_" + remoteIp + "_" + remotePort)
                    .set(TRANS_KEY_REMOTE_IP, remoteIp).set(TRANS_KEY_REMOTE_PORT, remotePort)
                    .set(TRANS_KEY_LOCAL_PORT, localPort).build();
                String connectionId = attrWrapper.get(TRANS_KEY_CONN_ID);
                Loggers.REMOTE_DIGEST.info("Connection transportReady,connectionId = {} ", connectionId);
                return attrWrapper;
            }
            
            @Override
            public void transportTerminated(Attributes transportAttrs) {
                String connectionId = null;
                try {
                    connectionId = transportAttrs.get(TRANS_KEY_CONN_ID);
                } catch (Exception e) {
                        //Ignore
                }
                if (StringUtils.isNotBlank(connectionId)) {
                    Loggers.REMOTE_DIGEST.info("Connection transportTerminated,connectionId = {} ", connectionId);
                    connectionManager.unregister(connectionId);
                }
            }
        }).build();
        
        //3.启动gRPC框架的Server
        server.start();
    }
    ...
}

(2)connectionId如何绑定Client对象的

BaseGrpcServer的startServer()方法在执行addServices()方法添加服务时,就会对connectionId与Client对象进行绑定。

绑定会由GrpcBiStreamRequestAcceptor的requestBiStream()方法触发。具体就是会调用ConnectionManager.register()方法来实现绑定,即先通过执行"connections.put(connectionId, connection)"代码,将connectionId和connection连接对象,放入到ConnectionManager的connections这个Map属性中。再执行ClientConnectionEventListenerRegistry的notifyClientConnected()方法,把Connection连接对象包装成Client对象。

将Connection连接对象包装成Client对象时,又会继续调用ConnectionBasedClientManager的clientConnected()方法,该方法便会根据connectionId创建出一个Client对象,然后将其放入到ConnectionBasedClientManager的clients这个Map中,从而实现connectionId与Client对象的关联。

//Grpc implementation as a rpc server.
public abstract class BaseGrpcServer extends BaseRpcServer {
    ...
    private void addServices(MutableHandlerRegistry handlerRegistry, ServerInterceptor... serverInterceptor) {
        //unary common call register.
        final MethodDescriptor<Payload, Payload> unaryPayloadMethod = MethodDescriptor.<Payload, Payload>newBuilder()
            .setType(MethodDescriptor.MethodType.UNARY)
            .setFullMethodName(MethodDescriptor.generateFullMethodName(REQUEST_SERVICE_NAME, REQUEST_METHOD_NAME))
            .setRequestMarshaller(ProtoUtils.marshaller(Payload.getDefaultInstance()))
            .setResponseMarshaller(ProtoUtils.marshaller(Payload.getDefaultInstance())).build();

        //对gRPC客户端请求的服务进行映射处理
        final ServerCallHandler<Payload, Payload> payloadHandler = ServerCalls.asyncUnaryCall((request, responseObserver) -> grpcCommonRequestAcceptor.request(request, responseObserver));
      
        //构建ServerServiceDefinition服务
        final ServerServiceDefinition serviceDefOfUnaryPayload = ServerServiceDefinition.builder(REQUEST_SERVICE_NAME).addMethod(unaryPayloadMethod, payloadHandler).build();

        //添加服务到gRPC的请求流程中
        handlerRegistry.addService(ServerInterceptors.intercept(serviceDefOfUnaryPayload, serverInterceptor));
    
        //bi stream register.
        //处理客户端连接对象的关联
        //也就是调用GrpcBiStreamRequestAcceptor.requestBiStream()方法对ConnectionId与Client对象进行绑定
        final ServerCallHandler<Payload, Payload> biStreamHandler = ServerCalls.asyncBidiStreamingCall((responseObserver) -> grpcBiStreamRequestAcceptor.requestBiStream(responseObserver));
    
        final MethodDescriptor<Payload, Payload> biStreamMethod = MethodDescriptor.<Payload, Payload>newBuilder()
            .setType(MethodDescriptor.MethodType.BIDI_STREAMING)
            .setFullMethodName(MethodDescriptor.generateFullMethodName(REQUEST_BI_STREAM_SERVICE_NAME, REQUEST_BI_STREAM_METHOD_NAME))
            .setRequestMarshaller(ProtoUtils.marshaller(Payload.newBuilder().build()))
            .setResponseMarshaller(ProtoUtils.marshaller(Payload.getDefaultInstance())).build();
    
        final ServerServiceDefinition serviceDefOfBiStream = ServerServiceDefinition.builder(REQUEST_BI_STREAM_SERVICE_NAME).addMethod(biStreamMethod, biStreamHandler).build();
        handlerRegistry.addService(ServerInterceptors.intercept(serviceDefOfBiStream, serverInterceptor));
    }
    ...
}

@Service
public class GrpcBiStreamRequestAcceptor extends BiRequestStreamGrpc.BiRequestStreamImplBase {
    ...
    @Override
    public StreamObserver<Payload> requestBiStream(StreamObserver<Payload> responseObserver) {
        StreamObserver<Payload> streamObserver = new StreamObserver<Payload>() {
            ...
            @Override
            public void onNext(Payload payload) {
                ...
                //创建连接信息对象,把一些元信息放入到这个对象中
                ConnectionMeta metaInfo = new ConnectionMeta(connectionId, payload.getMetadata().getClientIp(),
                    remoteIp, remotePort, localPort, ConnectionType.GRPC.getType(),
                    setUpRequest.getClientVersion(), appName, setUpRequest.getLabels());
                metaInfo.setTenant(setUpRequest.getTenant());
                //把连接信息包装到连接对象中
                Connection connection = new GrpcConnection(metaInfo, responseObserver, CONTEXT_KEY_CHANNEL.get());
                connection.setAbilities(setUpRequest.getAbilities());
                boolean rejectSdkOnStarting = metaInfo.isSdkSource() && !ApplicationUtils.isStarted();

                //ConnectionManager.register()方法,会将connectionId和连接对象进行绑定
                if (rejectSdkOnStarting || !connectionManager.register(connectionId, connection)) {
                    ...
                }
                ...
            }
            ...
        };
        return streamObserver;
    }
    ...
}

@Service
public class ConnectionManager extends Subscriber<ConnectionLimitRuleChangeEvent> {
    //存储connectionId对应的Connection对象
    Map<String, Connection> connections = new ConcurrentHashMap<>();
    ...
    //register a new connect.
    public synchronized boolean register(String connectionId, Connection connection) {
        if (connection.isConnected()) {
            if (connections.containsKey(connectionId)) {
                return true;
            }
            if (!checkLimit(connection)) {
                return false;
            }
            if (traced(connection.getMetaInfo().clientIp)) {
                connection.setTraced(true);
            }
            //将connectionId与Connection连接对象进行绑定
            connections.put(connectionId, connection);
            connectionForClientIp.get(connection.getMetaInfo().clientIp).getAndIncrement();
            //把Connection连接对象包装成Client对象
            clientConnectionEventListenerRegistry.notifyClientConnected(connection);
            Loggers.REMOTE_DIGEST.info("new connection registered successfully, connectionId = {},connection={} ", connectionId, connection);
            return true;
        }
        return false;
    }
    ...
}

@Service
public class ClientConnectionEventListenerRegistry {
    final List<ClientConnectionEventListener> clientConnectionEventListeners = new ArrayList<ClientConnectionEventListener>();
    //notify where a new client connected
    public void notifyClientConnected(final Connection connection) {
        for (ClientConnectionEventListener clientConnectionEventListener : clientConnectionEventListeners) {
            try {
                //调用ConnectionBasedClientManager.clientConnected()方法
                clientConnectionEventListener.clientConnected(connection);
            } catch (Throwable throwable) {
                Loggers.REMOTE.info("[NotifyClientConnected] failed for listener {}", clientConnectionEventListener.getName(), throwable);
            }
        }
    }
    ...
}

@Component("connectionBasedClientManager")
public class ConnectionBasedClientManager extends ClientConnectionEventListener implements ClientManager {
    private final ConcurrentMap<String, ConnectionBasedClient> clients = new ConcurrentHashMap<>();
    
    @Override
    public void clientConnected(Connection connect) {
        if (!RemoteConstants.LABEL_MODULE_NAMING.equals(connect.getMetaInfo().getLabel(RemoteConstants.LABEL_MODULE))) {
            return;
        }
        //把Connection对象中的信息取出来,放到ClientAttributes对象中
        ClientAttributes attributes = new ClientAttributes();
        attributes.addClientAttribute(ClientConstants.CONNECTION_TYPE, connect.getMetaInfo().getConnectType());
        attributes.addClientAttribute(ClientConstants.CONNECTION_METADATA, connect.getMetaInfo());
        //传入connectionId和连接信息
        clientConnected(connect.getMetaInfo().getConnectionId(), attributes);
    }
    
    @Override
    public boolean clientConnected(String clientId, ClientAttributes attributes) {
        String type = attributes.getClientAttribute(ClientConstants.CONNECTION_TYPE);
        ClientFactory clientFactory = ClientFactoryHolder.getInstance().findClientFactory(type);
        //这里的clientId就是connectionId,根据connectionId创建出Client对象
        return clientConnected(clientFactory.newClient(clientId, attributes));
    }
    
    @Override
    public boolean clientConnected(final Client client) {
        //最后将connectionId与Client对象进行绑定,放入到ConnectionBasedClientManager的clients这个Map中
        clients.computeIfAbsent(client.getClientId(), s -> {
            Loggers.SRV_LOG.info("Client connection {} connect", client.getClientId());
            return (ConnectionBasedClient) client;
        });
        return true;
    }
    ...
}

(3)总结

13.gRPC服务端如何映射各种请求与对应的Handler处理类

gRPC服务端会如何处理客户端请求,如何找到对应的Handler处理类。

在gRPC服务端启动时,会调用BaseGrpcServer的startServer()方法,其中就会执行到BaseGrpcServer的addServices()方法。在BaseGrpcServer的addServices()方法中,就会进行请求与Handler映射,也就是调用GrpcRequestAcceptor的request()方法进行请求与Handler映射。

在GrpcRequestAcceptor的request()方法中,首先会从请求对象中获取请求type,然后会通过请求type获取一个Handler对象,最后调用RequestHandler的模版方法handleRequest(),从而调用具体Handler对象的handle()方法。

//Grpc implementation as a rpc server.
public abstract class BaseGrpcServer extends BaseRpcServer {
    @Autowired
    private GrpcRequestAcceptor grpcCommonRequestAcceptor;
    ...
    private void addServices(MutableHandlerRegistry handlerRegistry, ServerInterceptor... serverInterceptor) {
        //unary common call register.
        final MethodDescriptor<Payload, Payload> unaryPayloadMethod = MethodDescriptor.<Payload, Payload>newBuilder()
            .setType(MethodDescriptor.MethodType.UNARY)
            .setFullMethodName(MethodDescriptor.generateFullMethodName(REQUEST_SERVICE_NAME, REQUEST_METHOD_NAME))
            .setRequestMarshaller(ProtoUtils.marshaller(Payload.getDefaultInstance()))
            .setResponseMarshaller(ProtoUtils.marshaller(Payload.getDefaultInstance())).build();

        //对gRPC客户端发出的请求进行Handler处理类的映射处理
        final ServerCallHandler<Payload, Payload> payloadHandler = ServerCalls.asyncUnaryCall((request, responseObserver) -> grpcCommonRequestAcceptor.request(request, responseObserver));
      
        //构建ServerServiceDefinition服务
        final ServerServiceDefinition serviceDefOfUnaryPayload = ServerServiceDefinition.builder(REQUEST_SERVICE_NAME).addMethod(unaryPayloadMethod, payloadHandler).build();

        //添加服务到gRPC的请求流程中
        handlerRegistry.addService(ServerInterceptors.intercept(serviceDefOfUnaryPayload, serverInterceptor));
    
        //bi stream register.
        //处理客户端连接对象的关联
        //也就是调用GrpcBiStreamRequestAcceptor.requestBiStream()方法对ConnectionId与Client对象进行绑定
        final ServerCallHandler<Payload, Payload> biStreamHandler = ServerCalls.asyncBidiStreamingCall((responseObserver) -> grpcBiStreamRequestAcceptor.requestBiStream(responseObserver));
    
        final MethodDescriptor<Payload, Payload> biStreamMethod = MethodDescriptor.<Payload, Payload>newBuilder()
            .setType(MethodDescriptor.MethodType.BIDI_STREAMING)
            .setFullMethodName(MethodDescriptor.generateFullMethodName(REQUEST_BI_STREAM_SERVICE_NAME, REQUEST_BI_STREAM_METHOD_NAME))
            .setRequestMarshaller(ProtoUtils.marshaller(Payload.newBuilder().build()))
            .setResponseMarshaller(ProtoUtils.marshaller(Payload.getDefaultInstance())).build();
    
        final ServerServiceDefinition serviceDefOfBiStream = ServerServiceDefinition.builder(REQUEST_BI_STREAM_SERVICE_NAME).addMethod(biStreamMethod, biStreamHandler).build();
        handlerRegistry.addService(ServerInterceptors.intercept(serviceDefOfBiStream, serverInterceptor));
    }
    ...
}

@Service
public class GrpcRequestAcceptor extends RequestGrpc.RequestImplBase {
    ...
    @Override
    public void request(Payload grpcRequest, StreamObserver<Payload> responseObserver) {
        ...
        //首先从请求对象中获取请求type
        String type = grpcRequest.getMetadata().getType();
        ...
        //然后通过请求type获取一个Handler对象
        RequestHandler requestHandler = requestHandlerRegistry.getByRequestType(type);
        ...
        //最后调用RequestHandler的模版方法handleRequest(),从而调用具体Handler对象的handle()方法
        Response response = requestHandler.handleRequest(request, requestMeta);
        ...
    }
    ...
}

public abstract class RequestHandler<T extends Request, S extends Response> {
    @Autowired
    private RequestFilters requestFilters;
    
    //Handler request.
    public Response handleRequest(T request, RequestMeta meta) throws NacosException {
        for (AbstractRequestFilter filter : requestFilters.filters) {
            try {
                Response filterResult = filter.filter(request, meta, this.getClass());
                if (filterResult != null && !filterResult.isSuccess()) {
                    return filterResult;
                }
            } catch (Throwable throwable) {
                Loggers.REMOTE.error("filter error", throwable);
            }
        }
        //调用具体Handler的handle()方法
        return handle(request, meta);
    }
    //Handler request.
    public abstract S handle(T request, RequestMeta meta) throws NacosException;
}

@Service
public class RequestHandlerRegistry implements ApplicationListener<ContextRefreshedEvent> {
    Map<String, RequestHandler> registryHandlers = new HashMap<String, RequestHandler>();
    
    @Autowired
    private TpsMonitorManager tpsMonitorManager;
    
    //Get Request Handler By request Type.
    public RequestHandler getByRequestType(String requestType) {
        return registryHandlers.get(requestType);
    }
    
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        //获取全部继承了RequestHandler类的实现类
        Map<String, RequestHandler> beansOfType = event.getApplicationContext().getBeansOfType(RequestHandler.class);
        Collection<RequestHandler> values = beansOfType.values();
        for (RequestHandler requestHandler : values) {
            Class<?> clazz = requestHandler.getClass();
            boolean skip = false;
            while (!clazz.getSuperclass().equals(RequestHandler.class)) {
                if (clazz.getSuperclass().equals(Object.class)) {
                    skip = true;
                    break;
                }
                clazz = clazz.getSuperclass();
            }
            if (skip) {
                continue;
            }
            try {
                Method method = clazz.getMethod("handle", Request.class, RequestMeta.class);
                if (method.isAnnotationPresent(TpsControl.class) && TpsControlConfig.isTpsControlEnabled()) {
                    TpsControl tpsControl = method.getAnnotation(TpsControl.class);
                    String pointName = tpsControl.pointName();
                    TpsMonitorPoint tpsMonitorPoint = new TpsMonitorPoint(pointName);
                    tpsMonitorManager.registerTpsControlPoint(tpsMonitorPoint);
                }
            } catch (Exception e) {
                //ignore.
            }
            Class tClass = (Class) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
            registryHandlers.putIfAbsent(tClass.getSimpleName(), requestHandler);
        }
    }
}

14.gRPC简单介绍

(1)gRPC是什么

(2)gRPC的特性

(3)gRPC和Dubbo的区别

(1)gRPC是什么

gRPC是一个高性能、开源和通用的RPC框架。gRPC基于ProtoBuf序列化协议开发,且支持众多开发语言。gRPC是面向服务端和移动端,基于HTTP 2设计的,带来诸如双向流、流控、头部压缩、单TCP连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。

(2)gRPC的特性

一.gRPC可以跨语言使用

二.基于IDL(接口定义语言Interface Define Language)文件定义服务

通过proto3工具生成指定语言的数据结构、服务端接口以及客户端Stub。

三.通信协议基于标准的HTTP 2设计

支持双向流、消息头压缩、单TCP的多路复用、服务端推送等特性,这些特性使得gRPC在移动端设备上更加省电和节省网络流量。

四.序列化支持ProtoBuf和JSON

ProtoBuf是一种语言无关的高性能序列化框架,它是基于HTTP2和ProtoBuf的,这保障了gRPC调用的高性能。

五.安装简单,扩展方便

使用gRPC框架每秒可达到百万RPC。

(3)gRPC和Dubbo的区别

一.通讯协议

gRPC基于HTTP 2.0,Dubbo基于TCP。

二.序列化

gRPC使用ProtoBuf,Dubbo使用Hession2等基于Java的序列化技术。

三.服务注册与发现

gRPC是应用级别的服务注册,Dubbo2.0及之前的版本都是基于更细力度的服务来进行注册,Dubbo3.0之后转向应用级别的服务注册。

四.编程语言

gRPC可以使用任何语言(HTTP和ProtoBuf天然就是跨语言的),而Dubbo只能使用在构建在JVM之上的语言。

五.服务治理

gRPC自身的服务治理能力很弱,只能基于HTTP连接维度进行容错,而Dubbo可以基于服务维度进行治理。

总结:gRPC的优势在于跨语言、跨平台,但服务治理能力弱。Dubbo服务治理能力强,但受编程语言限制无法跨语言使用。

JFM7VX690T型SRAM型现场可编程门阵列技术手册主要介绍的是上海复旦微电子集团股份有限公司(简称复旦微电子)生产的高性能FPGA产品JFM7VX690T。该产品属于JFM7系列,具有现场可编程特性,集成了功能强大且可以灵活配置组合的可编程资源,适用于实现多种功能,如输入输出接口、通用数字逻辑、存储器、数字信号处理和时钟管理等。JFM7VX690T型FPGA适用于复杂、高速的数字逻辑电路,广泛应用于通讯、信息处理、工业控制、数据中心、仪表测量、医疗仪器、人工智能、自动驾驶等领域。 产品特点包括: 1. 可配置逻辑资源(CLB),使用LUT6结构。 2. 包含CLB模块,可用于实现常规数字逻辑和分布式RAM。 3. 含有I/O、BlockRAM、DSP、MMCM、GTH等可编程模块。 4. 提供不同的封装规格和工作温度范围的产品,便于满足不同的使用环境。 JFM7VX690T产品系列中,有多种型号可供选择。例如: - JFM7VX690T80采用FCBGA1927封装,尺寸为45x45mm,使用锡银焊球,工作温度范围为-40°C到+100°C。 - JFM7VX690T80-AS同样采用FCBGA1927封装,但工作温度范围更广,为-55°C到+125°C,同样使用锡银焊球。 - JFM7VX690T80-N采用FCBGA1927封装和铅锡焊球,工作温度范围与JFM7VX690T80-AS相同。 - JFM7VX690T36的封装规格为FCBGA1761,尺寸为42.5x42.5mm,使用锡银焊球,工作温度范围为-40°C到+100°C。 - JFM7VX690T36-AS使用锡银焊球,工作温度范围为-55°C到+125°C。 - JFM7VX690T36-N使用铅锡焊球,工作温度范围与JFM7VX690T36-AS相同。 技术手册中还包含了一系列详细的技术参数,包括极限参数、推荐工作条件、电特性参数、ESD等级、MSL等级、重量等。在产品参数章节中,还特别强调了封装类型,包括外形图和尺寸、引出端定义等。引出端定义是指对FPGA芯片上的各个引脚的功能和接线规则进行说明,这对于FPGA的正确应用和电路设计至关重要。 应用指南章节涉及了FPGA在不同应用场景下的推荐使用方法。其中差异说明部分可能涉及产品之间的性能差异;关键性能对比可能包括功耗与速度对比、上电浪涌电流测试情况说明、GTH Channel Loss性能差异说明、GTH电源性能差异说明等。此外,手册可能还提供了其他推荐应用方案,例如不使用的BANK接法推荐、CCLK信号PCB布线推荐、JTAG级联PCB布线推荐、系统工作的复位方案推荐等,这些内容对于提高系统性能和稳定性有着重要作用。 焊接及注意事项章节则针对产品的焊接过程提供了指导,强调焊接过程中的注意事项,以确保产品在组装过程中的稳定性和可靠性。手册还明确指出,未经复旦微电子的许可,不得翻印或者复制全部或部分本资料的内容,且不承担采购方选择与使用本文描述的产品和服务的责任。 上海复旦微电子集团股份有限公司拥有相关的商标和知识产权。该公司在中国发布的技术手册,版权为上海复旦微电子集团股份有限公司所有,未经许可不得进行复制或传播。 技术手册提供了上海复旦微电子集团股份有限公司销售及服务网点的信息,方便用户在需要时能够联系到相应的服务机构,获取最新信息和必要的支持。同时,用户可以访问复旦微电子的官方网站(***以获取更多产品信息和公司动态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值