做网站怎么签订协议/策划方案模板

做网站怎么签订协议,策划方案模板,成都网站建设g冠辰,太原网站建设世纪优创作者:来自 vivo 互联网服务器团队- Wang Zhi 通过对 Redis 和 Caffeine 的缓存监控快速发现和定位问题降低故障的影响面。 一、缓存监控的背景 游戏业务中存在大量的高频请求尤其是对热门游戏而言,而应对高并发场景缓存是一个常见且有效的手段。 游戏业…

作者:来自 vivo 互联网服务器团队- Wang Zhi

通过对 Redis 和 Caffeine 的缓存监控快速发现和定位问题降低故障的影响面。

一、缓存监控的背景

  • 游戏业务中存在大量的高频请求尤其是对热门游戏而言,而应对高并发场景缓存是一个常见且有效的手段。

  • 游戏业务中大量的采用远程缓存(Redis)和本地缓存(Caffeine)组合方式来应对大流量的场景。

  • 在整个缓存使用的实践过程中,基于真实线上案例和日常缓存运维痛点沉淀了一些缓存监控治理的有效案例供分享。

二、远程缓存的监控介绍

2.1 监控的方案
2.1.1 监控目的

  • 从宏观来讲监控本质目的是为了及时发现定位并解决问题,在成本可控的前提下监控维度尽可能丰富。

  • 聚焦到 Redis 的维度,除了 Server 本身的监控指标(如请求量、连接数外),还需要监控更多偏业务的指标。

  • Redis 目前最常见的问题包括:热点 Key 问题,大 Key 问题,超负载的大请求量问题。

  • 聚焦上述的问题,在基于 Redis 的原生监控指标基础上,补充更多的包含业务属性的监控。

2.1.2 监控方案

  • 目前从监控的维度进行分析,希望能做到既能针对某个 key 的热点监控,又能针对某一类相同前缀的 key 做聚合趋势监控。前者目的是发现热点 key,后者目的是从趋势维度监控缓存的实际访问量。

  • Redis 的具体 key的监控由 Redis 自研团队集成到 redis server 侧实现监控,分类上归属为 Redis Server 侧的监控,这部分不在本篇分享中具体展开。

  • Redis 的某类相同前缀的 key 的聚合监控由业务侧通过Aspect 拦截器拦截并上报埋点实现,其中 key 的设计需要遵循便于聚合的原则,分类上归属为 Redis 的业务侧的监控。

2.1.3 监控大盘

【Redis Server系统监控指标】

说明:

  • 上图监控 Redis Server 的原生指标,具体可以参考 Redis 官方文档

    http://doc.redisfans.com/server/info.html。

  • 上述指标用来评估 Redis Server 本身的负载情况,并基于此考虑是否需要横向和纵向扩容。

【Redis 业务维度前缀监控指标】

说明:

  • 上图监控的业务维度按照某类 key 的前缀进行聚合的指标,评估各类的 Redis 的 key 的读写指标。

  • 上述指标用来评估业务对 Redis 缓存使用的合理性,如发现某个前缀 key 的写入量太大(缓存应该是读多写少场景)就需要思考缓存设计的合理性。

2.2 监控的实现

  • 业务维度按照某类 key 的前缀进行聚合的功能,关键的实现逻辑包括:一类业务需要统一前缀 key 并在末尾拼接变量;通过切面拦截 redis 的读写并上报埋点。

  • 统一前缀 key 是指:如果业务A是按照用户维度进行缓存 Key 的设计,那么 Key 的形态应该是 Prefix:UserId,Prefix 是业务场景的前缀,UserId 是用户维度的动态值。

  • 切面拦截是指:针对指定的Redis操作(包括常见的 Set 等),进行拦截并匹配前缀进行埋点上报。

2.2.1 前缀 key 设计

Redis Key 的设计

public class RedisKeyConstants {public static final String    REDIS_GAMEGROUP_NEW_KEY              = "newgamegroup";public static final String    REDIS_GAMEGROUP_DETAIL_KEY          = "gamegroup:detail";public static final String    REDIS_KEY_IUNIT_STRATEGY_COUNT      = "activity:ihandler:strategy:count";public static final String    CONTENT_DISTRIBUTE_CURRENT          = "content:distribute:current";public static final String    RECOMMEND_NOTE                      = "recommend:note";
}public class RedisUtils {public static final String    COMMON_REDIS_KEY_SPLIT    = ":";public static String buildRedisKey(String key, Object... params) {if (params == null || params.length == 0) {return key;}for (Object param : params) {key += COMMON_REDIS_KEY_SPLIT + param;}return key;}
}

左右滑动查看完整代码

说明:

  • 在常量定义 RedisKeyConstants 中按照不同的业务区分了不同的业务场景的前缀 Key。

  • 在 RedisUtils#buildRedisKey 中将业务的前缀和动态变化的参数进行拼接,中间通过分隔符进行连接。

  • 分割符的引入是为了后续切面拦截时候进行逆向切割获取前缀使用。

2.2.2 监控实现

@Slf4j
@Aspect
@Order(0)
@Component
public class RedisMonitorAspect {private static final String PREFIX_CONFIG = "redis.monitor.prefix";private static final Set<String> PREFIX_SET = new HashSet<>();@Resourceprivate MonitorComponent monitorComponent;static {// 更新前缀匹配的名单String prefixValue = VivoConfigManager.getString(PREFIX_CONFIG, "");refreshConf(prefixValue);// 增加配置变更的回调VivoConfigManager.addListener(new VivoConfigListener() {@Overridepublic void eventReceived(PropertyItem propertyItem, ChangeEventType changeEventType) {if (StringUtils.equalsIgnoreCase(propertyItem.getName(), PREFIX_CONFIG)) {refreshConf(propertyItem.getValue());}}});}/*** 更新前缀匹配的名单* @param prefixValue*/private static void refreshConf(String prefixValue) {if (StringUtils.isNotEmpty(prefixValue)) {String[] prefixArr = StringUtils.split(prefixValue, ",");Arrays.stream(prefixArr).forEach(item -> PREFIX_SET.add(item));}}@Pointcut("execution(* com.vivo.joint.dal.common.redis.dao.RedisDao.set*(..))")public void point() {}@Around("point()")public Object around(ProceedingJoinPoint pjp) throws Throwable {//业务逻辑异常情况直接抛到业务层处理Object result = pjp.proceed();try {if (VivoConfigManager.getBoolean("joint.center.redis.monitor.switch", true)) {Object[] args = pjp.getArgs();if (null != args && args.length > 0) {String redisKey = String.valueOf(args[0]);if (VivoConfigManager.getBoolean("joint.center.redis.monitor.send.log.switch", true)) {LOGGER.info("更新redis的缓存 {}", redisKey);}String monitorKey = null;// 先指定前缀匹配if (!PREFIX_SET.isEmpty()) {for (String prefix : PREFIX_SET) {if (StringUtils.startsWithIgnoreCase(redisKey, prefix)) {monitorKey = prefix;break;}}}if (StringUtils.isEmpty(monitorKey) && StringUtils.contains(redisKey, ":")) {// 需要考虑前缀的格式,保证数据写入不能膨胀monitorKey = StringUtils.substringBeforeLast(redisKey, ":");}monitorComponent.sendRedisMonitorData(monitorKey);}}} catch (Exception e) {}return result;}
}
printf("hello world!");

说明:

  • 通过 Aspect 的切面功能对 Redis 的指定操作进行拦截,如上图中的 Set 操作等,可以按需扩展到其他操作(包括 get 命令等)。

  • 针对前缀 key 的提取支持两个维度,默认场景和自定义场景,其中处理优先级为 自定义场景 > 默认场景

  • 默认场景是指如 Redis 的 Key 为 A:B:C:UserId,从后往前寻找后向第一个分割符进行分割,A:B:C:UserId 分割后的根据前缀 A:B:C 进行聚合后数据埋点上报。

  • 自定义场景如 Redis的 Key 为 A:B:UserId,通过配置自定义的前缀 A:B 来匹配,A:B:C:UserId 根据自定义的前缀分割后根据前缀 A:B 进行聚合后数据埋点上报。

  • 考虑自定义场景的灵活性,相关的自定义前缀通过配置中心实时生效。

2.3 监控的案例

public static final String REDISKEY_USER_POPUP_PLAN = "popup:user:plan";public PopupWindowPlan findPlan(FindPlanParam param) {String openId = param.getOpenId();String imei = param.getImei();String gamePackage = param.getGamePackage();Integer planType = param.getPlanType();String appId = param.getAppId();// 1、获取缓存的数据PopupWindowPlan cachedPlan = getPlanFromCache(openId, imei, gamePackage, planType);if (cachedPlan != null) {monitorPopWinPlan(cachedPlan);return cachedPlan;}// 2、未命中换成后从持久化部分获取对应的 PopupWindowPlan 对象// 3、保存到Redis换成setPlanToCache(openId, imei, gamePackage, plan);return cachedPlan;}// 从缓存中获取数据的逻辑private PopupWindowPlan getPlanFromCache(String openId, String imei, String gamePackage, Integer planType) {String key = RedisUtils.buildRedisKey(RedisKeyConstants.REDISKEY_USER_POPUP_PLAN, openId, imei, gamePackage, planType);String cacheValue = redisDao.get(key);if (StringUtils.isEmpty(cacheValue)) {return null;}try {PopupWindowPlan plan = objectMapper.readValue(cacheValue, PopupWindowPlan.class);return plan;} catch (Exception e) {}return null;}// 保存数据到缓存当中private void setPlanToCache(String openId, String imei, String gamePackage, PopupWindowPlan plan, Integer planType) {String key = RedisUtils.buildRedisKey(RedisKeyConstants.REDISKEY_USER_POPUP_PLAN, openId, imei, gamePackage, planType);try {String serializedStr = objectMapper.writeValueAsString(plan);redisDao.set(key, serializedStr, VivoConfigManager.getInteger(ConfigConstants.POPUP_PLAN_CACHE_EXPIRE_TIME, 300));} catch (Exception e) {}}

左右滑动查看完整代码

说明:

  • 如监控实现部分所述,通过 Redis Key 的前缀聚合监控,能够发现某一类业务场景的 Redis 的写请求数,进而发现 Redis 的无效使用场景。

  • 上述案例是典型的Redis的缓存使用场景:1.访问 Redis 缓存;2.若命中则直接返回结果;3、如未命中则查询持久化存储获取数据并写入 Redis 缓存。

  • 从业务监控的大盘发现前缀 popup:user:plan 存在大量的 set 操作命令,按照缓存读多写少的原则,该场景标明该缓存的设计是无效的。

  • 通过业务分析后,发现在游戏的业务场景中 用户维度+游戏维度 不存在5分钟重复访问缓存的场景,确认缓存的无效。

  • 确认缓存无效后,删除相关的缓存逻辑,降低了 Redis Server 的负载后并进一步提升了接口的响应时间。

三、本地缓存的监控介绍

3.1 监控的方案

3.1.1 监控目的

  • 从宏观来讲监控本质目的是为了及时发现定位并解决问题,在成本可控的前提下监控维度尽可能丰富。

  • 聚焦到 Caffeine 的维度,监控指标包括缓存的请求次数、命中率,未命中率等指标。

  • Caffeine 目前最常见的问题是:缓存设置不合理导致缓存穿透引发的系统问题。

3.1.2 监控方案

  • 目前从监控的维度进行分析,按照机器维度+缓存实例进行监控指标采集,其中监控指标的采集基于 Caffeine 的 recordStats 功能开启。

  • 基于 caffeine 的原生能力定制的 vivo-caffeine 集成了单机器维度+单缓存实例的指标数据的采集和上报功能。

  • vivo-caffeine 上报的数据会按照单机器+单缓存实例维度进行大盘展示,支持全量指标的查询功能。

  • vivo-caffeine 的上报的数据和公司级的告警功能相结合,例如针对缓存未命中率进行监控就能很快发现缓存穿透的问题。

3.1.3 监控大盘

【Caffeine 系统监控指标】

说明:

  • vivo-caffeine 按照单机器 + 缓存实例维度进行监控数据的上报并进行展示。

  • 所有的系统指标都支持查询并以图片的形式进行展示。

3.2 监控的实现

public final class Caffeine<K, V> {/*** caffeine的实例名称*/String instanceName;/*** caffeine的实例维护的Map信息*/static Map<String, Cache> cacheInstanceMap = new ConcurrentHashMap<>();@NonNullpublic <K1 extends K, V1 extends V> Cache<K1, V1> build() {requireWeightWithWeigher();requireNonLoadingCache();@SuppressWarnings("unchecked")Caffeine<K1, V1> self = (Caffeine<K1, V1>) this;Cache localCache =  isBounded() ? new BoundedLocalCache.BoundedLocalManualCache<>(self) : new UnboundedLocalCache.UnboundedLocalManualCache<>(self);if (null != localCache && StringUtils.isNotEmpty(localCache.getInstanceName())) {cacheInstanceMap.put(localCache.getInstanceName(), localCache);}return localCache;}
}static Cache<String, List<String>> accountWhiteCache = Caffeine.newBuilder().applyName("accountWhiteCache").expireAfterWrite(VivoConfigManager.getInteger("trade.account.white.list.cache.ttl", 10), TimeUnit.MINUTES).recordStats().maximumSize(VivoConfigManager.getInteger("trade.account.white.list.cache.size", 100)).build();

左右滑动查看完整代码

说明:

  • Caffeine 的按缓存实例进行指标采集的前提是需要全局维护缓存实例和对应的 instanceName 之间的关联关系。

  • Caffeine 在缓存创建的时候会设置实例的名称,通过 applyName 方法设置实例名称。

public static StatsData getCacheStats(String instanceName) {Cache cache = Caffeine.getCacheByInstanceName(instanceName);CacheStats cacheStats = cache.stats();StatsData statsData = new StatsData();statsData.setInstanceName(instanceName);statsData.setTimeStamp(System.currentTimeMillis()/1000);statsData.setMemoryUsed(String.valueOf(cache.getMemoryUsed()));statsData.setEstimatedSize(String.valueOf(cache.estimatedSize()));statsData.setRequestCount(String.valueOf(cacheStats.requestCount()));statsData.setHitCount(String.valueOf(cacheStats.hitCount()));statsData.setHitRate(String.valueOf(cacheStats.hitRate()));statsData.setMissCount(String.valueOf(cacheStats.missCount()));statsData.setMissRate(String.valueOf(cacheStats.missRate()));statsData.setLoadCount(String.valueOf(cacheStats.loadCount()));statsData.setLoadSuccessCount(String.valueOf(cacheStats.loadSuccessCount()));statsData.setLoadFailureCount(String.valueOf(cacheStats.loadFailureCount()));statsData.setLoadFailureRate(String.valueOf(cacheStats.loadFailureRate()));Optional<Eviction> optionalEviction = cache.policy().eviction();optionalEviction.ifPresent(eviction -> statsData.setMaximumSize(String.valueOf(eviction.getMaximum())));Optional<Expiration> optionalExpiration = cache.policy().expireAfterWrite();optionalExpiration.ifPresent(expiration -> statsData.setExpireAfterWrite(String.valueOf(expiration.getExpiresAfter(TimeUnit.SECONDS))));optionalExpiration = cache.policy().expireAfterAccess();optionalExpiration.ifPresent(expiration -> statsData.setExpireAfterAccess(String.valueOf(expiration.getExpiresAfter(TimeUnit.SECONDS))));optionalExpiration = cache.policy().refreshAfterWrite();optionalExpiration.ifPresent(expiration -> statsData.setRefreshAfterWrite(String.valueOf(expiration.getExpiresAfter(TimeUnit.SECONDS))));return statsData;
}

左右滑动查看完整代码

说明:

  • 监控指标的采集基于 Caffeine 原生的统计功能 CacheStats。

  • 所有采集的指标封装成一个统计对象 StatsData 进行上报。

public static void sendReportData() {try {if (!VivoConfigManager.getBoolean("memory.caffeine.data.report.switch", true)) {return;}// 1、获取所有的cache实例对象Method listCacheInstanceMethod = HANDLER_MANAGER_CLASS.getMethod("listCacheInstance", null);List<String> instanceNames = (List)listCacheInstanceMethod.invoke(null, null);if (CollectionUtils.isEmpty(instanceNames)) {return;}String appName = System.getProperty("app.name");String localIp = getLocalIp();String localPort = String.valueOf(NetPortUtils.getWorkPort());ReportData reportData = new ReportData();InstanceData instanceData = new InstanceData();instanceData.setAppName(appName);instanceData.setIp(localIp);instanceData.setPort(localPort);// 2、遍历cache实例对象获取缓存监控数据Method getCacheStatsMethod = HANDLER_MANAGER_CLASS.getMethod("getCacheStats", String.class);Map<String, StatsData> statsDataMap = new HashMap<>();instanceNames.stream().forEach(instanceName -> {try {StatsData statsData = (StatsData)getCacheStatsMethod.invoke(null, instanceName);statsDataMap.put(instanceName, statsData);} catch (Exception e) {}});// 3、构建上报对象reportData.setInstanceData(instanceData);reportData.setStatsDataMap(statsDataMap);// 4、发送Http的POST请求HttpPost httpPost = new HttpPost(getReportDataUrl());httpPost.setConfig(requestConfig);StringEntity stringEntity = new StringEntity(JSON.toJSONString(reportData));stringEntity.setContentType("application/json");httpPost.setEntity(stringEntity);HttpResponse response = httpClient.execute(httpPost);String result = EntityUtils.toString(response.getEntity(),"UTF-8");EntityUtils.consume(response.getEntity());logger.info("Caffeine 数据上报成功 URL {} 参数 {} 结果 {}", getReportDataUrl(), JSON.toJSONString(reportData), result);} catch (Throwable throwable) {logger.error("Caffeine 数据上报失败 URL {} ", getReportDataUrl(), throwable);}
}

左右滑动查看完整代码

说明:

  • 每个应用单独的部署的服务作为一个采集点,进行指标的采集和上报。

  • 采集过程是获取当前部署的应用下的所有缓存实例并进行指标的采集封装。

  • 整体上报采用 Http 协议进行上报并最终展示到监控平台。

3.3 监控的案例

说明:

  • 某次线上问题发生时发现突然多出了大量的 Redis 的请求,但是无法具体定位请求的 Redis 的前缀 key,设想如果接入了 Redis 的业务监控,问题来源就能很快定位。

  • 在后续的问题排查中发现某个 Caffeine 的本地缓存因为大小设置过小导致大量的本地请求缓存穿透导致 Redis 的请求量突增,最终导致 Redis 的服务接近崩溃。

  • 针对本地缓存穿透的场景,如果采用 Caffeine 的本地缓存监控方案,能够从缓存的命中率指标和缓存的未命中率指标突增突降中发现问题根源。

四、结束语

  • 本篇内容是基于线上真实案例分享游戏业务侧在缓存监控治理方面的有效实践,监控治理本身是一个未雨绸缪的过程。在没有线上问题发生时看似不重要,但一旦发生无法快速定位问题又会导致问题的放大,因此完善的缓存监控整理其实是非常有必要的。

  • Redis 的前缀 key 的监控思路是游戏业务服务端在优化Redis 的使用效率的过程中发现的一个较好的实践,逐步延伸后发现这是一个很好的监控手段,能够通过突增的趋势快速定位问题。

  • 基于 Caffeine 的原生能力定制的监控指标采集是游戏业务服务端在探索 Caffeine 可视化过程中进行的一个探索落地,将整个缓存实例的运行态进行完整呈现,为业务稳定性贡献力量。

  • 相信业内同仁会有更多更好的实践,相互分享共同进步,共勉。

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

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

相关文章

WordPress漏洞

一&#xff0c;后台修改模板拿WebShell 1&#xff0c;安装好靶场后访问 2&#xff0c;在如图所示的位置选择一个php文件写入一句话木马&#xff0c;我们这里选择在404.php中写入 3&#xff0c;访问404.php 二&#xff0c;上传主题拿WebShell 1&#xff0c;找到如图所示的页面…

【Linux系列】实时监控磁盘空间:`watch -n 1 ‘df -h‘` 命令详解

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

腾讯云大模型知识引擎×DeepSeek:股票分析低代码应用实践

项目背景与发展历程 在金融科技快速发展的今天&#xff0c;股票分析作为投资决策的核心环节&#xff0c;正面临数据量激增和复杂性提升的挑战。传统股票分析依赖人工处理&#xff0c;效率低下且成本高昂&#xff0c;而人工智能&#xff08;AI&#xff09;的引入为这一领域带来…

高性能边缘计算网关-高算力web组态PLC网关

高性能EG8200Pro边缘计算算力网关-超强处理能力 样机申请测试&#xff1a;免费测试超30天&#xff08;https://www.iotrouter.com/prototype/&#xff09; 产品主要特点和特色功能 设备概览与连接能力 设备型号&#xff1a;EG8200P。主要特点&#xff1a; 支持多种工业协议&am…

Web开发-JS应用原生代码前端数据加密CryptoJS库jsencrypt库代码混淆

知识点&#xff1a; 1、安全开发-原生JS-数据加密&代码混淆 2、安全开发-原生JS-数据解密安全案例 一、演示案例-WEB开发-原生JS&第三方库-数据加密 前端技术JS实现&#xff1a; 1、非加密数据大致流程&#xff1a; 客户端发送->明文数据传输-服务端接受数据->…

【Dive Into Stable Diffusion v3.5】1:开源项目正式发布——深入探索SDv3.5模型全参/LoRA/RLHF训练

目录 1 引言2 项目简介3 快速上手3.1 下载代码3.2 环境配置3.3 项目结构3.4 下载模型与数据集3.5 运行指令3.6 核心参数说明3.6.1 通用参数3.6.2 优化器/学习率3.6.3 数据相关 4 结语 1 引言 在人工智能和机器学习领域&#xff0c;生成模型的应用越来越广泛。Stable Diffusion…

Docker Compose部署MantisBT

文章目录 1.docker-compose-mantisbt.yml2.部署3.配置MantisBT4.登录5.修改配置5.1 取消修改用户需要邮箱确认 1.docker-compose-mantisbt.yml version: "3" services:web:image: okainov/mantisbt:latestcontainer_name: mantisbt_webports:- "8989:80"e…

Grokking System Design 系统设计面试问题

《Grokking the System Design Interview》列举了多个经典的系统设计题目,通常按照 不同的业务场景和技术难点 进行分类。以下是一些常见的分类和题目示例: 1. 社交网络类 设计 Twitter(支持关注/取关、推文、Feed 流) 设计 Facebook Messenger(即时聊天,支持在线/离线状…

## DeepSeek写射击手机小游戏

DeepSeek写射击手机小游戏 提问 根据提的要求&#xff0c;让DeepSeek整理的需求&#xff0c;进行提问&#xff0c;内容如下&#xff1a; 请生成一个包含以下功能的可运行移动端射击小游戏H5文件&#xff1a; 要求 可以重新开始游戏 可以暂停游戏 射击位置在底部中间&#xff…

【智能体】| 知识库、RAG概念区分以及智能体是什么

文章目录 前言简介大模型“幻觉”问题如何解决“幻觉”问题&#xff1f; RAG、智能体、RAG智能体概念什么是检索增强型生成&#xff08;RAG&#xff09;模拟简单的RAG场景 AI系统中的智能体是什么什么是Agentic RAG&#xff1f;Agentic RAG如何工作&#xff1f;Agentic RAG架构…

Linux与HTTP中的Cookie和Session

HTTP中的Cookie和Session 本篇介绍 前面几篇已经基本介绍了HTTP协议的大部分内容&#xff0c;但是前面提到了一点「HTTP是无连接、无状态的协议」&#xff0c;那么到底有什么无连接以及什么是无状态。基于这两个问题&#xff0c;随后解释什么是Cookie和Session&#xff0c;以…

【深度】JADC2的层级结构以及全域Mesh网络

文章目录 内容摘要1. 引言2. JADC2层级结构3. JADC2转变为CJADC24. 与工业领域自动化金字塔和全域MESH网络的异同4.1 工业领域自动化金字塔4.2 全域Mesh网络 #JADC2 #Mesh网络 #融合计划 #ABMS #超越计划 #人工智能 #普罗米修斯 **专栏说明&#xff1a;主要研究作战概念、新型作…

210、【图论】课程表(Python)

题目 思路 这道题本质上是一个拓扑排序。每次先统计每个点的入度个数、然后再统计点与点之间的邻接关系&#xff0c;找到入度为0的点作为起始遍历点。之后每遍历到这个点之后&#xff0c;就把这个点后续的邻接关系边的点入度减去一。当某个点入度为0时&#xff0c;继续被加入其…

Mock接口编写教程-axios-mock-adapter(React)

Mock模拟接口编写教程 直接在前端实现接口模拟 1.第一步 设置模拟接口 // mock.ts import axios from axios import MockAdapter from axios-mock-adapter// 创建一个模拟适配器 const mock new MockAdapter(axios)// 设置模拟接口 export const setupMock () > {mock.…

CCF 编程能力认证 C++ 四级宝典

CCF编程能力等级认证&#xff08;以下简称GESP&#xff09;2025年四次认证时间分别为&#xff1a;3月22日、6月28日、9月27日、12月20日&#xff0c;认证方式为线下机考&#xff0c;认证语言包括&#xff1a;C、Python和Scratch三种语言&#xff0c;其中Scratch认证为一到四级&…

OpenCV图像拼接(4)图像拼接模块的一个匹配器类cv::detail::BestOf2NearestRangeMatcher

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::detail::BestOf2NearestRangeMatcher 是 OpenCV 库中用于图像拼接模块的一个匹配器类&#xff0c;专门用于寻找两幅图像之间的最佳特征点匹配…

【C#语言】C#中的同步与异步编程:原理、示例与最佳实践

文章目录 ⭐前言⭐一、同步编程&#xff1a;简单但低效的线性执行&#x1f31f;代码示例&#x1f31f;执行流程示意图&#x1f31f;同步编程特点 ⭐二、异步编程&#xff1a;非阻塞的高效执行&#x1f31f;代码示例&#x1f31f;执行流程示意图&#x1f31f;异步编程核心机制&a…

el-input 不可编辑,但是点击的时候出现弹窗/或其他操作面板,并且带可清除按钮

1.focus“getFocus”鼠标聚焦的时候写个方法&#xff0c;弹窗起来 getFocus(){ this.定义的弹窗状态字段 true;} 2.点击确定的时候&#xff0c;数值赋值到el-input的输入框,弹窗取消&#xff08;this.定义的弹段字端 false&#xff09; 3.但是会有个问题就是el-input 不可点…

事件响应计划:网络弹性的关键

网络安全事件响应计划不仅仅是技术上的需要&#xff0c;更是企业的当务之急。在网络威胁比以往任何时候都更加复杂和频繁的时代&#xff0c;了解并做好准备应对这些事件可能会决定是恢复还是灾难。 以下是简要分析&#xff1a; 网络安全事件不仅仅是技术故障&#xff1b;它们…

正则表达式详解(regular expression)

&#x1f4a1; 正则表达式&#xff08;Regular Expression, regex&#xff09;知识点总结 &#x1f4a1; 正则表达式是一种用于匹配字符串的模式&#xff0c;广泛用于搜索、替换、验证等操作。 &#x1f4cc; 正则表达式的主要作用 1️⃣ 字符串匹配 &#x1f9d0; 检查一个…