安庆大理运城常德铜陵江西
投稿投诉
江西南阳
嘉兴昆明
铜陵滨州
广东西昌
常德梅州
兰州阳江
运城金华
广西萍乡
大理重庆
诸暨泉州
安庆南充
武汉辽宁

当云原生网关遇上图数据库,NebulaGraph的APISI

8月20日 风雨峰投稿
  本文介绍了利用开源API网关APISIX加速NebulaGraph多个场景的落地最佳实践:负载均衡、暴露接口结构与TLSTermination。API网关介绍什么是API网关
  API网关是位于客户端和服务器之间的中间人,用于管理、监控和保护API。它可以在API之前执行一些操作,例如:身份验证、授权、缓存、日志记录、审计、流量控制、安全、防火墙、压缩、解压缩、加密、解密等。
  API网关可以工作在TCPIP4层和OSI7层。跑在7层的API网关可以使用多种协议,例如:HTTP、HTTPS、WebSocket、gRPC、MQTT等。在这些应用层协议中做一些操作,比如,请求的重写、转发、合并、重试、缓存、限流、熔断、降级、鉴权、监控、日志、审计等等。
  这里举例一下借助API网关可以做的具体的事:在网关层增加认证层,比如:JWT认证、OAuth2认证、OpenID认证等等,这样不需要在每个服务中都做具体的认证集成工作,进而节省许多开发成本。借助网关给跳板机SSH流量增加无需客户端修改的复杂认证,比如:跳转任何客户端的SSH登录,给出一个网址或者输入框,引导登陆者通过网页的SSO认证(包含多因素认证),再通过网关转发到SSH服务。甚至在网关层做Serverless数据库!TiDB社区的同学们就在做这个事儿,他们从普通的MySQL客户端的登录请求中解析能推断出转到需要的TiDB示例的信息,并且在需要coldstart唤醒实例的时候把连接保持住,可以参考这篇文章:TiDBGateway。如果你特别惨在维护屎山项目,不得不针对旧版本的应用程序对新版本的服务端进行兼容,这时候API网关也可以通过一些请求重写,把旧版本的请求转换成新版本的请求。
  只要脑洞大,理论上API网关可以做很多事。但显然不是所有的事情都是适合在这一层去做的,通常那些比较通用的事情才适合在这一层去做,上面我只是给出一些典型和极端的具体例子。ApacheAPISIX
  API网关是从LB、ReverseProxy项目演进过来的。随着云原生的兴起,API网关也逐渐成为了云原生的一部分,流行的开源网关有:NginxApacheAPISIXKongLuraOpenRestyTykTraefikIstioEnvoy
  而且其中很多都是基于NginxOpenResty的下游项目。这里就以ApacheAPISIX为例,介绍一下NebulaGraph借助API网关的几个实践。NebulaGraph介绍
  NebulaGraph是一个开源的分布式图数据库,它的特点是:高性能:可达到每秒百万级的读写,具有极高的扩展性,在千亿点、万亿边的数据规模下支持毫秒级的查询。易扩展:分布式的架构可在多台机器上扩展。每台机器上可以运行多个服务进程,它的查询层是无状态的计算存储分离架构,可以容易地引入不同配置、不同类型的计算层,实现同一集群上TP、AP、图计算等不同负载的混合查询。易使用:类SQL的原生查询语言,易于学习和使用,同时支持openCypher。丰富生态:NebulaGraph的生态系统正在不断壮大,目前已经有了多个客户端,包括Java、Python、Go、C、JavaScript、Spark、Flink等,同时也有了多个可视化工具,包括NebulaGraphStudio、NebulaGraphDashboard、NebulaGraphExplorer等。本文讨论的问题
  本文给出了基于NebulaGraph集群应用中涉及到API网关的几个场景。查询接口的负载均衡底层存储接口的暴露传输层的加密查询接口负载均衡
  首先是图数据库查询接口graphd的负载均衡与高可用的问题。
  NebulaGraph内核由三种服务组成:graphd、metad和storaged:
  所以,在默认情况下,集群只会暴露graphd的接口,提供给客户端连接,执行nGQL的查询。其中,graphd是无状态的,这意味着可以在多个graphd之间做负载均衡。这里,我们有两种方法:基于客户端的(ClientSideLB)与基于代理的。客户端的负载均衡
  客户端的负载均衡,就是在客户端,也就是应用程序中,实现负载均衡的逻辑。NebulaGraph的各个语言的客户端里边已经内置了轮询(RoundRobin)负载均衡,我们只需要在客户端配置多个graphd的地址就可以了。比如,我们在创建连接池的时候,指定了两个不同的graphd的地址(对应不同进程实例),下面以Python代码为例:fromnebula3。gclient。netimportConnectionPoolfromnebula3。ConfigimportConfigconfigConfig()config。maxconnectionpoolsize10connectionpoolConnectionPool()connectionpool。init(〔(127。0。0。1,9669),(127。0。0。1,49433)〕,config)
  在取得连接的时候,就会从连接池中随机取得一个连接:In〔10〕:connection0connectionpool。getconnection()In〔11〕:connection1connectionpool。getconnection()这两个连接的graphd地址是不同的In〔12〕:connection0。port,connection1。portOut〔12〕:(9669,49433)
  这种客户端负载均衡的问题在于配置、实现细节与应用代码耦合在一起,如果需要修改负载均衡的策略,就要修改应用代码,这样就会增加应用的复杂度。代理的负载均衡
  基于代理的负载均衡,就是在应用程序之前,增加一个代理层,来实现负载均衡的逻辑。这样,应用程序就不需要关心负载均衡的问题了。在K8s里的话,我们可以使用K8s的Service来实现这个代理层。
  这是一个在Minikube中为NebulaGraph集群中graphd创建的Service:catEOFkubectlcreatefapiVersion:v1kind:Servicemetadata:labels:app。kubernetes。iocluster:nebulaapp。kubernetes。iocomponent:graphdapp。kubernetes。iomanagedby:nebulaoperatorapp。kubernetes。ioname:nebulagraphname:nebulagraphdsvcnodeportnamespace:defaultspec:externalTrafficPolicy:Localports:name:thriftport:9669protocol:TCPtargetPort:9669nodePort:30000name:httpport:19669protocol:TCPtargetPort:19669nodePort:30001selector:app。kubernetes。iocluster:nebulaapp。kubernetes。iocomponent:graphdapp。kubernetes。iomanagedby:nebulaoperatorapp。kubernetes。ioname:nebulagraphtype:NodePortEOF
  创建后,我们就可以通过它暴露的单独端口来访问NebulaGraph集群中的graphd了:In〔13〕:connectionpoolConnectionPool()。。。:connectionpool。init(〔(192。168。49。2,9669)〕,config)Out〔13〕:TrueIn〔14〕:connection0connectionpool。getconnection()In〔15〕:connection1connectionpool。getconnection()In〔16〕:connection0。ip,connection1。ipOut〔16〕:(192。168。49。2,192。168。49。2)
  可以看到,在连接层面上来看,客户端只知道代理的地址,而不知道NebulaGraph集群中的graphd的地址,这样就实现了客户端与NebulaGraph集群中的graphd的解耦。
  然而,当我们在Connection之上创建Session的时候,就能看到实际上客户端的不同请求是落在了不同的graphd上的:In〔17〕:sessionconnectionpool。getsession(root,nebula)In〔18〕:session。sessionidOut〔18〕:1668670607568178In〔19〕:session1connectionpool。getsession(root,nebula)In〔20〕:session1。sessionidOut〔20〕:1668670625563307得到每一个session的IDIn〔21〕:session。execute(SHOWSESSIONS)它们分别对应了两个不同的graphd实例Out〔21〕:ResultSet(keys:〔SessionId,UserName,SpaceName,CreateTime,UpdateTime,GraphAddr,Timezone,ClientIp〕,values:〔1668670607568178,root,,utcdatetime:20221117T07:36:47。568178,timezoneoffset:0,utcdatetime:20221117T07:36:47。575303,timezoneoffset:0,nebulagraphd0。nebulagraphdsvc。default。svc。cluster。local:9669,0,172。17。0。1〕,〔1668670625563307,root,,utcdatetime:20221117T07:37:05。563307,timezoneoffset:0,utcdatetime:20221117T07:37:03。638910,timezoneoffset:0,nebulagraphd1。nebulagraphdsvc。default。svc。cluster。local:9669,0,172。17。0。1〕)底层存储接口的暴露
  在NebulaGraph中,可以通过StorageClient来访问底层的存储接口,这个接口可以用来做一些分析型、数据全扫描计算的工作。
  然而,存储层的分布式服务实例不像graphd那样,它们是有状态的。这其实与K8s或者DockerCompose的部署模型是相违背的。如果访问的应用storaged客户端在集群外部,我们需要在NebulaGraph集群中的每一个存储实例上都部署一个代理Service。这非常不方便,有时候还是一种浪费。
  此外,由于NebulaGraph内部服务发现机制和storaged客户端的实现机制决定,每一个storaged服务实体都是由其内部的host:port唯一确定和寻址的,这给我们中间的代理工作也带来了一些麻烦。
  总结来看,我们的需求是:能够从集群外部访问NebulaGraph的存储层每一个实例每一个实例的访问地址(host:port)和内部的地址是完全一致的
  为了实现这个需求,我之前的做法是为每一个实例单独部署一个graphd代理(消耗一个地址,保证端口不变),再在外部手动搭一个Nginx作为代理,配合DNS把内部的地址解析Nginx上,然后通过域名找到上游(每一个单独的graphd代理)。本文的延伸阅读1、2中给出了相关的实验步骤。
  最近,我找到了一个相对优雅的可维护的方式:在NebulaGraph集群同一个命名空间下引入一个APISIX网关;利用APISIX中的NginxTCP代理的封装streamproxy来暴露storaged的接口;为了最终只利用一个集群的出口(Service,我们利用其支持的TLSv1。3中的extendhostname字段:SNI来路由上游),做到用不同域名的TCPoverTLS指向后端的不同只需要Storage客户端能支持TLSv1。3(发送SNI),并且能解析所有storaged的地址到APISIX的Service上即可;
  示例图:K8sClusterNebulaGraphClusterAPISIXAPIGATEWAYstoraged0streamproxy。。addr:9559storaged1DNS(Service)tls:true。,SNIstoraged2storaged3
  这样做的好处是:在APISIX中比较优雅地维护代理的配置,并且可以用到APISIX现代化的流量管理能力;不需要为每一个storaged单独创建Service,只需要一个Service、集群地址就可以了;为流量增加了TLSv1。3的加密,提高了安全性。同时,没有给NebulaGraph集群内部的南北流量带来的性能损耗;
  在本文的结尾,给出了实验过程,包含了本文提到的所有要点和细节。传输层的加密
  我们在前一个问题中提及到了,在APISIX网关中terminateTLSv1。3的连接,借助SNI信息路由storaged的方法。其实,单独将graphd接口的TLS交给网关来做,好处也是非常明显的:证书管理在统一的网关控制面做,更加方便;证书运维无NebulaGraph集群配置侵入(NebulaGraph原生支持TLS加密,但是加密之后带来了集群内部通信的开销,而且配置和集群其他层面配置在一起,证书更新涉及进程重启,不够灵活);
  具体的方法在后边实操中也是有体现的。实操:利用APISIX的streamproxy暴露storaged的接口实验环境:Minikube
  本实验在本地的Minikube上做。首先,启动一个Minikube。因为APISIX内部的etcd需要用到storageclass,我们带上穷人版的storageclass插件。同时,为了在K8s外部访问storaged的时候用和内部相同的域名和端口,将把nodeport允许的端口扩充到小于9779的范围。addonsdefaultstorageclassextraconfigapiserver。servicenodeportrange165535实验环境:NebulaGraphonK8s
  这里,我们使用NebulaOperator来部署NebulaGraph集群,具体的部署方法可以参考NebulaOperator文档:https:docs。nebulagraph。com。cn3。3。0nebulaoperator1。introductiontonebulaoperator。
  咱们做实验,就偷个懒,用我写的NebulaOperatorKinD来一键部署:curlsLnebulakind。siwei。ioinstallonK8s。shbash实验环境:APISIXonK8s
  首先,是安装。在Helm参数中指定打开streamproxy的开关:helmrepoaddapisixhttps:charts。apiseven。comhelmrepoaddbitnamihttps:charts。bitnami。combitnamihelmrepoupdatehelminstallapisixapisixapisixsetgateway。typeNodePortsetgateway。stream。enabledtruesetingresscontroller。enabledtruedashboard也装上,方便我们绕过adminAPIcall做一些方便的操作。helminstallapisixdashboardapisixapisixdashboard
  因为截止到现在,APISIX的HelmChart之中并没有提供streamproxyTCP的监听端口的TLS支持的配置格式,见:https:github。comapacheapisixhelmchartissues348。我们需要手动更改APISIX的ConfigMap,把streamproxy的TLS配置加上:kubectleditConfigMapapisix
  我们编辑把streamproxy。tcp改写成这样:streamproxy:TCPUDPproxyonly:falsetcp:TCPproxyportlistaddr:9779tls:trueaddr:9559tls:true
  这里我们需要重建APISIXPod,因为APISIX的streamproxy的TLS配置是在启动的时候加载的,所以我们需要重建APISIXPod:kubectldelete(kubectlgetpolapp。kubernetes。ionameapisixoname)开始实验
  这个实验的目标是把NebulaGraph的storaged的接口暴露出来,让外部的客户端可以访问到,而暴露的方式如图:K8sClusterNebulaGraphClusterAPISIXAPIGATEWAYstoraged0streamproxy。。addr:9559storaged1DNS(Service)tls:true。,SNIstoraged2storaged3
  我们已经有了所有的框架,我们要往里填箭头和圆圈就行。kubectlgetpoNAMEREADYSTATUSRESTARTSAGEapisix6d89854bc55m78811Running1(31hago)2d4hapisixdashboardb544bd766nh79j11Running8(31hago)2d10hapisixetcd011Running2(31hago)2d10hapisixetcd111Running2(31hago)2d10hapisixetcd211Running2(31hago)2d10hnebulagraphd011Running2(31hago)3d4hnebulametad011Running2(31hago)3d4hnebulastoraged011Running2(31hago)3d4hnebulastoraged111Running2(31hago)3d4hnebulastoraged211Running2(31hago)3d4h配置APISIX的streamproxy
  参考APISIX文档:https:apisix。apache。orgdocsapisixstreamproxyaccepttlsovertcpconnection。
  我们用APISIX的API来配置streamproxy:apisixapikeyedd1c9f034335f136f87ad84b625c8f1apisixpod(kubectlgetpolapp。kubernetes。ionameapisixoname)kubectlexecitapisixpodcurlhttp:127。0。0。1:9180apisixadminstreamroutes1HXAPIKEY:apisixapikeyXPUTd{sni:nebulastoraged0。nebulastoragedheadless。default。svc。cluster。local,upstream:{nodes:{172。17。0。13:9779:1},type:roundrobin}}kubectlexecitapisixpodcurlhttp:127。0。0。1:9180apisixadminstreamroutes2HXAPIKEY:apisixapikeyXPUTd{sni:nebulastoraged1。nebulastoragedheadless。default。svc。cluster。local,upstream:{nodes:{172。17。0。18:9779:1},type:roundrobin}}kubectlexecitapisixpodcurlhttp:127。0。0。1:9180apisixadminstreamroutes3HXAPIKEY:apisixapikeyXPUTd{sni:nebulastoraged2。nebulastoragedheadless。default。svc。cluster。local,upstream:{nodes:{172。17。0。5:9779:1},type:roundrobin}}
  这里需要注意,目前,APISIX的streamproxy上游节点不支持域名解析是受限于上游的lua库,详见issue:https:github。comapacheapisixissues8334。理想情况下,这里应该给出每一个storaged的SNI相同的地址作为upstream。nodes。像这样:kubectlexecitapisixpodcurlhttp:127。0。0。1:9180apisixadminstreamroutes1HXAPIKEY:apisixapikeyXPUTd{sni:nebulastoraged0。nebulastoragedheadless。default。svc。cluster。local,upstream:{nodes:{nebulastoraged0。nebulastoragedheadless。default。svc。cluster。local:1},type:roundrobin}}配置APISIX中storaged地址的TLS证书
  在生产环境下,我们应该以云原生的方式去管理自签或者公共信任的证书。这里,我们就手动利用MKCert工具来做这件事儿。
  安装MKCert:首次运行,需要安装mkcert,并且生成根证书macOS的话brewinstallmkcertubuntu的话aptgetinstallwgetlibnss3tools然后再去https:github。comFiloSottilemkcertreleases下载mkcert
  签发证书:mkcert。nebulastoragedheadless。default。svc。cluster。local
  利用APISIXDashboard将证书导入到APISIX之中。单独开一个终端,运行:exportPODNAME(kubectlgetpodslapp。kubernetes。ionameapisixdashboard,app。kubernetes。ioinstanceapisixdashboardojsonpath{。items〔0〕。metadata。name})exportCONTAINERPORT(kubectlgetpodPODNAMEojsonpath{。spec。containers〔0〕。ports〔0〕。containerPort})kubectlportforwardPODNAME8080:CONTAINERPORTaddress0。0。0。0
  浏览器访问:http:10。1。1。168:8080ssllist,账号密码都是admin。点击Create按钮,将刚刚生成的证书导入到APISIX之中。
  增加APISIX的NodePortService
  创建一个NodePortService,用于暴露APISIX的9779端口。这样,我们就可以通过外部的IP地址访问到APISIX了。catEOFkubectlapplyfspec:selector:app。kubernetes。ioinstance:apisixapp。kubernetes。ioname:apisixports:protocol:TCPport:9779targetPort:9779name:thriftnodePort:9779type:NodePortEOF
  因为前边Minikube中我们配置了端口的范围覆盖到了9779,所以我们可以看到,这个NodePortService的端口在宿主机上也可以从Minikubeip的同一个端口访问到:minikubeserviceapisixsvcminikubeservicelistNAMESPACENAMETARGETPORTURL。。。defaultapisixsvcthrift9779http:192。168。49。2:9779。。。
  当然,Minikube假设我们的服务都是HTTP的,给出的URL是HTTP:的。不用理会它,我们心里知道它是TCPoverTLS就好了。配置K8s外部DNS
  这里需要配置一个DNS服务,让我们可以通过nebulastoraged0。nebulastoragedheadless。default。svc。cluster。local等三个域名通过Minikube的NodePortService访问到NebulaGraph的storaged服务。
  获得Minikube的IP地址:minikubeip192。168。49。2
  配置etchosts192。168。49。2nebulastoraged0。nebulastoragedheadless。default。svc。cluster。local192。168。49。2nebulastoraged1。nebulastoragedheadless。default。svc。cluster。local192。168。49。2nebulastoraged2。nebulastoragedheadless。default。svc。cluster。local192。168。49。2nebulametad0。nebulametadheadless。default。svc。cluster。local验证NebulaGraphStorageClient可以从所有的节点中获取到数据
  这里,为了方便,我们用到Python的客户端。
  由于在写本文的时候,NebulaGraphPython客户端的StorageClient尚未支持TLS,对它支持的PR刚好是我为了本实验写的:https:github。comvesoftincnebulapythonpull239。
  所以,这里从个人分支安装这个客户端:gitclonehttps:github。comweygunebulapython。gitcdnebulapythonpython3mpipinstall。python3mpipinstallipython进入ipythonipython
  我们在iPython中交互式验证:fromnebula3。mclientimportMetaCache,HostAddrfromnebula3。sclient。GraphStorageClientimportGraphStorageClientfromnebula3。ConfigimportSSLconfigimportsslimportosmetacacheMetaCache(〔(nebulametad0。nebulametadheadless。default。svc。cluster。local,9559)〕,50000)storageaddrs〔HostAddr(hostnebulastoraged0。nebulastoragedheadless。default。svc。cluster。local,port9779),HostAddr(hostnebulastoraged1。nebulastoragedheadless。default。svc。cluster。local,port9779),HostAddr(hostnebulastoraged2。nebulastoragedheadless。default。svc。cluster。local,port9779)〕自签证书配置currentdiros。path。abspath(。)sslconfigSSLconfig()sslconfig。certreqsssl。CERTOPTIONALsslconfig。certreqsssl。CERTOPTIONALsslconfig。cacertsos。path。join(os。path。expanduser(。localsharemkcert),rootCA。pem)sslconfig。keyfileos。path。join(currentdir,nebulastoragedheadless。default。svc。cluster。local1key。pem)sslconfig。certfileos。path。join(currentdir,nebulastoragedheadless。default。svc。cluster。local1。pem)实例化StorageClientgraphstorageclientGraphStorageClient(metacache,storageaddrs,5000,sslconfig)验证可以从所有的节点中获取到数据respgraphstorageclient。scanvertex(spacenamebasketballplayer,tagnameplayer)whileresp。hasnext():resultresp。next()forvertexdatainresult:print(vertexdata)
  结果:(player112:player{name:JonathonSimmons,age:29})(player117:player{name:StephenCurry,age:31})(player119:player{name:KevinDurant,age:30})(player134:player{name:BlakeGriffin,age:30})(player141:player{name:RayAllen,age:43})(player144:player{name:ShaquilleONeal,age:47})(player149:player{name:BenSimmons,age:22})(player100:player{name:TimDuncan,age:42})(player101:player{name:TonyParker,age:36})(player110:player{name:CoryJoseph,age:27})(player126:player{name:KyrieIrving,age:26})(player131:player{name:PaulGeorge,age:28})(player133:player{name:YaoMing,age:38})(player140:player{name:GrantHill,age:46})(player105:player{name:DannyGreen,age:31})(player109:player{name:TiagoSplitter,age:34})(player111:player{name:DavidWest,age:38})。。。总结NebulaGraph查询接口的负载均衡可以借助K8sService来做;NebulaGraph底层存储接口的暴露在K8s中可以利用APISIXStreamProxy和SNI来优雅实现;利用API网关对出口传输层的加密是一个很好的选择,相较于用NebulaGraph原生的TLS的方式。一些坑
  fbthriftPython并不支持发送extendhostname(SNI):https:github。comvesoftincnebulapythonpull238,写了PR去做支持。这时候APISIX中的报错是failedtofindSNI:2022111510:18:26〔error〕7878:1744270stream〔lua〕init。lua:842:streamsslphase():failedtofetchsslconfig:failedtofindSNI:pleasecheckiftheclientrequestsviaIPorusesanoutdatedprotocol。Ifyouneedtoreportanissue,provideapacketcapturefileoftheTLShandshake。,context:sslcertificatebylua,client:172。17。0。1,server:0。0。0。0:9779
  参考延伸阅读的36。
  此外,我还发现APISIXstream里边不解析上游node域名,我查了所有DNS都没有问题,去提了issue才知道是已知问题:https:github。comapacheapisixissues8334,只好先手配IP:Port作罢。2022111512:26:59〔error〕4444:9538531stream〔lua〕resolver。lua:47:parsedomain():failedtoparsedomain:nebulastoraged0。nebulastoragedheadless。default。svc。cluster。local,error:failedtoquerytheDNSserver:dnsclienterror:101emptyrecordreceivedwhileprereadingclientdata,client:172。17。0。1,server:0。0。0。0:97792022111512:26:59〔error〕4444:9538531stream〔lua〕upstream。lua:79:parsedomainfornodes():dnsresolverdomain:nebulastoraged0。nebulastoragedheadless。default。svc。cluster。localerror:failedtoquerytheDNSserver:dnsclienterror:101emptyrecordreceivedwhileprereadingclientdata,client:172。17。0。1,server:0。0。0。0:97792022111512:26:59〔error〕4444:9538531stream〔lua〕init。lua:965:streamprereadphase():failedtosetupstream:novalidupstreamnodewhileprereadingclientdata,client:172。17。0。1,server:0。0。0。0:9779延伸阅读https:gist。github。comweygu950e4f4c673badae375e59007d80d372https:gist。github。comweygu699b9a2ef5dff5f0fb5f288d692ddfd5https:docs。python。org3libraryssl。htmlssl。SSLContext。sslsocketclasshttps:github。comapachethriftcommit937228e030569bf25ceb379c9491426709792701https:github。comapachethriftpull894https:github。comapachethriftblobe8353cb46e9f5e71f9b76f55d6bf59530b7f98eflibpysrctransportTSSLSocket。pyL184
  谢谢你读完本文()
  要来近距离体验一把图数据库吗?现在可以用用NebulaGraphCloud来搭建自己的图数据系统哟,快来节省大量的部署安装时间来搞定业务吧NebulaGraph阿里云计算巢现30天免费使用中
  想看源码的小伙伴可以前往GitHub阅读、使用、()star它GitHub:https:github。comvesoftincnebula
投诉 评论 转载

思考的人一实现你的荣光与梦想优秀的人物,伟大的人物,首先都是伟大的梦想家。是伟大的梦想指引成就了他们卓越的人生、光辉的事业。如果你想在这个世界上出人头地,那么,首先就要做一个伟大的梦想家!梦想……黑洞内部有什么?宇宙的生命是有限的?科学家给出答案黑洞宇宙中最狂暴,但又最迷人的天体,它似乎包含了宇宙的终极奥秘。但很多人不知道的是,黑洞第一次被发现,不是观测到的,而是由一名哲学家推断出来的,这个人就是英国的哲学家约翰……银行和支付宝相比,五万元能放银行吗?三大原因告诉你五万元当然是放银行好,绝对不放支付宝,理由特别简单,把钱放银行安全性高,保障性更强,收益率也比较乐观,支付宝里面投资理财五花八门,很容易本金亏损。银行老百姓都是非常熟悉的……当云原生网关遇上图数据库,NebulaGraph的APISI本文介绍了利用开源API网关APISIX加速NebulaGraph多个场景的落地最佳实践:负载均衡、暴露接口结构与TLSTermination。API网关介绍什么是API网关……退休的马云,为啥选择东京定居马云定居东京,这是风清扬的命中注定吗?近日啊,英国的金融时报曝光了一件大事儿,那就是咱们中国的电商大佬马云现在定居东京了。要知道,其实早在2016年,马云就获得了联合国授……大作不断,索尼StateOfPlay直面会内容汇总2022年9月14日索尼发布了一场长约20分钟的直面会公布了不少游戏的全新情报已经PSVR2的游戏。下面就让我们一起看看重点值得关注的游戏吧!倍受索粉期待的《战神诸神黄昏……耶鲁大学新线索揭示人类大脑独特性8月25日,耶鲁大学基因学与精神卫生学教授内纳德塞斯坦(NenadSestan)等人发表文章,为揭示人类大脑究竟与其他灵长类有何不同提供了新线索。研究者们使用单细胞转录组测序技……你最近看书了吗?读不读书和成功的关系你最近看书了吗?当有人问这个问题的时候,不少人会因为自己不读书而感到焦虑。很多人并不是真正焦虑自己没有读书这件事情,而是因为他们理所当然的认为读书和成功是直接相关的……方舟生存进化玩家最快发育的办法,潜入海底寻得宝藏作为Steam上的一款生存沙盒游戏,在《方舟:生存进化》中玩家是有不少能够快速发育的办法的,其中之一就是潜入海底,寻找到海底宝箱。由于《方舟:生存进化》的海底世界和现实一样,玩……快报阿森纳,纽卡斯尔与尤文图斯将竞争本菲卡后卫TuttoJuve据报道,亚历克斯格里马尔多(AlexGrimaldo)是阿森纳和纽卡斯尔的一月份转会目标,尤文图斯也潜在其中。这名本菲卡后卫的合同进入最后一年。葡萄牙豪……CBA三消息上海强援开始隔离,深圳小外援公布,江苏榜眼受质疑大家好呀,我是北柠,各位小伙伴们要养成先赞后看的习惯哦!上海队这个休赛期的外援工作早早就已经开始进行了,球队原本想要留下大外援冯莱,上海队选择使用了冯莱的优先续约权,但是……三分王满血归来!湖人为他放弃欧文值得吗?篮网三巨头已给出答案近日,据《华尔街日报》房地产板块报道,湖人后卫拉塞尔威斯布鲁克已经将在他洛杉矶的豪宅挂牌出售,要价约3000万美元。这个消息一出马上引起了球迷的热议,不少人相信这是威少即将被交……
鲁医生固然不对,熊孩子谁之过?香橙派OrangePiZero烧录Armbian避坑教程杨子钰妈妈哭诉离婚视频已删除,账号中的另一段视频疑似意有所指为什么有些人恨不得华为赶紧倒闭?明年一季度恢复国际线?新加坡扩大开放,日本机票预定量大增5倍DOTA2液体已然锁定major名额,新赛季暗流涌动凌晨5点!大巴黎做出重要决定国米遭毁灭打击,球迷吐槽声一片男人过了60岁,早晨养成这几个习惯,一般都会长寿天籁系列Fi音响新概念医生说火锅甜点这些高热量饮食都是导致尿酸高的原因医疗医药医美将成就510倍抱团行情人工智能行业人才走俏,深圳平均34。24万元年薪稳居行业第一洪水后灾区如何预防传染病?郝伟也保不了他了,关系户将被泰山队放弃,可能会面临失业的危险土地使用权赠与合同不履行合同诉讼书范文内容是什么?实用春节风俗习惯作文300字四篇藏在电话里的爱我的新发现少年强则国强演讲稿三篇生活知识科普鹅蛋能和鸡蛋一起吃吗战国策《鲁共公择言》原文、翻译及鉴赏贺生日作文一个岁小萝莉如何拯救百万非洲儿童轰动全世界

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找七猫云易事利