【gRPC学习】使用go学习gRPC

个人博客:Sekyoro的博客小屋
个人网站:Proanimer的个人网站
RPC是远程调用,而google实现了grpc比较方便地实现了远程调用,gRPC是一个现代的开源远程过程调用(RPC)框架

概念介绍

在gRPC中,客户端应用程序可以直接调用另一台计算机上的服务器应用程序上的方法,就好像它是本地对象一样。

远程过程调用是一个分布式计算的客户端-服务器(Client/Server)的例子,它简单而又广受欢迎。
远程过程调用总是由客户端对服务器发出一个执行若干过程请求,并用客户端提供的参数。执行结果将返回给客户端。
由于存在各式各样的变体和细节差异,对应地派生了各式远程过程调用协议,而且它们并不互相兼容。

为了允许不同的客户端均能访问服务器,许多标准化的 RPC 系统应运而生了。其中大部分采用接口描述语言(Interface Description Language,IDL),方便跨平台的远程过程调用

与许多RPC系统一样,gRPC基于定义服务的思想,指定可以通过其参数和返回类型远程调用的方法。在服务器端,服务器实现了这个接口,并运行gRPC服务器来处理客户端调用。在客户端,客户端有一个stub(在某些语言中称为客户端),它提供与服务器相同的方法。

它具有许多特性

  1. 强大的IDL特性
    RPC使用ProtoBuf来定义服务,ProtoBuf是由Google开发的一种数据序列化协议,性能出众,得到了广泛的应用。
  2. 支持多种语言
    支持C++、Java、Go、Python、Ruby、C#、Node.js、Android Java、Objective-C、PHP等编程语言。
  3. 基于HTTP/2标准设计

在这里插入图片描述

默认情况下,gRPC使用Protocol Buffers,这是谷歌成熟的开源机制,用于序列化结构化数据(尽管它可以与JSON等其他数据格式一起使用)

与REST差异

RPC 的消息传输可以通过 TCP、UDP 或者 HTTP等,所以有时候我们称之为 RPC over TCP、 RPC over HTTP。

RPC 通过 HTTP 传输消息的时候和 RESTful的架构是类似的,但是也有不同。

  • gRPC使用HTTP/2,而REST使用HTTP1.1
  • gRPC使用协议缓冲区数据格式,而不是REST API中通常使用的标准JSON数据格式
  • 使用gRPC,可以利用HTTP/2功能,如服务器端流式传输、客户端流式传输,甚至双向流式传输

首先 RPC 的客户端和服务器端师紧耦合的,客户端需要知道调用的过程的名字,过程的参数以及它们的类型、顺序等。一旦服务器更改了过程的实现,客户端的实现很容易出问题。RESTful基于 http的语义操作资源,参数的顺序一般没有关系,也很容易的通过代理转换链接和资源位置,从这一点上来说,RESTful 更灵活。

其次,它们操作的对象不一样。 RPC 操作的是方法和过程,它要操作的是方法对象。 RESTful 操作的是资源(resource),而不是方法。

第三,RESTful执行的是对资源的操作,增加、查找、修改和删除等,主要是CURD,所以如果你要实现一个特定目的的操作,比如为名字姓张的学生的数学成绩都加上10这样的操作,
RESTful的API设计起来就不是那么直观或者有意义。在这种情况下, RPC的实现更有意义,它可以实现一个直接的方法方法供客户端调用

RPC over TCP可以通过长连接减少连接的建立所产生的花费,在调用次数非常巨大的时候(这是目前互联网公司经常遇到的情况,大并发的情况下),这个花费影响是非常巨大的。
当然 RESTful 也可以通过 keep-alive 实现长连接, 但是它最大的一个问题是它的request-response模型是阻塞的 (http1.0和 http1.1, http 2.0没这个问题),
发送一个请求后只有等到response返回才能发送第二个请求 (有些http server实现了pipeling的功能,但不是标配), RPC的实现没有这个限制。

其他RPC框架

目前的 RPC 框架大致有两种不同的侧重方向,一种偏重于服务治理,另一种偏重于跨语言调用

服务治理型的 RPC 框架有Alibabs Dubbo、Motan 等,这类的 RPC 框架的特点是功能丰富,提供高性能的远程调用以及服务发现和治理功能,适用于大型服务的微服务化拆分以及管理,对于特定语言(Java)的项目可以十分友好的透明化接入。但缺点是语言耦合度较高,跨语言支持难度较大。

跨语言调用型的 RPC 框架有 Thrift、gRPC、Hessian、Finagle 等,这一类的 RPC 框架重点关注于服务的跨语言调用,能够支持大部分的语言进行语言无关的调用,非常适合于为不同语言提供通用远程服务的场景。但这类框架没有服务发现相关机制,实际使用时一般需要代理层进行请求转发和负载均衡策略控制。

thrift是Apache的一个跨语言的高性能的服务框架,也得到了广泛的应用。它的功能类似 gRPC, 支持跨语言,不支持服务治理。

rpcx 是一个分布式的Go语言的 RPC 框架,支持Zookepper、etcd、consul多种服务发现方式,多种服务路由方式, 是目前性能最好的 RPC 框架之一

使用protobuf

定义要在proto文件中序列化的数据的结构:这是一个扩展名为.proto的普通文本文件。协议缓冲区数据被构造为消息,其中每个消息都是一个包含一系列名值对(称为字段)的信息的小逻辑记录。

message Person {string name = 1;int32 id = 2;bool has_ponycopter = 3;
}

指定了数据结构,就可以使用协议缓冲区编译器protoc从proto定义中生成首选语言的数据访问类.

它们为每个字段提供了简单的访问器,如name()和set_name(),以及将整个结构序列化到原始字节/从原始字节解析整个结构的方法。

因此,例如,如果选择的语言是C++,那么在上面的示例中运行编译器将生成一个名为Person的类。然后,您可以在应用程序中使用此类来填充、序列化和检索Person协议缓冲区消息。

gRPC使用protoc和一个特殊的gRPC插件从proto文件中生成代码:可以获得生成的gRPC客户端和服务器代码,以及用于填充、序列化和检索消息类型的常规协议缓冲区代码。(截至目前protobuf最新版本是v3)

gRPC in Go

下载protoc

虽然不是强制性的,但gRPC应用程序通常利用proto buffer进行服务定义和数据序列化。

Releases · protocolbuffers/protobuf (github.com)

protoc用于编译.proto文件,其中包含服务和消息定义,Linux或Mac直接使用对应包管理器下载即可

apt install -y protobuf-compiler
protoc --version  # Ensure compiler version is 3+

Windows在github上下载二进制包Releases · protocolbuffers/protobuf (github.com)

protocol compiler的Go插件

下载protoc-go-gen
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28

下载zip的文件

git clone -b v1.60.1 --depth 1 https://github.com/grpc/grpc-go
proto文件

下面定义了服务

// Interface exported by the server.
service RouteGuide {// A simple RPC.//// Obtains the feature at a given position.//// A feature with an empty name is returned if there's no feature at the given// position.rpc GetFeature(Point) returns (Feature) {}// A server-to-client streaming RPC.//// Obtains the Features available within the given Rectangle.  Results are// streamed rather than returned at once (e.g. in a response message with a// repeated field), as the rectangle may cover a large area and contain a// huge number of features.rpc ListFeatures(Rectangle) returns (stream Feature) {}// A client-to-server streaming RPC.//// Accepts a stream of Points on a route being traversed, returning a// RouteSummary when traversal is completed.rpc RecordRoute(stream Point) returns (RouteSummary) {}// A Bidirectional streaming RPC.//// Accepts a stream of RouteNotes sent while a route is being traversed,// while receiving other RouteNotes (e.g. from other users).rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
}

其中涉及到一些参数message表示传递数据.

// Points are represented as latitude-longitude pairs in the E7 representation
// (degrees multiplied by 10**7 and rounded to the nearest integer).
// Latitudes should be in the range +/- 90 degrees and longitude should be in
// the range +/- 180 degrees (inclusive).
message Point {int32 latitude = 1;int32 longitude = 2;
}// A latitude-longitude rectangle, represented as two diagonally opposite
// points "lo" and "hi".
message Rectangle {// One corner of the rectangle.Point lo = 1;// The other corner of the rectangle.Point hi = 2;
}// A feature names something at a given point.
//
// If a feature could not be named, the name is empty.
message Feature {// The name of the feature.string name = 1;// The point where the feature is detected.Point location = 2;
}// A RouteNote is a message sent while at a given point.
message RouteNote {// The location from which the message is sent.Point location = 1;// The message to be sent.string message = 2;
}// A RouteSummary is received in response to a RecordRoute rpc.
//
// It contains the number of individual points received, the number of
// detected features, and the total distance covered as the cumulative sum of
// the distance between each point.
message RouteSummary {// The number of points received.int32 point_count = 1;// The number of known features passed while traversing the route.int32 feature_count = 2;// The distance covered in metres.int32 distance = 3;// The duration of the traversal in seconds.int32 elapsed_time = 4;
}

生成的两个文件包括message实现和用于server,client的代码

在pb.go文件中对于每个message实现了其type,比如对于Rectangle

type Rectangle struct {state         protoimpl.MessageStatesizeCache     protoimpl.SizeCacheunknownFields protoimpl.UnknownFields// One corner of the rectangle.Lo *Point `protobuf:"bytes,1,opt,name=lo,proto3" json:"lo,omitempty"`// The other corner of the rectangle.Hi *Point `protobuf:"bytes,2,opt,name=hi,proto3" json:"hi,omitempty"`
}
func (x *Rectangle) Reset() {*x = Rectangle{}if protoimpl.UnsafeEnabled {mi := &file_routeguide_route_guide_proto_msgTypes[1]ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))ms.StoreMessageInfo(mi)}
}func (x *Rectangle) String() string {return protoimpl.X.MessageStringOf(x)
}func (*Rectangle) ProtoMessage() {}func (x *Rectangle) ProtoReflect() protoreflect.Message {mi := &file_routeguide_route_guide_proto_msgTypes[1]if protoimpl.UnsafeEnabled && x != nil {ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))if ms.LoadMessageInfo() == nil {ms.StoreMessageInfo(mi)}return ms}return mi.MessageOf(x)
}// Deprecated: Use Rectangle.ProtoReflect.Descriptor instead.
func (*Rectangle) Descriptor() ([]byte, []int) {return file_routeguide_route_guide_proto_rawDescGZIP(), []int{1}
}func (x *Rectangle) GetLo() *Point {if x != nil {return x.Lo}return nil
}func (x *Rectangle) GetHi() *Point {if x != nil {return x.Hi}return nil
}

对于Client来说,定义接口.首先使用grpc库中的grpc.ClientConnInterface作为routeGuideClient的成员.

type routeGuideClient struct {cc grpc.ClientConnInterface
}

给结构体routeGuideClient实现多个方法,并定义接口

type RouteGuideClient interface {// A simple RPC.//// Obtains the feature at a given position.//// A feature with an empty name is returned if there's no feature at the given// position.GetFeature(ctx context.Context, in *Point, opts ...grpc.CallOption) (*Feature, error)// A server-to-client streaming RPC.//// Obtains the Features available within the given Rectangle.  Results are// streamed rather than returned at once (e.g. in a response message with a// repeated field), as the rectangle may cover a large area and contain a// huge number of features.ListFeatures(ctx context.Context, in *Rectangle, opts ...grpc.CallOption) (RouteGuide_ListFeaturesClient, error)// A client-to-server streaming RPC.//// Accepts a stream of Points on a route being traversed, returning a// RouteSummary when traversal is completed.RecordRoute(ctx context.Context, opts ...grpc.CallOption) (RouteGuide_RecordRouteClient, error)// A Bidirectional streaming RPC.//// Accepts a stream of RouteNotes sent while a route is being traversed,// while receiving other RouteNotes (e.g. from other users).RouteChat(ctx context.Context, opts ...grpc.CallOption) (RouteGuide_RouteChatClient, error)
}

然后通过NewRouteGuideClient返回结构体

func NewRouteGuideClient(cc grpc.ClientConnInterface) RouteGuideClient {return &routeGuideClient{cc}
}

实现结构体的方法

func (c *routeGuideClient) GetFeature(ctx context.Context, in *Point, opts ...grpc.CallOption) (*Feature, error) {out := new(Feature)err := c.cc.Invoke(ctx, RouteGuide_GetFeature_FullMethodName, in, out, opts...)if err != nil {return nil, err}return out, nil
}func (c *routeGuideClient) ListFeatures(ctx context.Context, in *Rectangle, opts ...grpc.CallOption) (RouteGuide_ListFeaturesClient, error) {stream, err := c.cc.NewStream(ctx, &RouteGuide_ServiceDesc.Streams[0], RouteGuide_ListFeatures_FullMethodName, opts...)if err != nil {return nil, err}x := &routeGuideListFeaturesClient{stream}if err := x.ClientStream.SendMsg(in); err != nil {return nil, err}if err := x.ClientStream.CloseSend(); err != nil {return nil, err}return x, nil
}

如果涉及stream还有新的结构,定义结构体,方法和接口


type RouteGuide_ListFeaturesClient interface {Recv() (*Feature, error)grpc.ClientStream
}type routeGuideListFeaturesClient struct {grpc.ClientStream
}func (x *routeGuideListFeaturesClient) Recv() (*Feature, error) {m := new(Feature)if err := x.ClientStream.RecvMsg(m); err != nil {return nil, err}return m, nil
}

对于server类似,定义接口

type RouteGuideServer interface {// A simple RPC.//// Obtains the feature at a given position.//// A feature with an empty name is returned if there's no feature at the given// position.GetFeature(context.Context, *Point) (*Feature, error)// A server-to-client streaming RPC.//// Obtains the Features available within the given Rectangle.  Results are// streamed rather than returned at once (e.g. in a response message with a// repeated field), as the rectangle may cover a large area and contain a// huge number of features.ListFeatures(*Rectangle, RouteGuide_ListFeaturesServer) error// A client-to-server streaming RPC.//// Accepts a stream of Points on a route being traversed, returning a// RouteSummary when traversal is completed.RecordRoute(RouteGuide_RecordRouteServer) error// A Bidirectional streaming RPC.//// Accepts a stream of RouteNotes sent while a route is being traversed,// while receiving other RouteNotes (e.g. from other users).RouteChat(RouteGuide_RouteChatServer) errormustEmbedUnimplementedRouteGuideServer()
}
实现server和client

当使用protoc生成文件之后,就可以写server和client了.

server

定义结构体,注意定义时加上pb.UnimplementedRouteGuideServer这样避免有些方法没有实现.

type routeGuideServer struct {pb.UnimplementedRouteGuideServersavedFeatures []*pb.Feature // read-only after initializedmu         sync.Mutex // protects routeNotesrouteNotes map[string][]*pb.RouteNote
}

实现接口满足的方法.

func (s *routeGuideServer) GetFeature(ctx context.Context, point *pb.Point) (*pb.Feature, error)
func (s *routeGuideServer) ListFeatures(rect *pb.Rectangle, stream pb.RouteGuide_ListFeaturesServer) 
func (s *routeGuideServer) RecordRoute(stream pb.RouteGuide_RecordRouteServer) 
func (s *routeGuideServer) RouteChat(stream pb.RouteGuide_RouteChatServer)

然后使用tcp链接新建grpc服务

func main() {flag.Parse()lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port))if err != nil {log.Fatalf("failed to listen: %v", err)}var opts []grpc.ServerOptionif *tls {if *certFile == "" {*certFile = data.Path("x509/server_cert.pem")}if *keyFile == "" {*keyFile = data.Path("x509/server_key.pem")}creds, err := credentials.NewServerTLSFromFile(*certFile, *keyFile)if err != nil {log.Fatalf("Failed to generate credentials: %v", err)}opts = []grpc.ServerOption{grpc.Creds(creds)}}grpcServer := grpc.NewServer(opts...)pb.RegisterRouteGuideServer(grpcServer, newServer())grpcServer.Serve(lis)
}

上面使用pb.RegisterRouteGuideServer注册服务,参数分别是grpc服务和newServer返回的结构体

client
func printFeature(client pb.RouteGuideClient, point *pb.Point) {log.Printf("Getting feature for point (%d, %d)", point.Latitude, point.Longitude)ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)defer cancel()feature, err := client.GetFeature(ctx, point)if err != nil {log.Fatalf("client.GetFeature failed: %v", err)}log.Println(feature)
}

利用context创建ctx和cancel,利用client := pb.NewRouteGuideClient(conn)创建client调用方法.

NewRouteGuideClient返回对应的client接口

func NewRouteGuideClient(cc grpc.ClientConnInterface) RouteGuideClient {return &routeGuideClient{cc}
}

gRPC面临的挑战

虽然gRPC确实允许您使用这些较新的技术,但gRPC服务的原型设计更具挑战性,因为无法使用Postman HTTP客户端等工具来轻松地与您公开的gRPC服务交互。你确实有一些选择可以实现这一点,但这并不是一种在本地就可以获得的东西。

有一些选项可以使用诸如特使之类的工具来反转代理标准JSON请求,并将其转码为正确的数据格式,但这是一个额外的依赖项,对于简单的项目来说,设置它可能很困难。

参考资料

  1. Documentation | gRPC
  2. Go gRPC Beginners Tutorial | TutorialEdge.net
  3. [Go RPC开发简介 - 官方RPC库 - 《Go RPC开发指南 中文文档]》 - 书栈网 · BookStack
  4. RESTful API 最佳实践 - 阮一峰的网络日志 (ruanyifeng.com)
  5. Basics tutorial | Go | gRPC
  6. What is gRPC? | gRPC

如有疑问,欢迎各位交流!

服务器配置
宝塔:宝塔服务器面板,一键全能部署及管理
云服务器:阿里云服务器
Vultr服务器
GPU服务器:Vast.ai

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/603406.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

认识加密和解密

加密技术源远流长,自从古代有了信息的传递和存储,就有了加密技术的运用。此后,很长一段时间里,加密及解密技术在军事、政治、外交、金融等特殊领域里被普遍采用,并经过长时间的研究和发展,形成了比较完备的…

element plus 表格组件怎样在表格中显示图片

官方给的&#xff1a; <el-table-column label"Thumbnail" width"180"><template #default"scope"><div style"display: flex; align-items: center"><el-image :preview-src-list"srcList"/><…

一起玩儿物联网人工智能小车(ESP32)——24. 变量与函数(二)

摘要&#xff1a;本文介绍变量和函数的基本知识 在前面一篇中了解了变量&#xff0c;接着就来了解一下函数。函数是程序中的一个关键概念&#xff0c;它可以简化程序的编写&#xff0c;使代码更加模块化、可复用&#xff0c;提高程序的可读性。其实在之前已经多次遇到函数了&am…

Arduion Modbus通讯示例

实现了Arduion和Qt上位机利用Modbus协议采集DHT11数据&#xff0c;以及开关LED灯 软件界面&#xff1a; 实物界面&#xff1a; arduion下位机代码&#xff1a; #include <ModbusRtu.h> #include <DHT.h>#define DHTPIN 2 // DHT11连接到Arduino的数字引…

使用C#发送邮箱验证码

使用C#发送邮箱验证码 在很多应用程序中&#xff0c;我们需要使用邮箱来进行用户身份验证。其中一种常见的方式是通过发送验证码到用户的邮箱&#xff0c;然后要求用户输入该验证码进行验证。本文将介绍如何使用 C# 发送邮箱验证码。 声明 验证码登录没有用任何的工具&#…

学习尚硅谷Vue的TodoList案例下半部分总结

今天学习尚硅谷Vue的TodoList案例四到八节的内容&#xff0c;主要实现的功能有勾选、删除、底部统计、底部交互这几部分。先说勾选&#xff0c;想要获取到用户是否勾选&#xff0c;就要给checkbox多选框注册鼠标点击事件&#xff0c;这里的思路是用户虽然是获取到了是否勾选但还…

项目框架构建之3:Nuget服务器的搭建

本文是“项目框架构建”系列之3&#xff0c;本文介绍一下Nuget服务器的搭建&#xff0c;这是一项简单的工作&#xff0c;您或许早已会了。 1.打开vs2022创建Asp.net Web应用程序 框架选择.net framework4.8&#xff0c;因为nuget服务器只支持.net framework。 2.选择空项目和保…

C++ 学习系列 -- tuple 原理

一 可变参数模板 variadic template 前面的章节 C 学习系列 -- 模板 template-CSDN博客 我们介绍了 c 中的模板概念&#xff0c;本章则在其基础上介绍了新的概念 可变参数模板 variadic template &#xff0c;顾名思义&#xff0c;可变参数模板意思为模板参数的类型与数量是变…

微信小程序封装vant 下拉框select 单选组件

先上效果图&#xff1a; 主要是用vant 小程序组件封装的&#xff1a;vant 小程序ui网址&#xff1a;vant-weapp 主要代码如下: 先封装子组件&#xff1a; select-popup 放在 components 文件夹里面 select-popup.wxml: <!--pages/select-popup/select-popup.wxml--> &…

爆肝整理,企业级性能测试-性能方案设计详细总结(二)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、测试策略 1&a…

【小沐学C++】C++ 实现鼠标键盘钩子HOOK

文章目录 1、简介2、相关函数2.1 SetWindowsHookEx2.2 UnhookWindowsHookEx2.3 CallNextHookEx 3、相关结构体3.1 KBDLLHOOKSTRUCT3.2 MSLLHOOKSTRUCT 4、挂钩过程5、代码测试5.1 代码1 结语 1、简介 https://learn.microsoft.com/zh-cn/windows/win32/winmsg/about-hooks 挂…

Java学习笔记(十)——异常

一、异常的概念 二、异常体系图&#xff08;重要&#xff09; 三、常见的异常 &#xff08;一&#xff09;常见的运行时异常 1、NullPointerException空指针异常 2、ArithmeticException数学运算异常 3、ArrayIndexOutOfBoundsException数组下标越界异常 4、ClassCastEx…

CSS 压重按钮 效果

<template><view class="cont"><div class="container"><div class="pane"><!-- 选项1 --><label class="label" @click="handleOptionClick(0)":style="{ color: selectedOption ==…

约数个数和约数之和算法总结

知识概览 约数个数 由算数基本定理 可得对于N的任何一个约数d&#xff0c;有 因为N的每一个约数和~的一种选法是一一对应的&#xff0c;根据乘法原理可得&#xff0c; 一个数的约数个数为 约数之和 一个数的约数之和公式为 多项式乘积的每一项为 正好对应的是一个数的每一个约…

【网络安全】upload靶场pass11-17思路

目录 Pass-11 Pass-12 Pass-13 Pass-14 Pass-15 Pass-16 Pass-17 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filotimo__✍️原创&#xff0c;首发于CSDN&#x1f4da;。 &#x…

JetCache源码解析——配置加载和初始化

JetCache自动化配置加载 JetCache的配置加载主要是在jetcache-autoconfigure模块中完成的&#xff0c;其中加载配置的核心类是JetCacheAutoConfiguration&#xff0c;主要是用于创建全局性的一些Bean&#xff0c;例如全局缓存配置类GlobalCacheConfig&#xff0c;AutoConfigur…

数据密集型应用系统设计--第2章 数据模型与查询语言

一、引言 数据模型可能是开发软件最重要的部分,而且还对如何思考待解决的问题都有深远的影响。 大多数应用程序是通过一层一层叠加数据模型来构建的。每一层都面临的关键问题是&#xff1a;如何将其用下一层来表示&#xff1f; 1.作为一名应用程序开发人员&#xff0c;观测现实…

yarn无法加载文件和‘vue-cli-service‘ 不是内部或外部命令解决方法

导致此错误的原因是&#xff0c;PowerShell 执行策略&#xff0c;默认设置为Restricted不加载配置文件或运行脚本。需变更设置为RemoteSigned&#xff0c;变更过程为&#xff1a; 1.运行 Windows PowerShell&#xff08;管理员&#xff09;&#xff0c;执行命令set-ExecutionPo…

使用redis时快速考虑的问题

使用场景 ap组件程序是否容忍极限丢失1s数据是否可以不依赖redis就能实现是否过度依赖redis 数据结构 5种结构选择不同结构有自己的限制&#xff0c;使用前需考虑限制考虑当前业务最适合那种解构&#xff0c;或多种解构混合使用 key设计 大keykey的格式热key敏感数据 过…

Redis的IO多路复用原理解析

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术&#x1f525;如果感觉博主的文章还不错的…