我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Mongodb代理程序如何实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Mongodb代理程序如何实现

这篇文章主要介绍“Mongodb代理程序如何实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Mongodb代理程序如何实现”文章能帮助大家解决问题。

根据一贯的风格,我们先来梳理下项目目录结构,结构如下:

|__ bin/                   # 用于存放编译后生成的二进制文件

|__ config/                # 用于存放配置文件

|__ connection/            # 存放连接相关的文件

|   |__ proxy.go           # 代理组件

|   |__ pool.go            # 连接池组件

|   |__ repl_set.go        # 复制集组件

|   |__ conn.go            # 连接对象组件

|__ internal/              # 存放 mongo 内部协议相关文件

|   |__ auth.go            # 握手鉴权组件

|   |__ protocol.go        # 协议解析组件

|   |__ request.go         # 请求重写组件

|   |__ response.go        # 响应重写组件

|__ statistics/            # 存放指标统计上报组件

|__ test/                  # 存放各种语言驱动测试代码的文件夹

|__ utils/                 # 工具函数文件夹

|__ glide.yaml             # 依赖包配置文件

|__ main.go                # 入口文件

proxy 实现

最简单的 proxy 实现套路就像下面这样:

// main.go

func main() {

  // 传入配置参数,实例化一个代理对象

  p := NewProxy(conf)

  // 卡住,循环接受客户端请求

  p.LoopAccept()

}

接着来实现 NewProxy、LoopAccept 方法:

// connection/proxy.go

type Proxy struct {

  sync.RWMutex

  listener            net.Listener

  writePool, readPool *pool

}

func NewProxy(conf config.UserConf) *Proxy {

  // 开始监听本地端口

  listener, err := net.Listen("tcp", ":"+conf.GetString("port"))

  if err != nil {

    log.Fatalln(err)

  }

  p := &Proxy{

    listener: listener,

  }

  // 实例化连接池

  p.readPool, p.writePool, err = newPool(p)

  if err != nil {

    panic(err)

  }

  return p 

}

func (p *Proxy) LoopAccept() {

  for {

    client, err := p.listener.Accept()

    go func(c net.Conn) {

      defer c.Close()

      // 一个连接在多次 messageHandler 中共用一个 Reader 对象

      cr := bufio.NewReader(c)

      // 因为一个连接可能会进行多次读或写操作

      for {

        // 将客户端请求代理给服务端,服务端响应代理回客户端

        // 同时中间对请求或响应进行重写操作

        err := p.messageHandler(cr, c)

        if err != nil {

          // 只要出现错误,就执行到上面的 defer c.Close() 来关闭连接

          return

        }

      }

    }(client)

  }

}

接着来实现核心逻辑 messageHandler:

// connection/proxy.go

func (p *Proxy) messageHandler(cr *bufio.Reader, c net.Conn) error {

  // 对请求报文进行解析操作

  req, err := internal.Decode(clientReader)

  if err != nil {

        return errors.New("decode error")

    }

  // 将客户端请求发送给数据库服务器

  res, err := p.clientToServer(req)

  if err != nil {

    return errors.New("request error")

  }

  // 将数据库服务器响应返回给客户端

  return res.WriteTo(c)

}

func (p *Proxy) clientToServer(req *internal.Message) (*internal.Message, error) {

  var server net.Conn

  // 如果是读操作,就从读池中取出连接

  if req.IsReadOp() {

    host := req.GetHost()

    // 某些读操作需要发送到指定的读库上,所以需要传 host,来获取指定读库连接

    server = p.readPool.Acquire(host)

  // 反之,写操作从写池中取出连接

  } else {

    // 由于写库只有一个,所以不用传 host 参数了

    server = p.writePool.Acquire()

  }

  // 将客户端请求发送给数据库服务器

  err := req.WriteTo(server)

  if err != nil {

    return nil, err

  }

  // 获取解析数据库服务器响应

  res, err := internal.Decode(bufio.NewReader(server))

  return res, err

}

大致逻辑就是,客户端通过代理把请求发给服务端,服务端响应也通过代理响应回客户端。

------------  request  -----------  request  ------------

|          | --------> |         | --------> |          |

|  client  |           |  proxy  |           | repl_set |

|          | <-------- |         | <-------- |          |

------------  response -----------  response ------------

呐&mdash;&mdash;,当然还有非常多的细节,由于篇幅原因不得不省略...

pool 实现

由 proxy 的代码逻辑来看,我们取读或写库连接是通过读或写池的 Acquire 方法来取的:

// connection/pool.go

type pool struct {

  sync.RWMutex

  connCh   chan net.Conn

  newConn  func(string) (net.Conn, error)

  freeConn func(net.Conn) error

}

func (p *pool) Acquire(opts ...interface{}) (net.Conn, error) {

  host := ""

  if len(opts) > 0 {

    host, _ = (opts[0]).(string)

  }

  chLen := len(p.connCh)

  // 从 channel 中遍历剩余数量的 conn

  for i := 0; i < chLen; i++ {

    select {

    case conn, ok := <- ch:

      if ok {

        if len(host) > 0 {

          if conn.RemoteAddr().String() == host {

            return conn, nil

          }

          // 没有找到对应 host 的 conn,则把 conn 重新放回 channel

          // 你可以简单理解为只是执行了 p.connCh <- conn 操作

          p.freeConn(conn)

        } else {

          return conn, nil

        }

      }

    // 避免数量不足而导致 channel 阻塞等待

    default:

    }

  }

  // 若还没有从 channel 中取到 conn,则立马 new 一个

  conn, err := p.newConn(host)

  if err != nil {

    return nil, err

  }

  return conn, nil

}

池的实现大致就是实现了一个循环队列,连接从池中取,取出的连接在使用完后,可以放回池中。

关于“Mongodb代理程序如何实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网行业资讯频道,小编每天都会为大家更新不同的知识点。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Mongodb代理程序如何实现

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

下载Word文档

猜你喜欢

如何理解C++实现程序方法

这篇文章将为大家详细讲解有关如何理解C++实现程序方法,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。C++实现程序解决问题,本程序采用射线法,由待测试点(v)水平引出一条射线B(v,w),计
2023-06-17

如何使用MongoDB实现数据排序功能

如何使用MongoDB实现数据排序功能引言:MongoDB是一种非关系型数据库,它以文档的形式组织数据,并且提供了丰富的查询操作。在实际应用中,数据的排序是非常常见的需求之一。本文将介绍如何使用MongoDB实现数据排序功能,并提供具体的代
2023-10-22

mongodb如何实现员工管理系统

要实现一个员工管理系统,可以使用MongoDB作为数据库存储员工的信息。以下是一个简单的示例:1. 创建一个MongoDB数据库并连接到数据库。```javascriptconst MongoClient = require('mongod
2023-08-30

微信小程序弹框功能代码如何实现

本篇内容介绍了“微信小程序弹框功能代码如何实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.提示框:wx.showToast实例:wx:
2023-06-26

C#如何实现简单订单管理程序

这篇文章主要介绍“C#如何实现简单订单管理程序”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C#如何实现简单订单管理程序”文章能帮助大家解决问题。订单管理的控制台程序,能够实现添加订单、删除订单、修
2023-06-30

小程序如何实现多进程

这篇文章将为大家详细讲解有关小程序如何实现多进程,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。前言小程序这个名词相信大家已经不陌生了,继微信之后,阿里巴巴、百度、头条等大厂相继实现了自己的小
2023-06-04

java如何实现代理模式

小编给大家分享一下java如何实现代理模式,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象
2023-05-30

Vue数据代理如何实现

这篇文章主要介绍“Vue数据代理如何实现”,在日常操作中,相信很多人在Vue数据代理如何实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue数据代理如何实现”的疑惑有所帮助!接下来,请跟着小编一起来学习吧
2023-07-04

Java代理模式如何实现

这篇文章主要介绍“Java代理模式如何实现”,在日常操作中,相信很多人在Java代理模式如何实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java代理模式如何实现”的疑惑有所帮助!接下来,请跟着小编一起来
2023-06-19

如何实现socks5全局代理

要实现socks5全局代理,需要进行以下步骤:1. 安装socks5服务器:首先需要在你的服务器或者本地机器上搭建一个socks5服务器。可以使用一些开源的软件,如Shadowsocks、Squid等来搭建。具体安装方法可以参考它们的官方文
2023-08-18

HTTP代理​是如何实现的

本篇内容主要讲解“HTTP代理是如何实现的”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“HTTP代理是如何实现的”吧!通常,网络采用公共网络IP访问双网卡结构的INT网关,外部网卡实现ERNET
2023-06-20

如何进行C#Windows应用程序模板代码实现

本篇文章为大家展示了如何进行C#Windows应用程序模板代码实现,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。C#Windows应用程序开发之应用程序模板实现/* C#Windows应用程序模
2023-06-17

Java动态代理如何实现

本篇内容介绍了“Java动态代理如何实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!JDK动态代理:利用反射机制生成一个实现代理接口的匿名
2023-06-30

VB.NET如何实现通信程序

这篇文章主要为大家展示了“VB.NET如何实现通信程序”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“VB.NET如何实现通信程序”这篇文章吧。1 mscomm.vbx通信控件描述 mscomm.
2023-06-17

Python 备份程序代码实现

Python的一个备份程序 这是一个备份脚本。路径请自行更换。 这是一个备份脚本,按照当前日期分目录,以时间作为文件名,并且可以在文件名加入备注信息.以zip方式作为压缩方式, 有特殊需求可以更改. 实例代码:#! /usr/bin/pyt
2022-06-04

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录