网易传媒Go语言探索服务器key调用

网易传媒于2020年将核心业务全部迁入容器,并将在线业务和离线业务混部,CPU利用率提升到了50%以上,取得了较大的收益,但在线业务方面,接入容器后仍存在一些问题:

Go语言于2009年由Google推出,经过了10多年的发展,目前已经有很多互联网厂商都在积极推进Go语言应用,网易传媒于2020年底开始尝试Go语言的探索,用于解决内存资源使用率偏高,编译速度慢等问题。本文将详细描述传媒在Go语言方面的所做的工作。

Go语言介绍

但是瑕不掩瑜,下面就来谈谈Go语言有哪些特性吸引我们去使用。

编译速度快

这种特性的主要原因官方文档里已经提到了:Go编译模型让依赖分析更简单,避免类C语言头文件和库的很多开销。不过这个也引入了一个束缚——包之间无法递归依赖,如果遇到类似的问题只能通过提取公共代码或者在外部初始化包等等方式来解决。

语法简单

像动态语言一样开发

使用过动态语言的应该接触过下面这种Python代码:

defbiu(toy):toy.roll()

o=new_ball()roll(o)

roll函数可以传入任何类型的对象,这种动态语言特征使开发及其灵活方便。但是大家可能都听说过“动态一时爽,重构火葬场”的名言,类似的实现会给其它维护者造成巨大的障碍,如果不是这个原因Python3也就不会加入typehints的特性了。

typeReadIFinterface{Read()}typeWriteIFinterface{Write()}typeReadWriteIFinterface{ReadIFWriteIF}

接下来使用这个interface,注意只要一个对象的类型满足interface里的全部函数,就说明匹配上了。

funcrw(iReadWriteIF){i.Read()i.Write()}typeFilestruct{}func(*File)Read(){}func(*File)Write(){}rw(&File{})

可以看到rw函数根本没有固定传入参数的具体类型,只要对象满足ReadWriteIF即可。

如果希望一个函数能像脚本语言一样接受任何类型的参数,你还可以使用interface{}作为参数类型,比如标准库的fmt.Print系列函数就是这样实现的。

资源消耗少

Go与C/C++消耗的CPU差距不大,但由于Go是垃圾回收型语言,耗费的内存会多一些。由于当前目标是使用Go取代Java,这里就将Go与同为垃圾回收型语言的Java简单比较一下。

Java当年诞生时最大的卖点之一是“一次编写,到处运行”。这个特性在20年前很棒,因为市场上几乎没有虚拟化解决方案。但是到了今天出现了Docker之类一系列跨平台工具,这种卖点可能被看做一种短板,主要原因如下:

为并发IO而生

练习过开发网络库的读者可能都知道Unix的epoll系统调用,如果了解Windows应该听说过IOCP,这两种接口分别对应网络的Reactor和Proactor模式。简单来说前者是同步的事件驱动模型,后者是异步IO。不论你使用任何语言只要涉及到高性能并发IO都逃不过这两种模式开发的折磨——除了Go。

为了展示使用Go开发并发IO有多么简单,我先从大家熟悉的普通程序的线程模型讲起。下图是一个常见的程序线程图,一般来说一个服务进程包含main、日志、网络、其他外部依赖库线程,以及核心的服务处理(计算)线程,其中服务线程可能会按CPU核数配置开启多个。

服务启动后RPC请求到来,此请求的发起端可能是客户端或者另一个服务,那么它在服务线程处理过程中将阻塞并等待回复事件。注意这里的RPC包含广义上的网络协议,比如HTTP、Redis、数据库读写操作都属于RPC。

此时的情况就如下图所示,服务调用端的请求要经过网络往返和服务计算的延迟后才能获得结果,而且服务端很可能还需要继续调用其它服务。

大多数开发者都会想:反正调用一般也就几十毫秒嘛,最多到秒级,我开个线程去同步等待回复就行,这样开发最方便。于是情况就会变成下图这样,每个请求占用一个连接和一个线程。如果网络和计算延迟加大,要保持服务器性能被充分利用,就需要开启更多的连接和线程。

为了偷懒我们倾向于避免使用Reactor和Proactor模式,甚至都懒得去了解它们,就算有人真的希望优化并发IO,类似Jedis这种只支持同步IO的库也能阻止他。

现在有Go能拯救我们了,在Go里没有线程的概念,你只需要知道使用go关键字就能创建一个类似线程的goroutine。Go提供了用同步的代码来写出异步接口的方法,也就是说我们调用IO时直接像上图期望的一样开发就行,Go在后台会调用epoll之类的接口来完成事件或异步处理。这样就避免了把代码写得零碎难懂。下面展示一个简单的RPC客户端例子,RPC调用和后续的计算处理代码可以顺畅地写在一起放入一个goroutine,而这段代码背后就是一个epoll实现的高性能并发IO处理:

funcprocess(client*RPCClient){response:=client.Call()//阻塞compute(response)//CPU密集型业务}

funcmain(){client:=NewRPCClient()fori:=0;i<100;i++{goprocess(client)}select{}//死等}

服务器的代码更简单,不需要再去监听事件,当获取到一个IO对象时,只要使用go就能在后台开启一个新的处理流程。

listener:=Listen("127.0.0.1:8888")for{conn:=listenser.Accept()//阻塞直至连接到来gofunc(){//对每个连接启动一个goroutine做同步处理for{req:=conn.Read()gofunc(){//将耗时处理放入新的goroutine,不阻塞连接的读取res:=compute(req)conn.Write(res)}()}}()}

注意go创建的goroutine相当于将IO读写和事件触发拼接起来的一个容器,消耗的内存非常小,所有goroutine被Go自动调度到有限个数的线程中,运行中切换基本是使用epoll的事件机制,因此这种协程机制可以很迅速启动成千上万个而不太消耗性能。

可运维性好

随着虚拟化技术发展,类似JVM的服务成为了一种累赘;因为磁盘空间大小不再是问题,动态库带来的兼容问题也层出不穷,因此它也在慢慢淡出视野。

Go是一种适应分布式系统和云服务的语言,所以它直接将静态编译作为默认选项,也就是说编译之后只要将可执行文件扔到服务器上或者容器里就能没有任何延迟地运行起来,不需要任何外部依赖库。

此外Go的项目只要在编译时修改参数,就能交叉编译出其他任意支持平台所需的二进制文件。比如我几乎完全在macOS上开发,当需要在linux服务器上测试则使用如下命令编译:

GOOS=linuxGOARCH=amd64gobuild./...

Go支持android、darwin、freebsd、linux、windows等等多种系统,包括386、amd64、arm等平台,绝大部分情况下你可以在自己的笔记本上调试任意系统平台的程序。

与C/C++兼容

由于没有虚拟机机制,Go可以与C语言库比较轻易地互相调用。下面是一个简单的例子,直接在Go中调用C语句:

/*#includevoidmyprint(){printf("hi~");}*/

import"C"C.myprint()

如果使用Go编写一个接口,然后使用gobuild-buildmode=c-shared编译,这样就能得到一个动态库和一个.h头文件,怎么使用就无需再解释了吧。

统一而完备的工具集

Go作为工程语言而设计,它的目标就是统一,即使一个团队有多种风格的开发者,他们的流程和产出最终都需要尽量保持一致,这样协同开发效率才会高。为了保证各方面的统一,Go提供了多种工具,安装以后执行go命令就能直接使用。

2

Ngo框架介绍

背景

在传媒技术团队中推广Go语言,亟需一个Web框架提供给业务开发同事使用,内含业务开发常用库,避免重复造轮子影响效率,并且需要无感知的自动监控数据上报,于是就孕育出Ngo框架。

选型

由于Go的开源Web框架没有类似SpringBoot大而全的,而最大的框架也是很受用户欢迎的框架是Beego,为什么没有直接使用Beego呢?主要有以下几个原因:

目标

Ngo是一个类似JavaSpringBoot的框架,全部使用Go语言开发,主要目标是:

注:哨兵是网易杭研运维部开发的监控系统,提供实时数据分析、丰富的监控指标和直观的报表输出。

主要功能模块

Ngo避免重复造轮子,所有模块都是在多个开源库中对比并挑选其一,然后增加部分必需功能,使其与Java系接口更接近。整个业务服务的架构如下图所示:

HTTPServer

funcmain(){s:=server.Init()s.AddRoute(server.GET,"/hello",func(ctx*gin.Context){ctx.JSON(protocol.JsonBody("hello"))})s.Start()}优雅停机

服务健康检查接口包括4个/health下的对外HTTP接口:

MySQLORM

使用gorm实现MySQLORM的功能,并在之上提供以下功能:

日志

使用logrus实现日志接口,并提供以下功能:

级别包含以下几种:

如果未设置级别,被被默认设置为info。非测试状态不要开启debug,避免日志过多影响性能。

另外在日志输出时可以使用WithField或WithFields来字段的key-value,在创建子日志对象时可以用来清晰地辨认日志的使用范围,但平时尽量不要使用。另外如果要输出error也尽量避免使用字段,直接使用Error()方法输出为字符串是最快的。

Redis

Redis客户端选择go-redis实现。同样只需在配置中提供Redis服务配置,即可在运行中直接使用GetClient获取指定名字的客户端。其支持client、cluster、sentinel三种形式的Redis连接,且都能自动上报哨兵监控数据。

Kafka

Kafka客户端在sarama基础上实现,由于原始接口比较复杂,业务需求一般用不上,Ngo中对其进行了较多的封装。在配置文件中增加kafka段,Ngo即会自动按配置生成生产者和消费者。

生产者只需调用func(p*Producer)Send(messagestring)传入字符串即可上报数据,无需关心结果。此接口是异步操作,会立即返回。如果出错,后台会重试多次,并将最后的结果记录上传到哨兵监控。

Kafka消费者只需这样调用Start注册处理函数即可工作:

consumer.Start(func(message*sarama.ConsumerMessage){//消费代码})HTTPClient

RPC

由于gRPC的使用比较复杂,而且性能与Go标准库的RPC差距不大,因此当前RPC库在Go标准库的基础上开发,并在之上增加连接池、连接复用、错误处理、断开重连、多host支持等功能。在使用上接口与标准库基本一致,因此没有学习成本。

至于使用RPC而不只限制于HTTP的主要原因,一是基于TCP的RPC运行多请求复用连接,而HTTP需要独占连接;二是HTTP在TCP之上实现,header占据了大量overhead,特别在小请求中是不必要的开销。在Ngo的两个库下自带性能测试,运行gotest-bench.就能查看结果,两者都使用20*CPU的并发量,模拟1ms、5ms、50ms的服务器网络和计算延迟,具体结果如下:

配置

配置模块使用viper实现,但用户无需调用配置模块的接口,在每个模块如Redis、Kafka、日志中都会被Ngo自动注入配置,用户只需写好yaml文件即可。

服务需要提供-cconf参数来指定配置文件,启动时,会依次加载以下配置:

配置文件范例如下:

哨兵模块的目的是提供统一且易扩展的接口,适配哨兵数据的收集方式,将各类数据上报到哨兵服务器。它包含两部分:数据收集和数据发送。

数据发送部分在程序启动时会加载当前服务的配置,设定好上报格式,当有收集器上报数据时会调用其接口生成固定的json格式,并使用HTTPClient库上报。

数据收集部分是一个可扩展的库,可以用其创建自定义的收集器,并指定metric和上报间隔,在Redis、Kafka、HTTPClient等库中都已经内置了收集器。一般来说一个收集器的处理行为只需要一种类型的数据来触发,在后台生成多种数据项。比如HTTPClient是每次都传入单次调用的记录,在收集器后台处理时生成对一分钟内所有调用的全汇总、url汇总、host汇总、状态码汇总等类型的数据项。

用户可以用以下实现来创建一个一分钟上报周期的收集器,至于RawData如何去更新ItemData需要用户自己实现。

collector=metrics.NewCollector(&metrics.MetricOptions{Name:metricName,Interval:time.Minute,})collector.Register(itemTypeInvocation,&RawData{},&ItemData1{})collector.Register(itemTypeHostInvocation,&RawData{},&ItemData2{})collector.Start()

后续用户只需调用collector.Push(rawData)就能将数据发送到收集器。数据处理在后台执行,整个收集器处理都是无锁的,不会阻塞用户的调用。

现在Ngo中已内置以下哨兵监控metric:

3

性能压测及线上表现

技术的转型,势必会带来性能表现的差异,这也是我们为什么花费精力来探究的第一因。现在我们将从以下几个维度来对比一下转型为Go之后的所带来的优点和缺点

压测比较

第一轮压测指标:

集群配置:

集群

cpu

内存

节点数量

Jvm配置

Java

2核

500M

xmx300M

xms300M

GO

100M

/

首先我们先看一下整体的不同项目的集群整体表现

Java集群

Go集群

TPS-RT曲线

因为我们加压的过程是直接进入峰值,启动时候的表现,从TPS指标和MaxRT指标,显示Java集群有一个冷启动的过程,而Go集群没有这么一个过程。两者在经历过冷启动之后,性能表现都很稳定。

请求曲线

机器性能指标

cpu-memory

从当前的压测结果和机器性能指标来看,Go集群有更好的并发请求处理能力,请求吞吐量更大,并且在机器资源占用上有更好的优势。使用更少的内存,做了更多的事情。

第二轮压测指标:

集群配置:

700M

xmx400M

xms400M

各项指标曲线和100并发状态相似,除了TPS曲线。Java在200并发下冷起的过程变得更长了。但最终都还是趋于稳定的状态。

机器资源曲线没有太大的变化。

总结:

100并发比较JavaGo配置2C500M2C100MTPS3472.594082.52MRT(ms)28.7424.4499%RT10293MaxRT997227CPU使用率100%100%内存使用率80%50%

200并发比较JavaGo配置2C700M2C100MTPS3410.554061.38MRT(ms)67.5349.1699%RT211103MaxRT2402533CPU使用率100%100%内存使用率80%57%

从两次结果压测结果来看的话,Go在集群中的表现是要优于Java的。Go拥有更好的并发处理能力,使用更少的机器资源。而且不存在冷启动的过程。随着压力的增加,虽然吞吐量没有上去,但是Go集群的RT90和RT99变化不是很大,但是相同分位Java集群的表现则扩大了一倍。而且在100并发情况下,MaxRT指标Java集群和Go集群相差无几,而在200并发情况下,RT99指标Java集群则变成了Go集群的2倍。并且在200并发的情况下,Java集群的TPS有明显的下降。而且TPS的指标的曲线Java的上升曲线过程被拉的更长了。其实换一个角度来看的话,在流量激增的情况下,Java集群的反应反而没有Go稳定。

Go集群线上接口表现

目前我们一共改造了三个接口,业务的复杂度逐渐提升。

hotTag接口表现

机器资源状态

推荐接口表现

结论:

就目前的线上集群的状态来看的话,集群的运行状态比较稳定,而且服务的处理能力是极为高效的。当然了,目前的线上状态Go项目接口单一,整个集群就只有这一个接口提供服务。Java集群因为业务关系,提供的服务接口更多,而且性能表现可能会因为系统IO或者网络带宽问题,导致了性能的看上去没有那么漂亮,更准确的结论会在Java集群中的所有接口全部迁移到Go集群中的时候的数据表现更具有说服力。

4

重构实践与问题

Go协程与Java的线程

talkischeap,showmycode!

Go使用协程

//使用协程来执行util.GoN(func(){topicInfo=GetTopicInfoCachable(tid)},)

Java使用线程

//当然了,我们知道很多种java的线程实现方式,我们就实现其中的一种//定义功能类privateCompletableFuturegetTopicInfoFuture(Stringtid){returnCompletableFuture.supplyAsync(()->{try{returnarticleProviderService.getTopicInfo(tid);}catch(Exceptione){log.error("SubscribeShortnewsServiceImpl.getTopicInfoFuturetid:{}",tid,e);}returnnull;},executor);}//线程使用CompletableFuturetopicInfoFuture=getTopicInfoFuture(tid);TopicInfotopicInfo=null;try{topicInfo=topicInfoFuture.get(2,TimeUnit.SECONDS);}catch(Exceptione){log.error("[SubscribeShortnewsServiceImpl]getSimpleSubscribeTopicHeadfutureerror,tid="+tid,e);}

从上述的代码实现中,我们可以看出来Java代码的书写过程略显冗余,而且被线程执行的过程是需要被实现为特定的类,需要被继承覆盖或者重写的方式来执行线程。想要复用已经存在功能函数会费些周折。但是Go在语法级别支持了协程的实现,可以对已经实现功能做到拿来即可使用,哪怕没有对这个功能做封装。

我个人理解是因为语言的实现理念导致了这种书写方式上的差异。本身Go就是类C语言,它是面向过程的编程方式,而Java又是面向对象编程的优秀代表。因此在不同的设计理念下,面向过程考虑更多的是功能调用,而面向对象需要设计功能本身的抽象模型,然后再实现功能。考虑的多必然导致编码的冗余,但是这样的方式的好处是更容易描述整个应用的状态和功能。如果理解的不正确,希望大家指出。

改造过程中遇到的问题

在将Java项目中迁移到Go的过程中也会遇到各种各样的问题,书写上的习惯,功能设计上的差异等等。我把它分为了以下几个方面:

1.万物皆指针到值和指针的控制

提到值传递和指针传递,是不是让你想起了写C或者Cplus的青葱岁月。Java中只有基本类型是值传递之外(不包含基本类型的封装类)其他的都是引用传递,引用换句话说就是指针。传递指针的一个好处是,传递的是一个内存地址,因此在程序赋值的时候,只需要将内存地址复制一下即可,具体地址指向的内容的大小和内容是什么,根本不用关心,只有在使用的时候再关心即可。可以说Java本身就屏蔽了这么一个可能出现大量复制的操作。但是Go并没有给你屏蔽这种操作,这个时候你自己就需要根据自己的应用场景选择到底是选择传递值还是引用。

//Car我们定义一个车的基本信息,用来比较车与车之间的性价比typeCarstruct{NamestringPricefloat32TopSpeedfloat32Accelerationfloat32}//CompareVa值传递,此时会存在Car所有的数据复制,低效funcCompareVa(aCar,bCar){//TODO...compare}//ComparePtr指针传递,只是复制了地址,内容不会复制,高效funcComparePtr(a*Car,b*Car){//TODO...compare}

2.精简的语法导致的不注意引起的局部变量的创建

var(currentItemInfo*itemInfoemptyKey=""dbCollectormetrics.CollectorInterface//我们定义了一个全局变量,数据上传的hook)//用于初始化我们的定义的db打点收集器funcinitMetrics(){dbCollector:=metrics.NewCollector(&metrics.MetricOptions{Name:metrics.MetricTypeMyql,Interval:time.Minute,})dbCollector.Register(itemTypeConnection,&rawOperation{},&itemConnection{})......dbCollector.Start()}

不知道大家有没有发现其中的问题?

initMetrics()

方法并没有完成自己的任务,dbCollector变量并没有被初始化。只是因为我们使用了:=。此时应用只是重新创建了一个局部变量而已,语法正确,IDE并不会给我们做出提示。因此,精简的语法带来了代码的整洁,随之而来的需要我们更加专注于自己写的代码,仔细检查自己打的每一个字符。

3.理解nil和null和空

nil只是Go语言中指针的空地址,变量没有被分配空间

null只是Java语言中引用的空地址,变量没有被分配空间

空就是分配了内存,但是没有任何内容

4.关于string

习惯了Java中对于String的使用方式,在Go中使用string的时候会稍微有点儿不习惯。Java中String是引用类型,而在Go中就是一个基本类型。

Java代码

Stringstr;//定义了一个java变量,初始化为null

Go代码

strstring//定义了一个go变量,初始化为空字符串,注意这里不是nil

5.没有包装类

我们经常会在Java工程当中写这样的代码

classModel{publicIntegerminLspri;publicIntegermaxLspri;...}publicMapgenerateParam(Modelparam){Mapparams=Maps.newHashMap();if(param.minLspri!=null){params.put("minLspri",param.minLspr.toString())}if(param.minLspri!=null){params.put("maxLspri",param.maxLspri.toString())}...}

那我们在改造为Go的时候要不要直接转化为这样

typeModelstruct{minLspri*intmaxLspri*int...}...

遇到这种问题怎么办?我的建议是我们还是直接定义为

typeModelstruct{minLspriintmaxLspriint...}

我们还是要像Go一样去写Go,而不是Java味道的Go项目。而出现这个问题的原因我也想了一下,其实就是在java项目当中,我们习惯的会把null作为一个值来理解,其实null是一种状态,而不是值。它只是告诉你变量的状态是还没有被分配内存,而不是变量是null。所以在改造这种项目的过程中,还是要把每个字段的默认值和有效值了解清楚,然后做判断即可。

6.数据库NULL字段的处理

这个其实也是因为上一条原因导致的,那就是Go中没有包装器类型,但好在sql包中提供了sql.NullString这样的封装器类型,让我们更好的判断到底数据库中存放的是一个特定的值还是保存为null

Java和Go在处理key不存在的时候方式不一样。Java中Key不存在就是返回一个空字符串,但是Go中如果Key不存在的话,返回的其实是一个error。因此我们在Go中一定要把其他的错误和key不存在的error区分开。

8.异常的处理和err处理

Java中的Exception记录了太多的东西,包含了你的异常的调用链路和打印的日志信息,在任何catch住的异常那里都很方便的把异常链路打印出来。而Go中处理方式更简洁,其实只是记录了你的异常信息,如果你要看异常堆栈需要你的特殊处理。这就需要你在任何出现error的地方及时的打印日志和作出处理,而不是像Java一样,我在最外层catch一下,然后处理一样也可以很潇洒了。孰是孰非,只能在不断的学习和理解当中来给出答案了。

接下来我们会在Ngo上继续增加流量跟踪标识、全链路数据上报等特性,并完善监控指标,陆续推动更多Java语言业务转入Go语言。

THE END
1.GotoLearnGo之基本数据类型除了上述的基本整数类型,Go语言还提供了其他几种整数类型,包括: rune:该类型表示Unicode码点,通常用来表示一个Unicode字符。 byte:与uint8是同义词,表示一个字节。 uintptr:该类型的大小不确定,与平台和编译器有关,但足以存放指针。uintptr通常用于底层编程,特别是与C程序库交互的地方。 https://www.jianshu.com/p/9a47fe922ca3
2.Go语言开发入门与实战一、Go语言的特点 简单易学:语法简洁,易于阅读和维护。 高效并发:原生支持goroutine和channel实现高效并发编程。 跨平台支持:编译后的二进制文件可以直接在多种操作系统上运行。 静态类型:强类型语言,编译时检查错误,提供更高的安全性。 强大的标准库:内置大量网络、I/O、字符串处理等功能模块。 https://zhuanlan.zhihu.com/p/13376334671
3.深入浅出:Go项目依赖管理与gomod的使用gomod依赖go mod是 Go 官方提供的依赖管理工具,它通过go.mod文件来记录项目的依赖关系。go.mod文件包含以下信息: 模块路径:项目的唯一标识符,通常为项目的 Git 仓库 URL。 依赖项:项目所需的外部库及其版本。 替换规则:用于临时替换某些依赖项的路径或版本。 https://blog.csdn.net/zhaoxilengfeng/article/details/144315476
4.文档中心虹软AIA:虹软提供独立离线版 SDK,支持离线或在线运行,可实现局域网、互联网等多种网络需求,并可根据场景需求,将应用部署在公有云上,或者搭建私有云,保障数据隐私性以及安全性。注意当前免费版本SDK首次使用需联网激活,激活后可离线使用;人脸识别增值版SDK同时支持联网激活和纯内网环境离线激活离线使用。 https://ai.arcsoft.com.cn/manual/docs#/42
5.testopenback.axbinsur.com/kta62551438.htm麻豆av中文字网在线观看免费 看我是怎么c哭你叫出来 911.21MB 6769好评 四虎在线网站8848 大香蕉一区二区三区大东北 打肿菊玉势调教姜刑打烂 115.48MB 15好评 好属妞在线观看 色老头人体艺术网 农村人乱弄一区二区 60.14MB 5090好评 天天天操夜夜夜操 四虎影库一级黄片 成人aTV网站 http://testopenback.axbinsur.com/kta62551438.htm
6.GitHub【超全golang面试题合集+golang学习指南+golang知识图谱+入门成长路线】 一份涵盖大部分golang程序员所需要掌握的核心知识。常用第三方库(mysql,mq,es,redis等)+机器学习库+算法库+游戏库+开源框架+自然语言处理nlp库+网络库+视频库+微服务框架+视频教程+音频音乐库+图形图片库+物联网库+地理位置信息+嵌入式脚本https://github.com/18737628639/golangFamily
7.gopkg/awesomegocn:golang的一些第三方包合集awesomeAwesome Go 此项目是 awesome-go 中文版,最后一次同步时间 : 2023-05-16 07:12:32(每隔1天同步一次) 为Awesome Go打赏~ 精选了一系列很棒的Go框架、库和软件。灵感来自于awesome-python。 小图标说明 : 小图标说明 最近一周有更新。可以基本判断当前库处于积极维护状态。 最近三年没有更新。反应了此库的维护https://gitea.mrx.ltd/Go-pkg/awesome-go-cn/src/commit/191279a019bab2dc25fa88dcf388656ef251ea32
8.Docker镜像仓库库来获取最新漏洞信息,并扫描用户上传的容器是否存在已知的漏洞信息,这两个安全功能对于企业级私有仓库来说是非常具有意义的。 Harbor安装有3种方式: 在线安装:从Docker Hub下载Harbor相关镜像,因此安装软件包非常小 离线安装:安装包包含部署的相关镜像,因此安装包比较大 https://developer.aliyun.com/article/1317766
9.好用的在线客服系统Go语言源码go env-wGOPROXY=https://goproxy.cn,direct 下载源码 Github 代码语言:javascript 复制 git clone https://github.com/taoshihan1991/go-fly.git Gitee 代码语言:javascript 复制 git clone https://gitee.com/taoshihan/go-fly.git 导入数据库 提前创建好数据库 https://cloud.tencent.com/developer/article/2167870
10.《Go编程基础》首页文档和下载Go语言的视频语音教程《Go编程基础》是一套针对 Google 出品的 Go 语言的视频语音教程,主要面向新手级别的学习者。 开发环境:Go 语言 1.0.3-1.8.* 版本 开发工具:Sublime Text 2-3 开发系统:Windows 7 64 位 其它说明:每堂课都会建立一个文件(例如:lecturehttps://www.oschina.net/p/go-fundamental-programming
11.FALCON:使用离线和在线学习实现快速准确的多路径调度? 我们设计了 FALCON,一种基于 ML 的多路径调度器,它结合了离线和在线学习的好处在于,使用较少的输入数据即可获得训练有素的多路径调度策略。据我们所知,我们的工作是首次系统地研究多路径调度,该调度优化了适应速度和对时变网络条件的准确性; ?我们使用 quic-go 在 MPQUIC 中实现 FALCON 的协议方面,使用 kerashttp://help.louzhutie.cn/?developer/article/2470399
12.BookStack:BookStack,基于MinDoc,使用Beego开发的在线文档管理增加版本库支持 8个月前 conf merge video 4年前 controllers 增加版本库支持 8个月前 dictionary 替换结巴分词(因为依赖C) 4年前 docker 升级html2md包 5年前 graphics 代码优化 6年前 models 增加版本库支持 8个月前 oauth github oauth登录调整 https://gitee.com/truthhun/BookStack
13.无涯教程网Golang教程完整离线版.pdf它提供垃圾回收,类型安全,动态键?功能,许多?级内置类型,如可变长度数组和键值映射,它还提供了丰富的标准库,Go编程语?于 2009年 ?发布,并在Google的某些?产系统中使?。 本教程是为需要从头了解Go编程语?的软件程序员设计的,本教程将使您对Go编程语?有?够的了解,从那?您可以进?更https://m.book118.com/html/2021/0513/6002242134003145.shtm
14.数据智能知识地图:数据应用+数据能力+数据架构+数据采离线态和在线态均需服务化 精度有微小损失,ML场景影响不大 百万/千万/亿级规模(带宽依赖) 数据提供方增多后性能有所下降,适用5方以下 数据控制力强 不依赖特殊硬件 无硬件信任根,国密化方案较为可控 需融入其它技术联合使用以实现数据安全保护效果 支持部分运算能力,需算法/研发投入,目前主要支持ML 离线态和在线https://doc.mbalib.com/view/0132ff1adc002fd16638cda75f2aa8b4.html
15.隐私政策GoPro本隐私政策适用于作为数据控制方的 GoPro, Inc.(以下简称“GoPro”、“我们”或“我们的”)在我们的业务过程中收集的有关您的信息,包括通过链接到本隐私政策的 GoPro 网站收集的信息;我们的产品;我们的移动和桌面应用程序;以及由 GoPro 运营或代表 GoPro 运营的其他相关在线或离线产品。我们将这些产品、服务、https://gopro.com/zh/cn/legal/privacy-policy
16.jeecg但是打成jar包,运行会提示找不到支付宝依赖。 显示java.lang.NoClassDefFoundError: com/alipay/api/domain/ZolozAuthenticationCustomerFtokenQueryModel之类错误。 原因:因jeecg新版的jeewx-api包与ijpay都引入了alipay-sdk-java,打jar包会有两个alipay-sdk-java包,所以冲突找不到。 http://blog.wandouwang.cn/archives/jeecg-boot245-shi-yong-ijpay-yun-xing-jar-bao-zhao-bu-dao-zhi-fu-bao-ku-yi-lai-wen-ti-jie-jue
17.go语言离线51CTO博客已为您找到关于go语言离线的相关内容,包含IT学习相关文档代码介绍、相关教程视频课程,以及go语言离线问答内容。更多go语言离线相关解答可以来51CTO博客参与分享和学习,帮助广大IT技术人实现成长和进步。https://blog.51cto.com/topic/ad31d0ad60af668.html
18.唐福林博客雨唐福林博客雨进行完这两个操作之后,他就产生了一个 VM,这个 VM 就是一个你可以一键 ssh 进去,它自动把你所有东西都搭配好,这是一个属于你的开发环境,那有了这个东西之后,整个公司可以有一套一致的开发环境,因为是一个 VM,它在哪台机子上运行的方式都一样,所有的依赖库都可以放进去,所以最后的结果就是我们有一个几G的https://tangfl.wordpress.com/