当前位置: 首页 > news >正文

golang rpc

RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务,对应rpc的是本地过程调用,函数调用是最常用的本地过程调用,将本地过程调用变成远程调用会面临着各种问题。

以两数相加为例

package mainimport "fmt"func add(a, b int) int {return a + b
}
func main() {fmt.Println(add(1, 2))
}

函数调用过程:
(1)将1和2压入函数的栈中
(2)进入add函数,从栈中取出1和2分别赋值给a和b
(3)执行a+b将结果压栈
(4)将栈中的结果取出打印

远程过程面临的问题
1.原本的本地函数放到另外一个服务器上去运行,但是引入了很多新问题
2.Call的id映射
我们怎么告诉远程机器我们要调用add,而不是sub或者Foo呢?在本地调用中,函数体是直接通过函数指针来指定的,我们调用add,编译器就自动帮我们调用它相应的函数指针。但是在远程调用中,函数指针是不行的,因为两个进程的地址空间是完全不一样的。所以,在RPC中,所有的函数都必须有自己的一个ID。这个ID在所有进程中都是唯一确定的。客户端在做远程过程调用时,必须附上这个ID。然后我们还需要在客户端和服务端分别维护一个(函数<–>Call ID}的对应表。两者的表不一定需要完全相同,但相同的函数对应的Call ID必须相同。当客户端需要进行远程调用时,它就查一下这个表,找出相应的Call ID,然后把它传给服务端,服务端也通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。
3.序列化和反序列化
客户端怎么把参数值传给远程的函数呢?在本地调用中,我们只需要把参数压到栈里,然后让函数自己去栈里读就行。但是在远程过程调用时,客户端跟服务端是不同的进程,不能通过内存来传递参数。甚至有时候客户端和服务端使用的都不是同一种语言(比如服务端用C++,客户端用Java或者Python)。这时候就需要客户端把参数先转成一个字节流,传给服务端后,再把字节流转成自己能读取的格式。这个过程叫序列化和反序列化。同理,从服务端返回的值也需要序列化反序列化的过程。
4.网络传输
远程调用往往用在网络上,客户端和服务端是通过网络连接的。所有的数据都需要通过网络传输,因此就需要有一个网络传输层。网络传输层需要把Call ID和序列化后的参数字节流传给服务端,然后再把序列化后的调用结果传给客户端。只要能完成这两者的,都可以作为传输层使用。因此,他所使用的协议其实是不限的,能完成传输就行,尽管大部分RPC框架都使用TCP协议,但其实UDP也可以,而RPC干脆就用了HTTP2。Java的Netty也属于这层的东西。

RPC第一个要点:数据编码协议

一般采用将数据传输到gin,gin传输到服务端,服务端负责解析数据
客户端流程

	1.建立连接tcp/http2.将employee对象序列化成json字符串-序列化3.发送json字符串-调用成功后实际上你接受到的是一个二进制的数据4.等待服务器发送结果5将服务返回的数据解析成PrintResult对象-反序列化

服务端流程

	1.监听网络接口802.读取数据-二进制的json数据3.对数据进行反序列化Employee对象4.开始处理业务逻辑5.将处理的结果PrintReuslt发序列化成json二进制数据-序列化6.将数据返回

序列化和反序列化是可以选择的,不一定要采用json、xml、protobuf、msgpack

RPC第二个要点:传输协议

http协议:http1.x http2.0协议
http协议底层使用的也是tcp,http现在主流的是http1.x,这种协议有性能问题(一次性),一旦结果返回,连接就断开。我们可以直接基于tcp/udp协议去封装一层协议myhttp,没有通用型,http2.0既有http的特性也有长连接的特性(grpc就是基于http2.0的)
http协议是文本协议,http底层的传输协议是tcp。grpc基于http2.0,传输协议也是tcp
在这里插入图片描述
http协议具有一次性的问题:一旦对方返回了结果,连接断开,http2.0通过长连接解决了这个问题。

基于Http Server实现rpc请求

server端

package mainimport ("encoding/json""fmt""net/http""strconv"
)func add(a, b int) int {return a + b
}func main() {//get方法http://127.0.0.1:8000/add?a=1&b=2或http://127.0.0.1:8000?method=add&a=1&b=2//返回的格式化:json{"data":3}//1、callId的问题:r.URL.Path,2、数据的传输协议:url的参数传输协议,3、网络传输协议:httphttp.HandleFunc("/add", func(w http.ResponseWriter, r *http.Request) {err := r.ParseForm() //解析参数if err != nil {panic("error")}fmt.Println("path:", r.URL.Path)a, err := strconv.Atoi(r.Form["a"][0])if err != nil {panic("transform error")}b, err := strconv.Atoi(r.Form["b"][0])if err != nil {panic("transform error")}w.Header().Set("Content-Type", "application/json")jData, err := json.Marshal(map[string]int{"data": a + b,})w.Write(jData)})_ = http.ListenAndServe(":8000", nil)
}

在这里插入图片描述
缺点:http1.x,麻烦,性能不高
客户端:

package mainimport ("encoding/json""fmt""time""github.com/kirinlabs/HttpRequest"
)type ResponseData struct {Data int `json:"data"`
}func Add(a, b int) int {req := HttpRequest.NewRequest()res, _ := req.Get(fmt.Sprintf("http://127.0.0.1:8000/%s?a=%d&b=%d", "add", a, b))body, _ := res.Body()rspData := ResponseData{}_ = json.Unmarshal(body, &rspData)return rspData.Data
}
func main() {fmt.Println(Add(2, 2))
}

这里遇到了一个Get “http://127.0.0.1:8000/add?a=1&b=2”: context deadline exceeded (Client.Timeout exceeded while awaiting headers)的问题,主要是客户端默认网络请求时间太短
修改之后

package mainimport ("encoding/json""fmt""time""github.com/kirinlabs/HttpRequest"
)type ResponseData struct {Data int `json:"data"`
}func Add(a, b int) int {req := HttpRequest.NewRequest()req.SetTimeout(10 * time.Second)res, _ := req.Get(fmt.Sprintf("http://127.0.0.1:8000/%s?a=%d&b=%d", "add", a, b))body, _ := res.Body()rspData := ResponseData{}_ = json.Unmarshal(body, &rspData)return rspData.Data
}
func main() {fmt.Println(Add(2, 2))
}

rpc开发的要素分析

RPC技术在架构设计上有四部分组成,分别是:客户端、客户端存根、服务端、服务端存根。
客户端(Client):服务调用发起方,也称为服务消费者。
客户端存根(Client Stub):该程序运行在客户端所在的计算机机器上,主要用来存储要调用的服务器的地址,另外,该程序还负责将客户端请求远端服务器程序的数据信息打包成数据包,通过网络发送给服务端Stub程序;其次,还要接收服务端Stub程序发送的调用结果数据包,并解析返回给客户端。
服务端(Server):远端的计算机机器上运行的程序,其中有客户端要调用的方法。
服务端存根(Server Stub):接收客户Stub程序通过网络发送的请求消息数据包,并调用服务端中真正的程序功能方法,完成功能调用;其次,将服务端执行调用的结果进行数据处理打包发送给客户端Stub程序。

rpc需要使用到的术语

1、动态代理技术: 上文中我们提到的Client Stub和Sever Stub程序,在具体的编码和开发实践过程中,都是使用动态代理技术自动生成的一段程序。
序列化和反序列化: 在RPC调用的过程中,我们可以看到数据需要在一台机器上传输到另外一台机器上。在互联网上,所有的数据都是以字节的形式进行传输的。而我们在编程的过程中,往往都是使用数据对象,因此想要在网络上将数据对象和相关变量进行传输,就需要对数据对象做序列化和反序列化的操作。
序列化:把对象转换为字节序列的过程称为对象的序列化,也就是编码的过程。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化,也就是解码的过程。
我们常见的Json,XML等相关框架都可以对数据做序列化和反序列化编解码操作。后面我们要学习的Protobuf协议,这也是一种数据编解码的协议,在RPC框架中使用的更广泛。

简单的rpc实例

服务端

package mainimport ("net""net/rpc"
)type HelloService struct {
}func (s *HelloService) Hello(request string, reply *string) error {//返回值是通过修改reply的值*reply = "hello, " + requestreturn nil
}
func main() {//rpc快速开发体验//1.实例化一个serverlistener, _ := net.Listen("tcp", ":1234")//2.注册处理逻辑_ = rpc.RegisterName("HelloService", &HelloService{})//3.启动服务conn, _ := listener.Accept() //当一个新的连接进来的时候rpc.ServeConn(conn)
}

客户端

package mainimport ("encoding/json""fmt""net/rpc""time"
)func main() {//1.建立连接client, err := rpc.Dial("tcp", "localhost:1234")if err != nil {panic("连接失败")}var reply *string = new(string)err = client.Call("HelloService.Hello", "bobby", reply)if err != nil {panic("调用失败")}fmt.Println(*reply)
}

替换rpc的序列化协议为json

序列化协议为json,各种语言都可以调用服务端的内容
服务端

package mainimport ("net""net/rpc""net/rpc/jsonrpc"
)type HelloService struct {
}func (s *HelloService) Hello(request string, reply *string) error {//返回值是通过修改reply的值*reply = "hello, " + requestreturn nil
}
func main() {//替换rpc的序列化协议为json//1.实例化一个serverlistener, _ := net.Listen("tcp", ":1234")//2.注册处理逻辑_ = rpc.RegisterName("HelloService", &HelloService{})//3.启动服务conn, _ := listener.Accept() //当一个新的连接进来的时候rpc.ServeCodec(jsonrpc.NewServerCodec(conn))}

客户端

package mainimport ("encoding/json""fmt""net""net/rpc""net/rpc/jsonrpc""time""github.com/kirinlabs/HttpRequest"
)func main() {//替换rpc的序列化协议为json//1.建立连接conn, err := net.Dial("tcp", "localhost:1234")if err != nil {panic("连接失败")}var reply *string = new(string)client := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn))err = client.Call("HelloService.Hello", "bobby", reply)if err != nil {panic("调用失败")}fmt.Println(*reply)
}

python连接rpc,序列化协议为json

服务端

package mainimport ("net""net/rpc""net/rpc/jsonrpc"
)type HelloService struct {
}func (s *HelloService) Hello(request string, reply *string) error {//返回值是通过修改reply的值*reply = "hello, " + requestreturn nil
}
func main() {//替换rpc的序列化协议为json//1.实例化一个serverlistener, _ := net.Listen("tcp", ":1234")//2.注册处理逻辑_ = rpc.RegisterName("HelloService", &HelloService{})//3.启动服务conn, _ := listener.Accept() //当一个新的连接进来的时候rpc.ServeCodec(jsonrpc.NewServerCodec(conn))}

客户端

import json
import socket
request={"id":0,"params":["bobby"],"method":"HelloService.Hello"
}
client=socket.create_connection(("localhost",1234))
client.sendall(json.dumps(request).encode())
#获取服务器返回的数据
rsp=client.recv(4096)
rsp=json.loads(rsp.decode())
print(rsp)

替换rpc的传输协议为http

服务端

package mainimport ("io""net/http""net/rpc""net/rpc/jsonrpc"
)
type HelloService struct {
}func (s *HelloService) Hello(request string, reply *string) error {//返回值是通过修改reply的值*reply = "hello, " + requestreturn nil
}
func main() {//替换rpc的序列化协议为http//2.注册处理逻辑_ = rpc.RegisterName("HelloService", &HelloService{})http.HandleFunc("/jsonrpc", func(w http.ResponseWriter, r *http.Request) {var conn io.ReadWriteCloser = struct {io.Writerio.ReadCloser}{ReadCloser: r.Body,Writer:     w,}rpc.ServeRequest(jsonrpc.NewServerCodec(conn))})http.ListenAndServe(":1234", nil)
}

客户端

import requests
request={"id":0,"params":["bobby"],"method":"HelloService.Hello"
}
rsp=requests.post("http://localhost:1234/jsonrpc",json=request)
print(rsp.text)

客户端

package mainimport ("encoding/json""fmt""net/rpc""time""github.com/kirinlabs/HttpRequest"
)func main() {//1.实例化一个client, err := rpc.Dial("tcp", "127.0.0.1:1234")if err != nil {panic("连接失败")}var reply stringerr = client.Call("HelloService.Hello", "bobby", &reply)if err != nil {// panic("调用失败")fmt.Println(err)}fmt.Println(reply)
}

代理封装

代理类

package handlerimport "net/rpc"const HelloServiceName = "HelloServiceName"type HelloServiceStub struct {*rpc.Client
}func NewHelloServiceClient(protcol, address string) HelloServiceStub {conn, err := rpc.Dial(protcol, address)if err != nil {panic("connect error!")}return HelloServiceStub{conn}
}
func (c *HelloServiceStub) Hello(request string, reply *string) error {err := c.Call(HelloServiceName+".Hello", request, reply)if err != nil {return err}return nil
}type HelloService struct {
}func (s *HelloService) Hello(request string, reply *string) error {//返回值是通过修改reply的值*reply = "hello, " + requestreturn nil
}func RegisterHelloService() error {return rpc.RegisterName(HelloServiceName, &HelloService{})
}

服务端

package mainimport ("TEMP/handler""net""net/rpc"
)func main() {//进一步改造rpc调用的代码//1.实例化一个serverlistener, _ := net.Listen("tcp", ":1234")//2.注册处理逻辑handler_ = handler.RegisterHelloService()//3.启动服务conn, _ := listener.Accept() //当一个新的连接进来的时候rpc.ServeConn(conn)}

客户端

package mainimport ("TEMP/handler""fmt"
)func main() {//进一步改造rpc调用的代码//1.实例化一个client := handler.NewHelloServiceClient("tcp", "127.0.0.1:1234")var reply stringerr := client.Hello("bobby", &reply)if err != nil {// panic("调用失败")fmt.Println(err)}fmt.Println(reply)
}

解耦合

将服务端的Hello函数传递变换成接口类型
代理类

package handlerimport "net/rpc"const HelloServiceName = "HelloServiceName"type HelloServiceStub struct {*rpc.Client
}func NewHelloServiceClient(protcol, address string) HelloServiceStub {conn, err := rpc.Dial(protcol, address)if err != nil {panic("connect error!")}return HelloServiceStub{conn}
}
func (c *HelloServiceStub) Hello(request string, reply *string) error {err := c.Call(HelloServiceName+".Hello", request, reply)if err != nil {return err}return nil
}type NewHelloService struct {
}
type HelloServicer interface {Hello(request string, reply *string) error
}func (s *NewHelloService) Hello(request string, reply *string) error {//返回值是通过修改reply的值*reply = "hello, " + requestreturn nil
}func RegisterHelloService() error {return rpc.RegisterName(HelloServiceName, &NewHelloService{})
}

服务端

package mainimport ("TEMP/handler""net""net/rpc"
)func main() {//进一步改造rpc调用的代码//1.实例化一个serverlistener, _ := net.Listen("tcp", ":1234")//2.注册处理逻辑handler_ = handler.RegisterHelloService()//3.启动服务conn, _ := listener.Accept() //当一个新的连接进来的时候rpc.ServeConn(conn)}

客户端

package mainimport ("TEMP/handler""fmt"
)func main() {//进一步改造rpc调用的代码//1.实例化一个client := handler.NewHelloServiceClient("tcp", "127.0.0.1:1234")var reply stringerr := client.Hello("bobby", &reply)if err != nil {// panic("调用失败")fmt.Println(err)}fmt.Println(reply)
}

相关文章:

golang rpc

RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务,对应rpc的是本地过程调用,函数调用是最常用的本地过程调用,将本地过程调用变成远程调用会面临着各种问题。 以两数…...

A Learning-Based Approach to Static Program Slicing —— 论文笔记

A Learning-Based Approach to Static Program Slicing OOPLSA’2024 文章目录 A Learning-Based Approach to Static Program Slicing1. Abstract2. Motivation(1) 为什么需要能处理不完整代码(2) 现有方法局限性(3) 验证局限性: 初步实验研究实验设计何为不完整代码实验结果…...

掌握 C# 中的委托与事件机制

C# 中的委托和事件为开发者提供了处理回调、异步编程以及发布订阅模式的强大工具。委托与事件机制在实际应用中非常常见,特别是在事件驱动编程和 GUI 应用中。本文将带你深入理解委托的定义、匿名方法、Lambda 表达式、事件机制以及多播委托的使用。 1. 委托&#x…...

使用微服务Spring Cloud集成Kafka实现异步通信(消费者)

1、本文架构 本文目标是使用微服务Spring Cloud集成Kafka实现异步通信。其中Kafka Server部署在Ubuntu虚拟机上,微服务部署在Windows 11系统上,Kafka Producer微服务和Kafka Consumer微服务分别注册到Eureka注册中心。Kafka Producer和Kafka Consumer之…...

docker pull 超时Timeout失败的解决办法

当国内开发者docker pull遇到如下提示时,不要惊讶 [rootvm /]# docker pull postgres Using default tag: latest Error response from daemon: Get "https://registry-1.docker.io/v2/": dial tcp 128.121.146.235:443: i/o timeout [rootvm /]# 自2024…...

YOLOv7改进之主干DAMOYOLO结构,结合 CReToNeXt 结构,打造高性能检测器

一、DAMOYOLO理论部分 论文地址:2211.15444 (arxiv.org) 在本报告中,我们提出了一种快速准确的对象检测方法,称为 DAMO-YOLO,它实现了比最先进的 YOLO 系列更高的性能。DAMO-YOLO 是从 YOLO 扩展而来的,具有一些新技术,包括神经架构搜索 (NAS)、高效的重新参数化广义 …...

进度条(倒计时)Linux

\r回车(回到当前行开头) \n换行 行缓冲区概念 什么现象? 什么现象?? 什么现象??? 自己总结: #pragma once 防止头文件被重复包含 倒计时 在main.c中,windows.h是不可以用的&…...

[每周一更]-(第117期):硬盘分区表类型:MBR和GPT区别

文章目录 1. **支持的磁盘容量**2. **分区数量**3. **引导方式**4. **冗余和数据恢复**5. **兼容性**6. **安全性**7. **操作系统支持**8. 对比 国庆假期前补一篇 在一次扫描机械硬盘故障的问题,发现我本机SSD和机械硬盘的分类型不一样,分别是GPT和MBR&a…...

河南移动:核心营业系统稳定运行超300天,数据库分布式升级实践|OceanBase案例

河南移动,作为电信全业务运营企业,不仅拥有庞大的客户群体和业务规模,还引领着业务产品与服务体系的创新发展。河南移动的原有核心营业系统承载着超过6000万的庞大用户量,管理着超过80TB的海量数据,因此也面临着数据规…...

22.1 k8s不同role级别的服务发现

本节重点介绍 : 服务发现的应用3种采集的k8s服务发现role 容器基础资源指标 role :nodek8s服务组件指标 role :endpoint部署在pod中业务埋点指标 role :pod 服务发现的应用 所有组件将自身指标暴露在各自的服务端口上,prometheus通过pull过来拉取指标但是promet…...

OpenCV计算机视觉库

计算机视觉和图像处理 Tensorflow入门深度神经网络图像分类目标检测图像分割OpenCVPytorchNLP自然语言处理 OpenCV 一、OpenCV简介1.1 简介1.2 OpenCV部署1.3 OpenCV模块 二、OpenCV基本操作2.1 图像的基本操作2.1.1 图像的IO操作2.1.2 绘制几何图像2.1.3 获取并修改图像的像素…...

CentOS 系统中的文件挂载 U 盘

要将 CentOS 系统中的文件保存到 U 盘,可以按照以下步骤进行操作: 一、插入 U 盘并确定设备名称 将 U 盘插入 CentOS 系统的 USB 接口。使用 fdisk -l 命令查看系统中的磁盘和分区情况,确定 U 盘的设备名称。通常 U 盘会显示为类似于 /dev/…...

Lumerical脚本语言-变量操作(Manipulating variables)

下面的命令用来创建和存取变量。 命令描述= 赋值操作符 :数组操作符 []创建矩阵 % 创建包含空格的变量名称 linspace 创建线性空间数组 matrix 创建一个全为 0 的矩阵 randmatrix 创建一个所有元素为 0~1 之间的一个随机数的矩阵 randnmatrix 创建一个所有元素为平均值为 0…...

一个基本的包括爬虫、数据存储和前端展示框架0

创建一个完整的网络爬虫和前端展示页面是一个涉及多个步骤和技术的任务。下面我将为你提供一个基本的框架,包括爬虫代码(使用Python和Scrapy框架)和前端HTML页面(伏羲.html)。 爬虫代码 (使用Scrapy) 首先,你需要安装Scrapy库:bash pip install scrapy 然后,创建一个新…...

简历制作面试篇

一.面试技巧分析 模板: 推荐使用简洁一点的模板,不要太花哨,能够让HR和面试官清楚,快速知道信息就可以,太花哨容易分散别人的注意力。 格式: 一般选用PDF,不要用WORD。 照片: 技术岗一般不用贴照片,推进写上自己的联系方式或者微信。 专业技能: 描述专业技能…...

智能制造--EAP设备自动化程序

EAP是设备自动化程序(Equipment Automation Program)的缩写,他是一种用于控制制造设备进行自动化生产的系统。EAP系统与MES系统整合,校验产品信息,自动做账,同时收集产品生产过程中的制程数据和设备参数数据…...

LabVIEW混合控制器质量检测

随着工业自动化水平的提高,对控制器的精度、稳定性、可靠性要求也在不断上升。特别是在工程机械、自动化生产、风力发电等领域,传统的质量检测方法已无法满足现代工业的高要求。因此,开发一套自动化、精确、可扩展的混合控制器质量检测平台成…...

新技术浪潮下的等保测评:云计算、物联网与大数据的挑战与机遇

随着信息技术的飞速发展,云计算、物联网(IoT)和大数据等新兴技术正以前所未有的速度改变着我们的生活和工作方式。这些技术的广泛应用不仅为信息系统带来了前所未有的性能提升,同时也对等保测评(信息安全等级保护测评&…...

微信小程序技术框架选型

“近期在对团队的微信小程序进行技术框架选型,故对目前主流的微信小程序技术框架进行了一些分析和比较,包括各框架的维护团队、社区链接、GitHub star数、优缺点对比等方面,为团队提供技术框架选型参考” 一、引言 随着移动互联网的快速发展…...

SQL学习3

24.10.3学习目录 一.c语言操作数据库 一.c语言操作数据库 (1)打开、关闭数据库函数 //打开数据库 int sqlite3_open(char *db_name,sqlite3 **db);db_name:数据库文件名,若文件名中有ASCLL码中以外的字符,其必须为UT…...

Linux:进程控制(一)

目录 一、写时拷贝 1.创建子进程 2.写时拷贝 二、进程终止 1.函数返回值 2.错误码 3.异常退出 4.exit 5._exit 一、写时拷贝 父子进程,代码共享,不作写入操作时,数据也是共享的,当任意一方试图写入,便通过写时拷…...

初识算法 · 双指针(3)

目录 前言: 和为s的两数之和 题目解析: ​编辑 算法原理: 算法编写: 三数之和 题目解析 算法原理 算法编写 前言: 本文通过介绍和为S的两数之和,以及三数之和,对双指针算法进行深一步…...

【AI知识点】近似最近邻搜索(ANN, Approximate Nearest Neighbor Search)

近似最近邻搜索(ANN, Approximate Nearest Neighbor Search) 是一种用于高维数据检索的技术,目标是在给定查询的情况下,快速找到距离查询点最近的数据点,尽管结果可能并不完全精确。这种方法特别适用于高维数据&#x…...

编程工具简介

在编程工作中,选择合适的工具确实能够显著提升工作效率。以下是一些被广泛推荐的工具: 1. Visual Studio Code (VS Code):这是一款轻量级但功能强大的代码编辑器,支持多种编程语言,拥有丰富的插件生态系统&#xff0…...

汽车信息安全 -- 存到HSM中的密钥还需包裹吗?

目录 1.车规芯片的ROM_KEY 2.密钥加密与包裹 3.瑞萨RZ\T2M的密钥导入 4.小结 在车控类ECU中,我们通常把主控芯片MCU中的HSM以及HSM固件统一看做整个系统安全架构的信任根。 所以大家默认在HSM内部存储的数据等都是可信的,例如CycurHSM方案中使用HSM…...

【PostgreSQL】入门篇——SELECT、INSERT、UPDATE 和 DELETE 语句,SQL 中最常用的四种操作用法

1. SELECT 语句 描述 SELECT 语句用于从数据库中查询数据。可以选择特定的列或所有列,并可以通过条件过滤结果。 语法 SELECT column1, column2, ... FROM table_name WHERE condition;示例 假设我们有一个名为 employees 的表,结构如下&#xff1a…...

【Ubuntu】安装常用软件包-mysql

我的几个服务是部署在docker的同一个网络里,这样相互访问就可以通过docker容器的名字访问,比如容器A访问容器B,就可以http://B:8080/xxx 这样访问,不用关心ip是多少。 所以mysql前面文章给安装到主机里,感觉有点坑自己…...

幂等性及技术解决方案

文章目录 定义幂等性 为什么需要幂等性幂等性设计注意事项幂等性的范围分布式锁解决幂等性 设计 延伸阅读 定义幂等性 简单地说,我们可以多次执行幂等运算而不改变结果或者使用相同的输入参数中被调用多次,则不具有额外效果的操作,也就是多…...

正向代理 反向代理

正向代理 正向代理是一种网络服务,它作为客户端和目标服务器之间的中间人,代表客户端向目标服务器发送请求并接收响应。以下是关于正向代理的详细解释: 工作原理 客户端配置: 客户端(如浏览器)配置为使用…...

【分布式微服务云原生】如何在ActiveMQ中优雅处理提前支付的延时订单

摘要 本文将深入探讨在ActiveMQ中如何处理用户提前支付的延时订单问题。我们将介绍如何通过更新订单状态、检查延迟任务、取消延迟消息、使用死信队列、消息选择性消费、设置合理的超时时间以及及时反馈和日志记录等策略,来确保系统的一致性和及时响应用户操作。文…...

电商系统的服务商/seo关键词优化软件合作

方法一:使用ActivityLifecycleCallbacksandroid 在从sdk14 开始为我们提供了一个新的api 用于检测app 中activity 的生命周期,我们可以直接使用。publicinterfaceActivityLifecycleCallbacks{voidonActivityCreated(Activity activity, Bundle savedInst…...

上海网站分站建设/移动端关键词排名优化

分析: 1.深度优先更适合目标比较明确,以找到目标为主要目的的情况 2.广度优先更适合在不断扩大遍历范围时找到相对最优解的情况 因此这里选用BFS—广度优先遍历 思路:这里要找到转机次数最少的方案,就是要寻找从V0顶点走到V4顶点…...

怎么做盗版网站赚钱/搜索推广代运营

已经编译好的没源码的 so以及 apk 编译进系统的步骤android1 .so 文件 编译进系统的 system/lib64app/vendor/mediatek/proprietary/external/ 目录下建立存放库文件的子目录, 以 libsslwrapper_jni.so 文件为例orm1. Android.mk:sslinclude $(CLEAR_VARS)LOCAL_MOD…...

网页微信版收藏健/杭州seo排名费用

1169 传纸条 2008年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵&am…...

云南网站建设哪个好/买卖网站

题目链接&#xff1a;http://www.51nod.com/onlineJudge/questionCode.html#!problemId1416 题意&#xff1a;中文题诶&#xff5e; 思路&#xff1a;dfs 搜索同一颜色的点。。 只要不往返回方向走&#xff0c;遇到以标记的点即出现了环。。。 代码&#xff1a; 1 #include <…...

网络和网站的区别/淘宝数据查询

之前的文章中讲到&#xff0c;JMM是内存模型规范在Java语言中的体现。JMM保证了在多核CPU多线程编程环境下&#xff0c;对共享变量读写的原子性、可见性和有序性。本文就具体来讲讲JMM是如何保证共享变量访问的原子性的。原子性问题#原子性是指&#xff1a;一个或多个操作&…...