40分钟学 Go 语言高并发:服务注册与发现

服务注册与发现

一、系统架构设计

让我们先通过流程图了解服务注册与发现的整体架构:
在这里插入图片描述

二、核心组件实现

1. 服务注册中心

package discoveryimport ("context""sync""time"
)// ServiceInstance 服务实例
type ServiceInstance struct {ID          string            `json:"id"`Name        string            `json:"name"`Version     string            `json:"version"`Endpoints   []string          `json:"endpoints"`Metadata    map[string]string `json:"metadata"`Status      string            `json:"status"`LastHeartbeat time.Time       `json:"last_heartbeat"`
}// Registry 注册中心
type Registry struct {services  map[string]map[string]*ServiceInstance // serviceName -> instanceID -> instancemutex     sync.RWMutexwatchers  map[string][]chan *ServiceInstance
}// NewRegistry 创建注册中心
func NewRegistry() *Registry {r := &Registry{services: make(map[string]map[string]*ServiceInstance),watchers: make(map[string][]chan *ServiceInstance),}go r.checkHealth()return r
}// Register 注册服务实例
func (r *Registry) Register(ctx context.Context, instance *ServiceInstance) error {r.mutex.Lock()defer r.mutex.Unlock()if _, exists := r.services[instance.Name]; !exists {r.services[instance.Name] = make(map[string]*ServiceInstance)}instance.LastHeartbeat = time.Now()instance.Status = "UP"r.services[instance.Name][instance.ID] = instance// 通知观察者r.notifyWatchers(instance.Name, instance)return nil
}// Deregister 注销服务实例
func (r *Registry) Deregister(ctx context.Context, serviceName, instanceID string) error {r.mutex.Lock()defer r.mutex.Unlock()if instances, exists := r.services[serviceName]; exists {if instance, ok := instances[instanceID]; ok {instance.Status = "DOWN"delete(instances, instanceID)// 如果服务没有实例了,删除服务if len(instances) == 0 {delete(r.services, serviceName)}return nil}}return nil
}// GetService 获取服务实例列表
func (r *Registry) GetService(ctx context.Context, serviceName string) ([]*ServiceInstance, error) {r.mutex.RLock()defer r.mutex.RUnlock()if instances, exists := r.services[serviceName]; exists {result := make([]*ServiceInstance, 0, len(instances))for _, instance := range instances {if instance.Status == "UP" {result = append(result, instance)}}return result, nil}return nil, nil
}// Watch 监听服务变化
func (r *Registry) Watch(ctx context.Context, serviceName string) (<-chan *ServiceInstance, error) {r.mutex.Lock()defer r.mutex.Unlock()ch := make(chan *ServiceInstance, 10)if _, exists := r.watchers[serviceName]; !exists {r.watchers[serviceName] = make([]chan *ServiceInstance, 0)}r.watchers[serviceName] = append(r.watchers[serviceName], ch)return ch, nil
}// Heartbeat 服务心跳
func (r *Registry) Heartbeat(ctx context.Context, serviceName, instanceID string) error {r.mutex.Lock()defer r.mutex.Unlock()if instances, exists := r.services[serviceName]; exists {if instance, ok := instances[instanceID]; ok {instance.LastHeartbeat = time.Now()instance.Status = "UP"return nil}}return nil
}// checkHealth 健康检查
func (r *Registry) checkHealth() {ticker := time.NewTicker(10 * time.Second)for range ticker.C {r.mutex.Lock()now := time.Now()for serviceName, instances := range r.services {for id, instance := range instances {if now.Sub(instance.LastHeartbeat) > 30*time.Second {instance.Status = "DOWN"delete(instances, id)if len(instances) == 0 {delete(r.services, serviceName)}}}}r.mutex.Unlock()}
}// notifyWatchers 通知观察者
func (r *Registry) notifyWatchers(serviceName string, instance *ServiceInstance) {if watchers, exists := r.watchers[serviceName]; exists {for _, ch := range watchers {select {case ch <- instance:default:// 如果channel已满,跳过}}}
}

2. 服务发现实现

package discoveryimport ("context""errors""sync""time"
)// ServiceDiscovery 服务发现
type ServiceDiscovery struct {registry       *RegistrylocalCache     map[string][]*ServiceInstancecacheMutex     sync.RWMutexupdateInterval time.Duration
}// NewServiceDiscovery 创建服务发现实例
func NewServiceDiscovery(registry *Registry, updateInterval time.Duration) *ServiceDiscovery {sd := &ServiceDiscovery{registry:       registry,localCache:     make(map[string][]*ServiceInstance),updateInterval: updateInterval,}go sd.startCacheUpdate()return sd
}// GetService 获取服务实例
func (sd *ServiceDiscovery) GetService(ctx context.Context, serviceName string) ([]*ServiceInstance, error) {// 首先检查本地缓存sd.cacheMutex.RLock()if instances, exists := sd.localCache[serviceName]; exists && len(instances) > 0 {sd.cacheMutex.RUnlock()return instances, nil}sd.cacheMutex.RUnlock()// 如果本地缓存没有,从注册中心获取instances, err := sd.registry.GetService(ctx, serviceName)if err != nil {return nil, err}// 更新本地缓存if len(instances) > 0 {sd.cacheMutex.Lock()sd.localCache[serviceName] = instancessd.cacheMutex.Unlock()}return instances, nil
}// startCacheUpdate 开始缓存更新
func (sd *ServiceDiscovery) startCacheUpdate() {ticker := time.NewTicker(sd.updateInterval)for range ticker.C {sd.updateCache()}
}// updateCache 更新缓存
func (sd *ServiceDiscovery) updateCache() {sd.cacheMutex.Lock()defer sd.cacheMutex.Unlock()ctx := context.Background()for serviceName := range sd.localCache {instances, err := sd.registry.GetService(ctx, serviceName)if err == nil && len(instances) > 0 {sd.localCache[serviceName] = instances}}
}// WatchService 监听服务变化
func (sd *ServiceDiscovery) WatchService(ctx context.Context, serviceName string) error {instanceCh, err := sd.registry.Watch(ctx, serviceName)if err != nil {return err}go func() {for {select {case instance := <-instanceCh:sd.handleInstanceUpdate(serviceName, instance)case <-ctx.Done():return}}}()return nil
}// handleInstanceUpdate 处理实例更新
func (sd *ServiceDiscovery) handleInstanceUpdate(serviceName string, instance *ServiceInstance) {sd.cacheMutex.Lock()defer sd.cacheMutex.Unlock()instances := sd.localCache[serviceName]updated := false// 更新或添加实例for i, inst := range instances {if inst.ID == instance.ID {instances[i] = instanceupdated = truebreak}}if !updated {instances = append(instances, instance)}// 过滤掉已下线的实例activeInstances := make([]*ServiceInstance, 0)for _, inst := range instances {if inst.Status == "UP" {activeInstances = append(activeInstances, inst)}}sd.localCache[serviceName] = activeInstances
}

3. 负载均衡实现

package discoveryimport ("context""errors""math/rand""sync""sync/atomic"
)// LoadBalancer 负载均衡接口
type LoadBalancer interface {Select(ctx context.Context, instances []*ServiceInstance) (*ServiceInstance, error)
}// RoundRobinLoadBalancer 轮询负载均衡器
type RoundRobinLoadBalancer struct {counter uint64
}// NewRoundRobinLoadBalancer 创建轮询负载均衡器
func NewRoundRobinLoadBalancer() *RoundRobinLoadBalancer {return &RoundRobinLoadBalancer{}
}// Select 选择服务实例
func (lb *RoundRobinLoadBalancer) Select(ctx context.Context, instances []*ServiceInstance) (*ServiceInstance, error) {if len(instances) == 0 {return nil, errors.New("no available instances")}count := atomic.AddUint64(&lb.counter, 1)return instances[int(count)%len(instances)], nil
}// RandomLoadBalancer 随机负载均衡器
type RandomLoadBalancer struct {}// NewRandomLoadBalancer 创建随机负载均衡器
func NewRandomLoadBalancer() *RandomLoadBalancer {return &RandomLoadBalancer{}
}// Select 选择服务实例
func (lb *RandomLoadBalancer) Select(ctx context.Context, instances []*ServiceInstance) (*ServiceInstance, error) {if len(instances) == 0 {return nil, errors.New("no available instances")}return instances[rand.Intn(len(instances))], nil
}// WeightedRoundRobinLoadBalancer 加权轮询负载均衡器
type WeightedRoundRobinLoadBalancer struct {mutex    sync.Mutexweights  map[string]intcurrent  map[string]int
}// NewWeightedRoundRobinLoadBalancer 创建加权轮询负载均衡器
func NewWeightedRoundRobinLoadBalancer() *WeightedRoundRobinLoadBalancer {return &WeightedRoundRobinLoadBalancer{weights: make(map[string]int),current: make(map[string]int),}
}// UpdateWeight 更新权重
func (lb *WeightedRoundRobinLoadBalancer) UpdateWeight(instanceID string, weight int) {lb.mutex.Lock()defer lb.mutex.Unlock()lb.weights[instanceID] = weight
}// Select 选择服务实例
func (lb *WeightedRoundRobinLoadBalancer) Select(ctx context.Context, instances []*ServiceInstance) (*ServiceInstance, error) {if len(instances) == 0 {return nil, errors.New("no available instances")}lb.mutex.Lock()defer lb.mutex.Unlock()var total intfor _, instance := range instances {weight := lb.weights[instance.ID]if weight <= 0 {weight = 1}lb.current[instance.ID] += weighttotal += lb.current[instance.ID]}max := 0var selected *ServiceInstancefor _, instance := range instances {current := lb.current[instance.ID]if current > max {max = currentselected = instance}}// 更新current值if selected != nil {weight := lb.weights[selected.ID]if weight <= 0 {weight = 1}lb.current[selected.ID] -= totalreturn selected, nil}return nil, errors.New("failed to select instance")
}// ConsistentHashLoadBalancer 一致性哈希负载均衡器
type ConsistentHashLoadBalancer struct {hashRing *ConsistentHashmutex    sync.RWMutex
}// NewConsistentHashLoadBalancer 创建一致性哈希负载均衡器
func NewConsistentHashLoadBalancer(replicas int) *ConsistentHashLoadBalancer {return &ConsistentHashLoadBalancer{hashRing: NewConsistentHash(replicas),}
}// Select 选择服务实例
func (lb *ConsistentHashLoadBalancer) Select(ctx context.Context, instances []*ServiceInstance, key string) (*ServiceInstance, error) {if len(instances) == 0 {return nil, errors.New("no available instances")}lb.mutex.Lock()// 更新哈希环lb.hashRing.Clear()for _, instance := range instances {lb.hashRing.Add(instance.ID)}lb.mutex.Unlock()// 根据key选择节点targetID := lb.hashRing.Get(key)for _, instance := range instances {if instance.ID == targetID {return instance, nil}}return nil, errors.New("failed to select instance")
}// LoadBalancerClient 负载均衡客户端
type LoadBalancerClient struct {discovery *ServiceDiscoverybalancer  LoadBalancer
}// NewLoadBalancerClient 创建负载均衡客户端
func NewLoadBalancerClient(discovery *ServiceDiscovery, balancer LoadBalancer) *LoadBalancerClient {return &LoadBalancerClient{discovery: discovery,balancer:  balancer,}
}// Call 调用服务
func (c *LoadBalancerClient) Call(ctx context.Context, serviceName string) (*ServiceInstance, error) {// 获取服务实例列表instances, err := c.discovery.GetService(ctx, serviceName)if err != nil {return nil, err}// 选择实例return c.balancer.Select(ctx, instances)
}

三、健康检查实现

package discoveryimport ("context""fmt""net/http""sync""time"
)// HealthChecker 健康检查器
type HealthChecker struct {registry        *RegistrycheckInterval  time.Durationtimeout        time.Durationendpoints      map[string]string // instanceID -> health check endpointmutex          sync.RWMutex
}// NewHealthChecker 创建健康检查器
func NewHealthChecker(registry *Registry, checkInterval, timeout time.Duration) *HealthChecker {checker := &HealthChecker{registry:      registry,checkInterval: checkInterval,timeout:      timeout,endpoints:    make(map[string]string),}go checker.start()return checker
}// RegisterEndpoint 注册健康检查端点
func (hc *HealthChecker) RegisterEndpoint(instanceID, endpoint string) {hc.mutex.Lock()defer hc.mutex.Unlock()hc.endpoints[instanceID] = endpoint
}// UnregisterEndpoint 注销健康检查端点
func (hc *HealthChecker) UnregisterEndpoint(instanceID string) {hc.mutex.Lock()defer hc.mutex.Unlock()delete(hc.endpoints, instanceID)
}// start 启动健康检查
func (hc *HealthChecker) start() {ticker := time.NewTicker(hc.checkInterval)defer ticker.Stop()for range ticker.C {hc.checkAll()}
}// checkAll 检查所有实例
func (hc *HealthChecker) checkAll() {hc.mutex.RLock()endpoints := make(map[string]string)for id, endpoint := range hc.endpoints {endpoints[id] = endpoint}hc.mutex.RUnlock()var wg sync.WaitGroupfor instanceID, endpoint := range endpoints {wg.Add(1)go func(id, ep string) {defer wg.Done()hc.checkInstance(id, ep)}(instanceID, endpoint)}wg.Wait()
}// checkInstance 检查单个实例
func (hc *HealthChecker) checkInstance(instanceID, endpoint string) {ctx, cancel := context.WithTimeout(context.Background(), hc.timeout)defer cancel()status := hc.doHealthCheck(ctx, endpoint)// 更新实例状态if status {hc.registry.Heartbeat(ctx, "", instanceID) // 服务名为空,因为我们只需要instanceID}
}// doHealthCheck 执行健康检查
func (hc *HealthChecker) doHealthCheck(ctx context.Context, endpoint string) bool {req, err := http.NewRequestWithContext(ctx, "GET", endpoint, nil)if err != nil {return false}client := &http.Client{Timeout: hc.timeout,}resp, err := client.Do(req)if err != nil {return false}defer resp.Body.Close()return resp.StatusCode == http.StatusOK
}// CustomHealthCheck 自定义健康检查接口
type CustomHealthCheck interface {Check(ctx context.Context) (bool, error)
}// CustomHealthChecker 自定义健康检查器
type CustomHealthChecker struct {checker CustomHealthCheckmutex   sync.RWMutex
}// NewCustomHealthChecker 创建自定义健康检查器
func NewCustomHealthChecker(checker CustomHealthCheck) *CustomHealthChecker {return &CustomHealthChecker{checker: checker,}
}// Check 执行健康检查
func (chc *CustomHealthChecker) Check(ctx context.Context) (bool, error) {chc.mutex.RLock()defer chc.mutex.RUnlock()return chc.checker.Check(ctx)
}// HealthCheckServer 健康检查服务器
type HealthCheckServer struct {port    inthandler http.Handlerserver  *http.Server
}// NewHealthCheckServer 创建健康检查服务器
func NewHealthCheckServer(port int, handler http.Handler) *HealthCheckServer {return &HealthCheckServer{port:    port,handler: handler,}
}// Start 启动服务器
func (s *HealthCheckServer) Start() error {s.server = &http.Server{Addr:    fmt.Sprintf(":%d", s.port),Handler: s.handler,}return s.server.ListenAndServe()
}// Stop 停止服务器
func (s *HealthCheckServer) Stop(ctx context.Context) error {return s.server.Shutdown(ctx)
}

四、系统配置和策略

1. 服务注册配置

配置项说明默认值推荐值
心跳间隔服务实例向注册中心发送心跳的间隔10s5-15s
注册超时服务注册的超时时间5s3-10s
实例缓存本地缓存服务实例信息的时间60s30-120s
重试次数注册失败时的重试次数33-5

2. 负载均衡策略对比

策略优点缺点适用场景
轮询实现简单,请求分布均匀不考虑服务器能力差异服务器性能相近
随机实现简单,负载较均衡可能造成不均衡大规模集群
加权轮询考虑服务器能力差异权重设置需要经验服务器性能差异大
一致性哈希请求分布稳定实现复杂需要会话保持

五、服务注册流程图

在这里插入图片描述

六、最佳实践建议

1. 服务注册

  1. 合理设置心跳间隔
  2. 实现优雅关闭
  3. 添加重试机制
  4. 使用服务分组

2. 服务发现

  1. 使用本地缓存
  2. 实现故障转移
  3. 监控服务健康
  4. 定期清理无效实例

3. 负载均衡

  1. 选择合适的策略
  2. 动态调整权重
  3. 实现熔断机制
  4. 监控服务质量

七、常见问题处理

1. 注册中心故障

  • 问题描述:注册中心不可用
  • 解决方案:
    1. 使用注册中心集群
    2. 本地缓存备份
    3. 定期同步数据
    4. 自动故障转移

2. 服务实例异常

  • 问题描述:服务实例不稳定
  • 解决方案:
    1. 实现健康检查
    2. 自动下线机制
    3. 故障恢复策略
    4. 监控告警系统

3. 网络分区

  • 问题描述:网络故障导致分区
  • 解决方案:
    1. 多数据中心部署
    2. 网络状态监控
    3. 自动切换机制
    4. 数据一致性保证

八、监控指标

1. 关键指标

  1. 服务注册延迟
  2. 服务发现延迟
  3. 心跳成功率
  4. 服务可用性
  5. 负载均衡效果
  6. 健康检查成功率

2. 告警阈值

  1. 服务注册延迟 > 3s
  2. 服务发现延迟 > 1s
  3. 心跳成功率 < 95%
  4. 服务可用性 < 99.9%
  5. 负载不均衡度 > 20%
  6. 健康检查失败率 > 5%

九、扩展建议

  1. 开发阶段:

    • 完善的单元测试
    • 模拟各种故障场景
    • 性能压力测试
    • 可观测性设计
  2. 运维阶段:

    • 监控系统部署
    • 告警规则配置
    • 故障演练
    • 容量规划
  3. 优化方向:

    • 性能优化
    • 可靠性提升
    • 可扩展性增强
    • 运维自动化

怎么样今天的内容还满意吗?再次感谢观众老爷的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

〔 MySQL 〕索引

目录 1. 没有索引&#xff0c;可能会有什么问题 2. 认识磁盘 MySQL与存储 先来研究一下磁盘&#xff1a; 在看看磁盘中一个盘片​编辑 扇区 定位扇区​编辑 结论 磁盘随机访问(Random Access)与连续访问(Sequential Access) 3. MySQL 与磁盘交互基本单位 4. 建立共识…

微信小程序里的小游戏研发需要什么技术栈

研发小程序里的小游戏通常需要以下技术栈&#xff1a; 前端技术 HTML5 / CSS3&#xff1a;用于构建游戏的界面布局和样式。JavaScript&#xff1a;作为核心编程语言&#xff0c;实现游戏的逻辑和交互。小程序开发框架&#xff1a;如微信小程序的开发框架&#xff0c;了解其 API…

php 生产者-消费者实现

一、项目背景 mes报工需求&#xff0c;原项目接口接收产线上位抛来的数据&#xff0c;处理无误后存储在本地&#xff0c;最后抛给工厂接口。 但是有时候工厂数据响应太慢&#xff0c;也导致mes响应给上位变慢&#xff0c;拖慢了mes系统。 现要求&#xff0c;将原接口中抛给工厂…

SpringBoot 解决跨域问题

SpringBoot 解决跨域问题 遇到前端跨域访问问题&#xff0c;类似于这样的&#xff1a; 在Springboot项目里加上这个配置文件CorsConfig.java&#xff0c;重启之后即可实现跨域访问&#xff0c;前端无需再配置跨域。 1、添加跨域工具包CorsConfig 2、写跨域代码 import org.sp…

IO基础(缓冲流)

FileInputStream、FileOutputStream、FileReader、FileWriter属于基础流。 缓冲流是高级流。能够高效的处理数据。原理&#xff1a;底层自带了长度为8192的缓冲区提高性能 字节缓冲流&#xff1a;BufferedInputStream、BufferedOutputStream 字符缓冲流&#xff1a;Buffered…

云数据库 Memcache

Memcached 是一个高性能的分布式内存缓存系统&#xff0c;主要用于加速动态网页应用的访问速度&#xff0c;通过减少数据库查询次数来提高系统性能。Memcached 将常用的数据存储在内存中&#xff0c;因此提供了非常快速的读取和写入操作&#xff0c;通常用于缓存热点数据&#…

高转化的Facebook广告文案的秘诀

Facebook 广告文案是制作有效 Facebook 广告的关键方面。它侧重于伴随广告视觉元素的文本内容。今天我们的博客将深入探讨成功的 Facebook 广告文案的秘密&#xff01; 一、广告文案怎么写&#xff1f; 正文&#xff1a;这是帖子的正文&#xff0c;出现在您姓名的正下方。它可…

算法基础学习Day2(双指针)

文章目录 1.题目2.题目解答1.快乐数题目及题目解析算法学习代码提交 2.题目2题目及题目解析算法学习代码提交 1.题目 202. 快乐数 - 力扣&#xff08;LeetCode&#xff09;11. 盛最多水的容器 - 力扣&#xff08;LeetCode&#xff09; 2.题目解答 1.快乐数 题目及题目解析 …

Web3与人工智能的跨界融合:数据隐私与去中心化的新机遇

随着Web3和人工智能&#xff08;AI&#xff09;技术的不断发展&#xff0c;两者的结合正在成为未来互联网的重要趋势。Web3代表着去中心化的未来&#xff0c;AI则提供了强大的智能化能力。当这两者结合时&#xff0c;不仅为数据隐私保护提供了新的解决方案&#xff0c;还推动了…

DevOps系统设计和技术选型

命名是一件痛苦的事情&#xff0c;除非你不想要一个好名字。 我正在做的这个管理系统叫什么合适&#xff0c;或者是什么类型的系统&#xff0c;想去想来不知所措&#xff0c;后来想想这么小的东西纠结什么&#xff0c;先从小的细节一点点来&#xff0c;能用就行&#xff0c;就用…

2024年华中杯数学建模A题太阳能路灯光伏板的朝向设计问题解题全过程文档及程序

2024年华中杯数学建模 A题 太阳能路灯光伏板的朝向设计问题 原题再现 太阳能路灯由太阳能电池板组件部分&#xff08;包括支架&#xff09;、LED灯头、控制箱&#xff08;包含控制器、蓄电池&#xff09;、市电辅助器和灯杆几部分构成。太阳能电池板通过支架固定在灯杆上端。…

sheng的学习笔记-AI-序列模型(Sequence Models),RNN,GRU,LSTM

Ai目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 基础知识 定义&#xff1a; 序列模型是输入输出均为序列数据的模型&#xff0c;它能够将输入序列数据转换为目标序列数据。常见的序列模型类型包括一对一、一对多、多对一、部分多对多和完全多对多。 重要的是需要有顺序…

《网络安全》相关知识点总结

第一章 安全现状及趋势 第二章 网络安全概述 2.1 信息保障阶段 信息保障技术框架IATF&#xff1a; 由美国国家安全局制定&#xff0c;提出“纵深防御策略” DiD&#xff08;Defense-in-Depth Strategy&#xff09; 在信息保障的概念下&#xff0c;信息安全保障的PDRR模型的内涵…

DApp浏览器能否集成在自己开发的DApp里?

答案是肯定的。在技术层面&#xff0c;DApp浏览器可以完全集成到你自己开发的DApp中&#xff0c;从而提供一个一体化的用户体验。本文将详细分析如何实现这一目标&#xff0c;以及其中的技术实现、优势和需要注意的问题。 一、什么是DApp浏览器&#xff1f; DApp浏览器是一种支…

MySQL--用户权限

1.使用root用户登录MySQL客户端&#xff0c;创建一个名为userl的用户&#xff0c;初始密码为123456;创建一个名为user2的用户&#xff0c;无初始密码。然后&#xff0c;分别使用uesr1、user2登录MySQL 客户端。 创建两个用户 使用user1登录 使用user2登录 2.使用root用户登录&a…

星海智算:skl-videolingo-2.0(AI视频翻译)使用教程

&#xff08;一&#xff09;项目介绍 VideoLingo是一款专为视频创作者设计的开源自动化工具&#xff0c;旨在提供从视频字幕生成到声音克隆配音的一站式服务。以下是对VideoLingo的详细介绍&#xff1a; 1、核心功能​ 1.1、一键全自动视频搬运​ 支持从YouTube等平台下载视…

SQL靶场第八关攻略

一.判断类型 输入?id1 and 11-- 输入?id1 and 12--页面都正常&#xff0c;说明不是数值型 输入?id1页面没有回显 加上--页面正常&#xff0c;说明是字符型注入 二.判断列数 输入?id1 order by 3--页面正常 输入?id1 order by 4--页面没有回显&#xff0c;说明一共有三列…

华为HCIP-Datacom H12-821H12-831 (12月最新题库)

备考HCIP-datacom的小伙伴注意啦 !!! 2024年下半年12月份最新(H12-821和H12-831)题库带解析,有需要的小伙伴移动至文章末 H12-821: H12-831: 1.BGP 邻居建立过程的状态存在以下几种&#xff1a;那么建立一个成功的连接所经历的状态机顺序是 A、3-1-2-5-4 B、1-3-5-2-4 C、…

Flask使用长连接

Flask使用flask_socketio实现websocket Python中的单例模式 在HTTP通信中&#xff0c;连接复用&#xff08;Connection Reuse&#xff09;是一个重要的概念&#xff0c;它允许客户端和服务器在同一个TCP连接上发送和接收多个HTTP请求/响应&#xff0c;而不是为每个新的请求/响…

MR30分布式 I/O 模块助力 CNC 设备产能飞跃

背景分析 在现代制造业中&#xff0c;CNC 设备扮演着极为关键的角色。然而&#xff0c;CNC 设备在运行过程中也存在着诸多痛点。传统的 CNC 设备往往在控制与通信方面存在局限&#xff0c;其内部的 I/O 系统大多采用集中式架构。这种架构下&#xff0c;一旦需要处理大量的输入输…