iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Go如何创建Grpc链接池
  • 894
分享到

Go如何创建Grpc链接池

2023-07-05 08:07:37 894人浏览 薄情痞子
摘要

这篇“Go如何创建grpc链接池”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Go如何创建Grpc链接池”文章吧。常规用法g

这篇“Go如何创建grpc链接池”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Go如何创建Grpc链接池”文章吧。

常规用法

gRPC 四种基本使用

  • 请求响应模式

  • 客户端数据流模式

  • 服务端数据流模式

  • 双向流模式

常见的gRPC调用写法

func main(){//... some code// 链接grpc服务conn , err := grpc.Dial(":8000",grpc.WithInsecure)if err != nil {//...log}defer conn.Close()//...some code

存在的问题:面临高并发的情况,性能问题很容易就会出现,例如我们在做性能测试的时候,就会发现,打一会性能测试,客户端请求服务端的时候就会报错:

rpc error: code = Unavailable desc = all SubConns are in TransientFailure, latest connection error: connection error: desc = "transport: Error while dialing dial tcp xxx:xxx: connect: connection refused

实际去查看问题的时候,很明显,这是 gRPC 的连接数被打满了,很多连接都还未完全释放。[#本文来源:janrs.com#]

gRPC 的通信本质上也是 TCP 的连接,那么一次连接就需要三次握手,和四次挥手,每一次建立连接和释放连接的时候,都需要走这么一个过程,如果我们频繁的建立和释放连接,这对于资源和性能其实都是一个大大的浪费。

在服务端,gRPC 服务端的链接管理不用我们操心,但是 gRPC 客户端的链接管理非常有必要关心,要实现复用客户端的连接。

创建链接池

创建链接池需要考虑的问题:

  • 连接池是否支持扩缩容

  • 空闲的连接是否支持超时自行关闭,是否支持保活

  • 池子满的时候,处理的策略是什么样的

创建链接池接口

type Pool interface {// 获取一个新的连接 , 当关闭连接的时候,会将该连接放入到池子中   Get() (Conn, error)// 关闭连接池,自然连接池子中的连接也不再可用   Close() error//[#本文来源:janrs.com#]   Status() string}

实现链接池接口

创建链接池代码

func New(address string, option Options) (Pool, error) {   if address == "" {      return nil, errors.New("invalid address settings")   }   if option.Dial == nil {      return nil, errors.New("invalid dial settings")   }   if option.MaxIdle <= 0 || option.MaxActive <= 0 || option.MaxIdle > option.MaxActive {      return nil, errors.New("invalid maximum settings")   }   if option.MaxConcurrentStreams <= 0 {      return nil, errors.New("invalid maximun settings")   }   p := &pool{      index:   0,      current: int32(option.MaxIdle),      ref:     0,      opt:     option,      conns:   make([]*conn, option.MaxActive),      address: address,      closed:  0,   }   for i := 0; i < p.opt.MaxIdle; i++ {      c, err := p.opt.Dial(address)      if err != nil {         p.Close()         return nil, fmt.Errorf("dial is not able to fill the pool: %s", err)      }      p.conns[i] = p.wrapConn(c, false)   }   log.Printf("new pool success: %v\n", p.Status())   return p, nil}

关于以上的代码,需要特别注意每一个连接的建立也是在 New 里面完成的,[#本文来源:janrs.com#]只要有 1 个连接未建立成功,那么咱们的连接池就算是建立失败,咱们会调用 p.Close() 将之前建立好的连接全部释放掉。

关闭链接池代码

// 关闭连接池func (p *pool) Close() error {   atomic.StoreInt32(&p.closed, 1)   atomic.StoreUint32(&p.index, 0)   atomic.StoreInt32(&p.current, 0)   atomic.StoreInt32(&p.ref, 0)   p.deleteFrom(0)   log.Printf("[janrs.com]close pool success: %v\n", p.Status())   return nil}

从具体位置删除链接池代码

// 清除从 指定位置开始到 MaxActive 之间的连接func (p *pool) deleteFrom(begin int) {   for i := begin; i < p.opt.MaxActive; i++ {      p.reset(i)   }}

销毁具体的链接代码

// 清除具体的连接func (p *pool) reset(index int) {   conn := p.conns[index]   if conn == nil {      return   }   conn.reset()   p.conns[index] = nil}

关闭链接

代码

func (c *conn) reset() error {   cc := c.cc   c.cc = nil   c.once = false   // 本文博客来源:janrs.com   if cc != nil {      return cc.Close()   }   return nil}func (c *conn) Close() error {   c.pool.decrRef()   if c.once {      return c.reset()   }   return nil}

在使用连接池通过 pool.Get() 拿到具体的连接句柄 conn 之后,会使用 conn.Close()关闭连接,实际上也是会走到上述的 Close() 实现的位置,但是并未指定当然也没有权限显示的指定将 once 置位为 false ,也就是对于调用者来说,是关闭了连接,对于连接池来说,实际上是将连接归还到连接池中。

扩缩容

关键代码

func (p *pool) Get() (Conn, error) {   // the first selected from the created connections   nextRef := p.incrRef()   p.RLock()   current := atomic.LoadInt32(&p.current)   p.RUnlock()   if current == 0 {      return nil, ErrClosed   }   if nextRef <= current*int32(p.opt.MaxConcurrentStreams) {      next := atomic.AddUint32(&p.index, 1) % uint32(current)      return p.conns[next], nil   }   // 本文博客来源:janrs.com   // the number connection of pool is reach to max active   if current == int32(p.opt.MaxActive) {      // the second if reuse is true, select from pool's connections      if p.opt.Reuse {         next := atomic.AddUint32(&p.index, 1) % uint32(current)         return p.conns[next], nil      }      // the third create one-time connection      c, err := p.opt.Dial(p.address)      return p.wrapConn(c, true), err   }   // the fourth create new connections given back to pool   p.Lock()   current = atomic.LoadInt32(&p.current)   if current < int32(p.opt.MaxActive) && nextRef > current*int32(p.opt.MaxConcurrentStreams) {      // 2 times the incremental or the remain incremental  ##janrs.com      increment := current      if current+increment > int32(p.opt.MaxActive) {         increment = int32(p.opt.MaxActive) - current      }      var i int32      var err error      for i = 0; i < increment; i++ {         c, er := p.opt.Dial(p.address)         if er != nil {            err = er            break         }         p.reset(int(current + i))         p.conns[current+i] = p.wrapConn(c, false)      }  // 本文博客来源:janrs.com      current += i      log.Printf("#janrs.com#grow pool: %d ---> %d, increment: %d, maxActive: %d\n",         p.current, current, increment, p.opt.MaxActive)      atomic.StoreInt32(&p.current, current)      if err != nil {         p.Unlock()         return nil, err      }   }   p.Unlock()   next := atomic.AddUint32(&p.index, 1) % uint32(current)   return p.conns[next], nil}

Get 代码逻辑

  • 先增加连接的引用计数,如果在设定 current*int32(p.opt.MaxConcurrentStreams) 范围内,那么直接取连接进行使用即可。

  • 若当前的连接数达到了最大活跃的连接数,那么就看我们新建池子的时候传递的 option 中的 reuse 参数是否是 true,若是复用,则随机取出连接池中的任意连接提供使用,如果不复用,则新建一个连接。

  • 其余的情况,就需要我们进行 2 倍或者 1 倍的数量对连接池进行扩容了。

也可以在 Get 的实现上进行缩容,具体的缩容策略可以根据实际情况来定,例如当引用计数 nextRef 只有当前活跃连接数的 10% 的时候(这只是一个例子),就可以考虑缩容了。

以上就是关于“Go如何创建Grpc链接池”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网精选频道。

--结束END--

本文标题: Go如何创建Grpc链接池

本文链接: https://www.lsjlt.com/news/350694.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Go如何创建Grpc链接池
    这篇“Go如何创建Grpc链接池”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Go如何创建Grpc链接池”文章吧。常规用法g...
    99+
    2023-07-05
  • Go创建Grpc链接池实现过程详解
    目录常规用法创建链接池创建链接池接口实现链接池接口关闭链接扩缩容性能测试常规用法 gRPC 四种基本使用 请求响应模式客户端数据流模式服务端数据流模式双向流模式 常见的gRPC调用...
    99+
    2023-03-03
    Go创建Grpc链接池 Go Grpc
  • linux软链接如何创建
    这篇“linux软链接如何创建”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“linux软链接如何创建”文章吧。在linux中...
    99+
    2023-07-02
  • html如何创建站内链接
    html创建站内链接的方法:可以通过<a>标签来实现站内链接,代码如:<a href="https://www.yisu.com/">编程网</a>//通过a标签在站内链接编...
    99+
    2022-10-14
  • HTML如何创建下载链接
    这篇文章主要为大家展示了“HTML如何创建下载链接”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“HTML如何创建下载链接”这篇文章吧。 您也可以使用与放置文本...
    99+
    2022-10-19
  • 在HTML中如何创建链接
    这篇文章主要为大家展示了“在HTML中如何创建链接”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“在HTML中如何创建链接”这篇文章吧。 链接或超链接是从一个W...
    99+
    2022-10-19
  • 如何创建Linux系统中硬链接与软链接
    这篇文章主要介绍“如何创建Linux系统中硬链接与软链接”,在日常操作中,相信很多人在如何创建Linux系统中硬链接与软链接问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何创建Linux系统中硬链接与软链接...
    99+
    2023-06-12
  • linux中如何创建符号链接
    本篇文章给大家分享的是有关linux中如何创建符号链接,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。硬链接(hard links): 为文件创建了额外的条目.使用时, 与文件没...
    99+
    2023-06-13
  • 在Ubuntu中如何创建符号链接
    在Ubuntu中创建符号链接的方法:在.conda原路径下建立符号链接,如:ln -s ./project/.conda .conda 软连接 (文件、文件夹)ln ./project/.conda .conda 硬连接(只对文件)...
    99+
    2022-10-23
  • 如何在HTML文档中创建链接
    这篇文章主要介绍了如何在HTML文档中创建链接,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。 HTML 超链接(链接) 超链接可以是一个...
    99+
    2022-10-19
  • IDEA2020如何新建spring项目和创建c3p0连接池
    这篇文章将为大家详细讲解有关IDEA2020如何新建spring项目和创建c3p0连接池,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。前言     &nb...
    99+
    2023-06-20
  • html5如何创建跳转页尾超链接
    这篇文章主要讲解了“html5如何创建跳转页尾超链接”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“html5如何创建跳转页尾超链接”吧! ...
    99+
    2022-10-19
  • 如何实现Linux给文件或目录创建软链接、硬链接
    这篇文章主要讲解了“如何实现Linux给文件或目录创建软链接、硬链接”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何实现Linux给文件或目录创建软链接、硬链接”吧!当我们需要在不同的目录...
    99+
    2023-06-13
  • 在Python数据库连接池中如何创建请求连接
    在Python数据库连接池中如何创建请求连接,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。在Python数据库连接池中操作过程中如果你设置好了连接池,你就可以按...
    99+
    2023-06-17
  • Android如何创建线程池
    在Android中,可以使用`ThreadPoolExecutor`类来创建线程池。下面是创建线程池的步骤:1. 导入所需的类:``...
    99+
    2023-09-12
    Android
  • Java线程池如何创建
    本文小编为大家详细介绍“Java线程池如何创建”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java线程池如何创建”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。线程池的好处可以实现线程的复用,避免重新创建线程和...
    99+
    2023-06-29
  • springboot如何创建线程池
    这篇文章主要介绍springboot如何创建线程池,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!springboot创建线程池两种方式1.使用static代码块创建这样的方式创建的好处是当代码用到线程池的时候才会初始...
    99+
    2023-06-22
  • ubuntu如何创建软链
    这篇文章主要介绍“ubuntu如何创建软链”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“ubuntu如何创建软链”文章能帮助大家解决问题。创建方法:sudo&nbs...
    99+
    2022-12-07
    ubuntu
  • Java如何手动创建线程池
    目录如何手动创建线程池构造器队列饱和策略示例源码分析线程池工具类实现线程的三种方式使用ThreadPoolExecutor编写线程池工具类如何手动创建线程池 jdk提供了一个通过Th...
    99+
    2022-11-13
  • 如何创建爬虫代理ip池
    本篇内容介绍了“如何创建爬虫代理ip池”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!爬虫抓取时,我们经常会遇到网站封锁IP地址的反爬虫策略。...
    99+
    2023-06-20
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作