• [区域初赛赛题问题] “本次比赛要求所有程序必须为单线程、单进程运行”是否过于 一刀切
    初衷竟然只是为了防止开挂。。反正也是单核
  • [分享交流] 国内国际全球贵金融黄金白银行情查询API接口介绍
    全球贵金属行情查询,包括:实时价格、历史价格、K线走势、期货合约等,覆盖国内和国外贵金属交易数据。国内贵金属包括:黄金、白银、铜、国际铜、锌、铝、镍、锡、铅、不锈钢、螺纹钢。国际贵金属包括:伦敦金、伦敦银、伦敦铜、伦敦铝、伦敦锌、伦敦镍、伦敦铅、伦敦锡、现货铂金、现货钯金、美黄金、美白银、美铜。下面介绍贵金融行情的API参见此处国内贵金属报价请求参数名称类型必须说明symbolString是国内贵金属期货品种代码成功返回样例{ "code": 200,//返回码对应描述 "msg": "成功",//返回码,详见返回码说明 "taskNo": "138485498227260625726111",//本次请求号 "data": { "presettle": 614.51, "ask_vol": 3, //卖量(手数) "change": 3.71,//涨跌额 "bid_vol": 1, //买量(手数) "hold": 236472, //持仓量 "volume": 13396, //成交量 "update_time": 1731090599, "high": 619.7, //最高价 "low": 614.2, //最低价 "price": 618.22,//当前价格 "name": "黄金延期", //名称 "ask": 618.68, //卖价 "preclose": 612.87,//昨日收盘价 "bid": 616.02, //买价 "changeRate": 0.6,//涨跌率 "value": 8273493248,//成交额 "open": 614.3 //今日开盘价 } } 国内贵金属K线请求参数名称类型必须说明symbolString是国内贵金属品种typeString是k线类型0:日k1:1分钟5:五分钟30:30分钟60:60分钟120:120分钟240:240分钟limitString否返回条数 默认10成功返回样例{ "code": 200,//返回码对应描述 "msg": "成功",//返回码,详见返回码说明 "taskNo": "089625202232146663243632",//本次请求号 "data": { "lines": [ [ 621.5, 624.78, 625.7, 620.32, 3.28, 0.53, 34402, 1730044800 ] ], "fields": [ "open",//当前分钟开盘价 "close",//当前分钟收盘价 "high", //当前分钟最高价 "low", //当前分钟最低价 "change", //当前分钟涨跌额 "changeRate", //当前分钟涨跌率正常返回示例 "volume", //当前分钟成交数 "tick_at" //数据时间戳 ] } } 国内贵金属期货合约请求参数名称类型必须说明symbolString是国内贵金属期货品种代码成功返回样例{ "code": 200,//返回码对应描述 "msg": "成功",//返回码,详见返回码说明 "taskNo": "668229506174286233793097",//本次请求号 "data": { "list": [ { "symbol": "AU0", //代码 "name": "黄金2412" //名称 }, { "symbol": "AU2412",//代码 "name": "黄金2412" //名称 } ] } } 国际贵金属报价请求参数名称类型必须说明symbolString是国际贵金属品种成功返回样例{ "code": 200,//返回码对应描述 "msg": "成功",//返回码,详见返回码说明 "taskNo": "795463438161562841240471",//本次请求号 "data": { "presettle": 614.51, "ask_vol": 3, //卖量(手数) "change": 3.71,//涨跌额 "bid_vol": 1, //买量(手数) "hold": 236472, //持仓量 "volume": 13396, //成交量 "update_time": 1731090599, "high": 619.7, //最高价 "low": 614.2, //最低价 "price": 618.22,//当前价格 "name": "伦敦金(现货黄金)", //名称 "ask": 618.68, //卖价 "preclose": 612.87,//昨日收盘价 "bid": 616.02, //买价 "changeRate": 0.6,//涨跌率 "value": 8273493248,//成交额 "open": 614.3 //今日开盘价 } } 国际贵金属K线请求参数名称类型必须说明symbolString是国际贵金属品种typeString是k线类型0:日k1:1分钟5:五分钟30:30分钟60:60分钟120:120分钟240:240分钟limitString否返回条数 默认10成功返回样例{ "code": 200,//返回码对应描述 "msg": "成功",//返回码,详见返回码说明 "taskNo": "881490008152974143098955",//本次请求号 "charge": true,//计费标志 "data": { "lines": [ [ 2734.83, 2736, 2736.09, 2734.83, 1.17, 0.04, 55, 1732310100 ], [ 2736, 2736.63, 2736.63, 2736, 0.63, 0.02, 42, 1732310400 ] ], "fields": [ "open",//当前分钟开盘价 "close",//当前分钟收盘价 "high",//当前分钟最高价 "low", //当前分钟最低价 "change",//当前分钟涨跌额 "changeRate",//当前分钟涨跌率正常返回示例 "volume",//当前分钟成交数 "tick_at" //数据时间戳 ] } } 国际贵金属期货合约请求参数名称类型必须说明symbolString是国际贵金属期货品种代码成功返回样例{ "code": 200,//返回码对应描述 "msg": "成功",//返回码,详见返回码说明 "taskNo": "251234402215985750524304",//本次请求号 "charge": true,//计费标志 "data": { "list": [ "SI", "SI2411", "SI2412", "SI2501", "SI2503", "SI2505", "SI2507", "SI2509", "SI2512" ] } } }
  • 为什么运行run_and_test.bat一直卡在Begin running ...啊
    >run_and_test.bat ./demos/Solution.java ./data/practice_2.in ./data/practice_1.outCompiling Solution.java...Begin running ...本地运行后一直卡在这里python的也是这样
  • [区域初赛赛题问题] 请问初赛练习赛正确性满分是多少
    不然根本不知道自己的分应该优化正确性还是速度,优化了交上去都没有提示,作为练习赛,应该放开这一点吧
  • [区域初赛赛题问题] 准确标准疑问
    依据任务书3.0所说,先判断欧式距离是否和正确答案差距小于1e-4,再判断图形是否重合。如果出现图形A,B之间在边缘处重合,但是因为所需位移小于1e-4而输出(0,0)答案是否算错误
  • [技术干货] ISBN书号查询-ISBN图书查询-ISBN书号解析API接口介绍
    书号通常指国际标准书号(ISBN,International Standard Book Number),是国际通行的图书唯一标识符,相当于每一本书、每一种版本的“身份证号码”。书号的构成目前使用最广的是13位ISBN(2007 年之后全面推行),其结构为:前缀元素:固定为978或979(图书产品代码)国家/语言区号:如中国为7(简体中文出版物常用)出版社代码:由书号管理机构分配给出版社书序号:出版社为具体出版物分配的编号校验码:最后一位,用于验证书号是否正确书号的作用唯一标识:一本书的不同版本(精装、平装、电子书)、不同语种、不同格式都会有各自独立的书号。全球通用:在世界范围内,通过书号可以精准定位一本出版物。出版必备:在中国,正规出版物必须配有书号,才能进入发行渠道(实体书店、电商平台、图书馆等)。流通与数据基础:图书的编目、订购、库存、销售统计、版权管理都依赖书号。#书号查询API介绍可以接入书号查询API,根据书号来查询书本的详细信息,包括:书名、作者(编者、译者)、出版社、出版日期、出版地、版次、印次、装帧信息、纸张开数、语言、字数、页数等信息。详细使用参见此处请求参数名称类型必须说明isbnString是书的isbn码(必须是10、13位的纯数字)返回样例{ "code": 200, "msg": "成功", "taskNo": "65171553403304103621", "charge": true, "data": { "details": [ { "series": "",//丛书信息(不是丛书为空字符串) "title": "2",//书名 "author": "",//作者(编者、译者)信息 "publisher": "",//出版社 "pubDate": "",//出版日期 "pubPlace": "长春",//出版地 "isbn": "9787555357902",//13位isbn号 "isbn10": "7555357909",//10位isbn号 "price": "28.80",//定价 "genus": "TP311.132.3",//中图分类号 "levelNum": "",//读者评分 "heatNum": "0",//图书热度(即:购买或评论总人次) "format": "",//纸张开数 "binding": "平装",//装帧信息 "page": "",//页数 "wordNum": "",//字数 "edition": "1版",//版次 "yinci": "1",//印次 "paper": "",//书籍纸张类型 "language": "",//语言 "keyword": "",//图书关键词 "img": "",//封面图片大图链接,有效期10天。建议自行下载保存,避免丢失 "bookCatalog": "",//目录 "gist": "",//图书内容简介 "cipTxt": "",//cip信息 "annotation": "",//一般附注 "subject": "",//主题 "batch": ""//丛编信息 } ] } }
  • sleep10秒得到一样的成绩是咋回事?
    线上判题器对时延的敏感性到底如何?10s的时间不改变成绩嘛?
  • [区域初赛赛题问题] 交demo是多少分?
    想问一下各位py,c++,java交demo分别多少分啊,一样吗?
  • [区域初赛赛题问题] 编译错误能否返回报错信息
    本地可以编译的情况下排查起来真的很费时间
  • [区域初赛赛题问题] 无法多文件编译
    sh脚本好像只编译Solution文件,和官方说的编译全部文件不一致,导致无法多文件运行。
  • [问题求助] 单元测试的UT智能体不见了
    用的codearts IDE,用户指南说单元测试要用UT智能体但是ide没有这一项挠头 
  • [交流吐槽] 代码实例说明:关于建立“代码管理监控机制”的思路
    经过年复一年的开发积累,企业的代码仓逐渐变得臃肿,甚至变成屎山代码。这些屎山代码,往往经过N个程序员之手,他们水平参差不起,风格不一。如何对这些屎山代码进行统一的管理,让它们可以被监控、评价和批量改造?建立“代码管理系统”的第一个难点在于,如何在庞大的代码仓中,快速的查找出具有某些特征的代码段。由于我们需要查找的是代码段,而不是代码行,用传统的正则表达式难以实现,需要通过语法解析器进行自定义语法配置,然后进行代码查找。 以小实例说明 : ### 实例1: 找出JAVA代码中,入参数量超过4个的函数:# 配置查找规则(Code_manage.syn)如下所示:__DEF_CASE_SENSITIVE__ Y __DEF_FUZZY__ Y __DEF_DEBUG__ N __DEF_LINE_COMMENT__ // __DEF_LINES_COMMENT__ /* */ __DEF_STR__ __NAME__ <1,200> [1,1]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$?? [0,199]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_?? [NO] import if else for while break continue class return try except finally final static public private __DEF_PATH__ __FUNCTION_DEF__ 0101 : x1 @ | public : x2 @ + private 0 0 : x3 @ CAN_SKIP | static 1 1 : x4 @ | __NAME__ : x5 @ | __NAME__ : x6 @ | ( 1111 : p1 @ CAN_SKIP | final : p11 @ | __NAME__ : p111 @ | __NAME__ : p2 @ | , : p22 @ CAN_SKIP | final : p222 @ | __NAME__ : p2222 @ | __NAME__ : p3 @ | , : p33 @ CAN_SKIP | final : p333 @ | __NAME__ : p3333 @ | __NAME__ NNNN : p4 @ | , : p44 @ CAN_SKIP | final : x444 @ | __NAME__ : x4444 @ | __NAME__ 1111 : xx @ | )# 假设java代码(MyCode.java) 如下所示:private int alreadyBufferedSize = 0; // The index in the byte[] found at buffers.getLast() to be written next private int index = 0; // Is the stream closed? private boolean closed = false; public FastByteArrayOutputStream(int initialBlockSize) { Assert.isTrue(initialBlockSize > 0, "Initial block size must be greater than 0"); this.initialBlockSize = initialBlockSize; this.nextBlockSize = initialBlockSize; } @Override public void applyBeanPropertyValues(Object existingBean, String beanName, int autowireMode, boolean dependencyCheck, int initSize) throws BeansException { markBeanAsCreated(beanName); BeanDefinition bd = getMergedBeanDefinition(beanName); BeanWrapper bw = new BeanWrapperImpl(existingBean); initBeanWrapper(bw); applyPropertyValues(beanName, bd, bw, bd.getPropertyValues()); } @Override public Object initializeBean(Object existingBean, String beanName) { return initializeBean(beanName, existingBean, null); }根据配置规则,执行查找命令: ZGLanguage -e Code_manage.syn -f MyCode.java可以得到结果:C:\>ZGLanguage -e Code_manage.syn -f MyCode.java Run type : Find Syntax file : Code_manage.syn code file : MyCode.java Output file : out.zgl -------------------------------------------------------------------- ### Found code by : __FUNCTION_DEF__ | Lines : 17 ~ 17 : -------------------------------------------------------------------- public void applyBeanPropertyValues(Object existingBean, String beanName, int autowireMode, boolean dependencyCheck, int initSize)可以看出,查找结果只输出了函数 applyBeanPropertyValues,它的入参数量为5个,其他2个函数的入参均不超过4个,因此被忽略。 ### 实例2: 提取SQL代码中的关联(on)和筛选(where)代码段:# 配置查找规则(Code_manage.syn)如下所示:__DEF_DEBUG__ N __DEF_FUZZY__ Y __DEF_CASE_SENSITIVE__ N __DEF_LINE_COMMENT__ -- __DEF_LINES_COMMENT__ /* */ __DEF_PATH__ __WHERE__ 1 : x1 | where : x2 | __PATH_4_EXPR__ __DEF_PATH__ __ON__ 1 : x1 | __\b__ : x2 + __\t__ : x3 + __\n__ : x4 | on : x5 | __PATH_4_EXPR__ __DEF_SUB_PATH__ __PATH_4_EXPR__ 1 : x1 | __SUB_PATH_EXPR__ : x2 + __ONE_PATH_EXPR__ __DEF_SUB_PATH__ __SUB_PATH_EXPR__ 1 : x1 | ( : x2 | __ONE_PATH_EXPR__ : x3 | ) __DEF_SUB_PATH__ __ONE_PATH_EXPR__ NN : @ | __NAME__ : @ + __INT__ : @ + __FLOAT__ : @ + __CASE_WHEN__ : @ + __STRING__ : @ + __CAST_AS__ : @ + __FUNCTION__ : @ + __SUB_PATH_EXPR__ : @ + = : @ + <> : @ + != : @ + > : @ + >= : @ + < : @ + <= : @ + . : @ + , : @ + + : @ + - : @ + * : @ + / : @ + || : @ + null : @ + between : @ + and : @ + or : @ + like : @ + in : @ STRING + not in : @ STRING + is null : @ STRING + is not null __DEF_STR__ __NAME__ <1,100> [1,1]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_?? [0,100]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_?? [NO] select inner left join on from where group order by having union all with as table date time __DEF_STR__ __FLOAT__ <1,100> [1,50]0123456789 [1,1]. [1,50]0123456789 __DEF_STR__ __INT__ <1,100> [1,100]0123456789 __DEF_SUB_PATH__ __STRING__ 1 : x1 | ' : x2 | __ANY__ : x3 | ' __DEF_SUB_PATH__ __DECIMAL__ 111 : x1 | decimal 0 : x2 | ( 01 : x3 | __INT__ 00 : x4 | , 00 : x5 | __INT__ 01 : x6 | ) __DEF_SUB_PATH__ __VAR_NAME__ 1 : x1 | $ : x2 | { : x3 | __NAME__ : x4 | } __DEF_SUB_PATH__ __CASE_WHEN__ 1 : x1 @ | case N : x2 @ | when : x3 @ | __PATH_4_EXPR__ : x4 @ | then : x5 @ | __PATH_4_EXPR__ 1 : x6 @ CAN_SKIP | else : x7 @ CAN_SKIP | __PATH_4_EXPR__ : x8 @ | end __DEF_SUB_PATH__ __CAST_AS__ 1 : x1 | cast : x2 | ( 1 : x3 | __PATH_4_EXPR__ : x4 | as : x5 | date : x6 + int : n1 + double : n2 + float : n3 + bigint : x8 + __DECIMAL__ 1 : xx | ) __DEF_SUB_PATH__ __FUNCTION__ 1 : x1 @ | __NAME__ : x2 @ | ( N : x3 @ CAN_SKIP | __PATH_4_EXPR__ e : x4 @ CAN_SKIP | , 1 : x5 @ | )# 假设SQL代码(myproc.sql) 如下所示:CREATE OR REPLACE PROCEDURE PROC_F_CWWS_LOAN ( P_AS_OF_DATE IN DATE, RET_FLG OUT VARCHAR2, RET_MSG OUT VARCHAR2 ) IS -- 声明变量并初始化 V_COUNT NUMBER := 0; V_PROC_NAME VARCHAR2(200) := 'PROC_F_CWWS_LOAN'; V_PROC_DESC VARCHAR2(100) := 'xxxx业务数据ETL处理'; V_P_FREQ VARCHAR2(4) := ''; BEGIN --写入初始日志 INSERT INTO M_RUNLOG VALUES (SYSDATE, V_PROC_NAME, 'it is 1'); COMMIT; --设置会话日期格式 EXECUTE IMMEDIATE ' ALTER SESSION SET NLS_DATE_FORMAT = ''YYYY-MM-DD'''; --查询参数表中,该程序对应的频率值 SELECT P_FREQ INTO V_P_FREQ FROM ETL_PROC_STATUS_DEF WHERE PROC_NAME = V_PROC_NAME; --判断是调度频率 ETL.ETL_ADD_PARTITION('MA_F_LOAN', P_AS_OF_DATE, 'ETL'); --从还款计划表中取每笔账户最近一次小于等于数据日期还款日,作为上次还款日 INSERT INTO ETL.TMP_XD_LAST_PAYDATE (OBJECTNO, LAST_PAYDATE) SELECT OBJECTNO, LAST_PAYDATE FROM (SELECT T.OBJECTNO, MAX(TO_DATE(PAYDATE, 'YYYY-MM-DD')) LAST_PAYDATE FROM NYBDP.O_CWWS_ACCT_PAYMENT_SCHEDULE T WHERE T.AS_OF_DATE = P_AS_OF_DATE AND T.SEQID <> '999' AND TO_DATE(T.PAYDATE, 'YYYY-MM-DD') < P_AS_OF_DATE GROUP BY T.OBJECTNO); INSERT INTO M_RUNLOG VALUES (SYSDATE, V_PROC_NAME, 'it is 3'); COMMIT; MERGE INTO ETL.MA_F_LOAN A USING (SELECT /*+PARALLEL(8)*/ T.ACCOUNT_NUMBER, T.GL_ACCOUNT_ID, T.INT_GL_ACCOUNT_ID FROM ETL.MA_F_LOAN T INNER JOIN ETL.MA_D_GL_SUBJECT T1 ON T.INT_GL_ACCOUNT_ID = T1.SUBJECT_NO3 AND T1.SUBJECT_NAME3 LIKE '%已减值%' AND T1.AS_OF_DATE = P_AS_OF_DATE WHERE T.AS_OF_DATE = P_AS_OF_DATE AND T.ACCOUNT_NUMBER IN (SELECT ACCOUNT_NUMBER FROM (SELECT /*+PARALLEL(8)*/ T2.ACCOUNT_NUMBER, COUNT(1) FROM ETL.MA_F_LOAN T2 WHERE T2.AS_OF_DATE = P_AS_OF_DATE GROUP BY T2.ACCOUNT_NUMBER HAVING COUNT(1) > 1))) B ON (A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER AND A.AS_OF_DATE = P_AS_OF_DATE AND A.GL_ACCOUNT_ID = B.GL_ACCOUNT_ID AND A.INT_GL_ACCOUNT_ID = B.INT_GL_ACCOUNT_ID) WHEN MATCHED THEN UPDATE SET A.CUR_BOOK_BAL = 0, A.OVERDUE_BAL = 0; COMMIT; RET_FLG := '0'; RET_MSG := '执行成功'; EXCEPTION WHEN OTHERS THEN --写入异常日志 ETL.PROC_ETL_LOG(P_AS_OF_DATE,V_PROC_NAME,V_PROC_DESC,V_COUNT,-1,SQLCODE,SQLERRM); RET_MSG := SQLCODE || ':' || SQLERRM; END; /根据配置规则,执行查找命令: ZGLanguage -e Code_manage.syn -f myproc.sql可以得到结果:C:\>ZGLanguage -e Code_manage.syn -f myproc.sql Run type : Find Syntax file : Code_manage.syn code file : myproc.sql Output file : out.zgl -------------------------------------------------------------------- ### Found code by : __WHERE__ | Lines : 27 ~ 27 : -------------------------------------------------------------------- WHERE PROC_NAME = V_PROC_NAME -------------------------------------------------------------------- ### Found code by : __WHERE__ | Lines : 39 ~ 41 : -------------------------------------------------------------------- WHERE T.AS_OF_DATE = P_AS_OF_DATE AND T.SEQID <> '999' AND TO_DATE(T.PAYDATE, 'YYYY-MM-DD') < P_AS_OF_DATE -------------------------------------------------------------------- ### Found code by : __ON__ | Lines : 52 ~ 54 : -------------------------------------------------------------------- ON T.INT_GL_ACCOUNT_ID = T1.SUBJECT_NO3 AND T1.SUBJECT_NAME3 LIKE '%宸插噺鍊?' AND T1.AS_OF_DATE = P_AS_OF_DATE -------------------------------------------------------------------- ### Found code by : __WHERE__ | Lines : 55 ~ 56 : -------------------------------------------------------------------- WHERE T.AS_OF_DATE = P_AS_OF_DATE AND T.ACCOUNT_NUMBER IN -------------------------------------------------------------------- ### Found code by : __WHERE__ | Lines : 61 ~ 61 : -------------------------------------------------------------------- WHERE T2.AS_OF_DATE = P_AS_OF_DATE -------------------------------------------------------------------- ### Found code by : __ON__ | Lines : 64 ~ 66 : -------------------------------------------------------------------- ON (A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER AND A.AS_OF_DATE = P_AS_OF_DATE AND A.GL_ACCOUNT_ID = B.GL_ACCOUNT_ID AND A.INT_GL_ACCOUNT_ID = B.INT_GL_ACCOUNT_ID) WHEN MATCHED THEN UPDATE SET A.CUR_BOOK_BAL = 0, A.OVERDUE_BAL = 0可以看出,查找结果将 myproc.sql 代码中的 where 和 on 代码块及其所在行号提取出来。  
  • [技术干货] 后端 API 设计实战:RESTful API 规范与最佳实践
    作为后端开发者,API 是系统的门面,也是前后端协作的基石。一份规范、优雅、可扩展的 RESTful API,不仅能降低协作成本,更能支撑系统长期迭代。今天用实战视角,把 RESTful 设计规范与落地最佳实践一次性讲透。  一、先搞懂:什么是 RESTfulREST(Representational State Transfer)是一种架构风格,而非强制标准。 满足以下核心原则,才能叫 RESTful:面向资源(Resource),一切皆资源使用 HTTP 方法表达行为无状态(Stateless):每个请求独立完整统一接口:URI、Method、Status、Response 标准化目标:直观、自解释、易维护、易扩展。  二、URI 设计规范(最容易踩坑的地方) 1. 使用名词,而非动词/getUser/deleteOrder/createProduct错误:/getUser/deleteOrder/createProduct正确:/users/orders/products2. 复数形式 资源是集合,统一用复数: /users 而非 /user/items 而非 /item3. 层级关系用 / 表示/users/{id}/orders/users/{userId}/addresses/{addressId}4. 禁止大写、下划线,用中横线/userInfo ❌/user-info ✅5. 不要暴露文件后缀/api/users.json ❌/api/users ✅三、HTTP 方法语义(必须严格遵守)方法作用幂等安全GET查询资源✅✅POST新增资源❌❌PUT全量更新 / 替换✅❌PATCH局部更新✅❌DELETE删除✅❌实战示例:获取用户列表:GET /users获取单个用户:GET /users/{id}新建用户:POST /users全量更新:PUT /users/{id}局部更新:PATCH /users/{id}删除用户:DELETE /users/{id}  四、状态码使用(别再只返回 200/404 了)成功类200 OK:查询 / 修改成功201 Created:创建成功204 No Content:删除成功(无返回体)客户端错误400 Bad Request:参数错误401 Unauthorized:未登录 / Token 无效403 Forbidden:已登录但无权限404 Not Found:资源不存在405 Method Not Allowed:方法不支持422 Unprocessable Entity:校验失败服务端错误500 Internal Server Error:服务器异常502 Bad Gateway:网关错误503 Service Unavailable:服务不可用 五、统一响应体结构(前后端必约定)推荐通用结构:{ "code": 200, // 业务码 "message": "success", "data": {}, // 主体数据 "requestId": "xxx" // 方便排查问题}成功:code=200失败:使用具体业务码,如 1001、4001禁止:成功失败混用结构六、分页、排序、过滤(标准写法)1. 分页GET /users?pageNum=1&pageSize=102. 排序GET /users?sort=createTime,desc3. 过滤GET /users?gender=male&status=active原则: 查询条件全部放 query不要放 body(GET 不规范)  七、版本管理(API 必做)三种主流方式,任选其一并统一:URL 路径(最常用)/api/v1/users/api/v2/users请求头Accept-version: v1参数/users?version=1建议:新项目直接用 v1 起步。八、安全与最佳实践必须 HTTPSToken 放 Header:Authorization: Bearer {token}敏感参数不暴露在 URL请求参数必校验接口限流防刷日志记录 requestId、入参、耗时、异常跨域使用 CORS,不要乱用 JSONP提供 API 文档:Swagger / Knife4j / OpenAPI 九、反例 vs 正例(一眼看懂差距)❌ 混乱不规范:/getUserInfo?id=1/api/delete_order/1/userList?type=1&page=1✅ RESTful 规范:GET /api/v1/users/1DELETE /api/v1/orders/1GET /api/v1/users?type=1&pageNum=1&pageSize=10十、总结一句话RESTful 不是花架子,而是团队协作的通用语言:资源用名词复数行为用 HTTP 方法状态码表达结果结构统一、版本必加、安全必做
  • [技术干货] Prometheus+Grafana+Alertmanager 监控体系搭建与告警优化实战
    Prometheus+Grafana+Alertmanager 监控体系搭建与告警优化实战在微服务、容器化普及的当下,一套高效、可靠的监控告警体系,是保障系统稳定运行的“生命线”。Prometheus负责数据采集与存储,Grafana负责可视化展示,Alertmanager负责告警分发与处理,三者联动形成“采集-展示-告警”全链路监控闭环,也是当前企业级监控的主流方案。本文从实战出发,手把手教你搭建Prometheus+Grafana+Alertmanager监控体系,同时分享高频告警优化技巧,解决“监控不准、告警泛滥、漏报误报”等核心痛点,适合运维、开发、架构师参考,可直接用于生产环境落地。一、监控体系核心架构:三者各司其职,联动闭环在动手搭建前,先明确三者的核心分工,避免搭建过程中混淆角色,确保体系高效运转:Prometheus(普罗米修斯):核心采集器,负责从目标设备(服务器、容器、微服务、数据库等)采集指标数据(如CPU使用率、内存占用、接口QPS),并以时序数据的形式存储,支持灵活的查询语句(PromQL)。Grafana(格拉法纳):可视化面板,对接Prometheus数据源,通过拖拽式操作生成直观的监控仪表盘,支持折线图、柱状图、仪表盘等多种展示形式,轻松实现“一眼看清系统状态”。Alertmanager(告警管理器):告警处理器,接收Prometheus触发的告警规则,进行去重、分组、路由,然后分发到指定渠道(邮件、企业微信、钉钉、Slack),同时支持告警抑制、静默等高级功能,避免告警泛滥。核心流程:Prometheus采集数据 → 存储时序数据 → Grafana可视化展示 → 触发告警规则 → Alertmanager处理并分发告警 → 运维人员响应处理。二、实战搭建:从0到1部署监控体系(Docker部署,最简单易落地)推荐使用Docker部署,无需复杂的环境配置,快速完成搭建,适合新手和生产环境快速落地。提前准备:服务器(推荐2核4G以上)、Docker、Docker Compose(简化部署命令)。1. 环境准备(前置操作)# 1. 安装Docker(略,已有Docker可跳过)# 2. 安装Docker Composecurl -L "https://github.com/docker/compose/releases/download/v2.20.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-composechmod +x /usr/local/bin/docker-compose# 3. 创建工作目录,统一管理配置文件mkdir -p /data/monitor/{prometheus,grafana,alertmanager}cd /data/monitor  2. 编写Docker Compose配置文件(核心)创建docker-compose.yml文件,整合三者服务,一键启动,配置如下(可直接复制修改):version: '3.8'services: # Prometheus服务 prometheus: image: prom/prometheus:v2.45.0 container_name: prometheus ports: - "9090:9090" # Prometheus访问端口 volumes: - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml # 核心配置文件 - prometheus_data:/prometheus # 数据持久化 restart: always networks: - monitor_net # Grafana服务 grafana: image: grafana/grafana:10.2.0 container_name: grafana ports: - "3000:3000" # Grafana访问端口 volumes: - grafana_data:/var/lib/grafana # 数据持久化 restart: always depends_on: - prometheus # 依赖Prometheus,确保先启动 networks: - monitor_net # Alertmanager服务 alertmanager: image: prom/alertmanager:v0.26.0 container_name: alertmanager ports: - "9093:9093" # Alertmanager访问端口 volumes: - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml # 告警配置 restart: always depends_on: - prometheus networks: - monitor_netvolumes: prometheus_data: grafana_data:networks: monitor_net: driver: bridge3. 配置Prometheus(数据采集核心)创建Prometheus核心配置文件prometheus.yml,定义数据采集目标、存储策略、告警规则关联,关键配置如下global: scrape_interval: 15s # 采集间隔,默认15秒,可根据需求调整 evaluation_interval: 15s # 告警规则评估间隔# 告警规则配置,关联Alertmanageralerting: alertmanagers: - static_configs: - targets: - alertmanager:9093 # 对接Alertmanager服务# 告警规则文件(可拆分,便于维护)rule_files: - "alert_rules.yml" # 后续创建,定义具体告警规则# 采集目标配置(核心:监控哪些设备/服务)scrape_configs: # 1. 监控Prometheus自身 - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] # 2. 监控服务器(需在服务器安装node_exporter,下文说明) - job_name: 'server' static_configs: - targets: ['服务器IP:9100'] # node_exporter端口 # 3. 监控Docker容器(需安装cadvisor) - job_name: 'docker' static_configs: - targets: ['服务器IP:8080'] # cadvisor端口 # 4. 监控微服务(以Spring Boot为例,需集成micrometer) - job_name: 'spring-boot' metrics_path: '/actuator/prometheus' static_configs: - targets: ['微服务IP:8080']  4. 配置Alertmanager(告警分发核心)创建Alertmanager配置文件alertmanager.yml,定义告警路由、接收渠道(以企业微信为例,最常用),配置如下:global: resolve_timeout: 5m # 告警解决后,5分钟内不再重复发送# 告警路由:默认路由,所有告警先进入这里route: group_by: ['alertname'] # 按告警名称分组,同一类型告警合并发送 group_wait: 10s # 组内第一个告警触发后,等待10秒,收集同组告警一起发送 group_interval: 10s # 同一组告警,两次发送间隔 repeat_interval: 1h # 同一告警,重复发送间隔(避免频繁骚扰) receiver: 'wechat' # 默认接收者# 接收者配置(企业微信)receivers:- name: 'wechat' wechat_configs: - corp_id: '你的企业微信corp_id' to_user: '@all' # 接收人,@all表示全员 agent_id: '你的应用agent_id' api_secret: '你的应用api_secret'# 告警抑制:避免关联告警泛滥(如CPU高告警触发后,不再发送内存高告警)inhibit_rules:- source_match: severity: 'critical' # 源告警级别(严重) target_match: severity: 'warning' # 目标告警级别(警告) equal: ['instance'] # 相同实例的告警,严重告警抑制警告告警5. 配置告警规则(触发告警的条件)在Prometheus配置目录下创建alert_rules.yml,定义常用告警规则(服务器、容器、服务),可根据实际需求扩展:groups:- name: 服务器监控告警 rules: # CPU使用率超过80%,持续5分钟,触发警告;超过90%,持续3分钟,触发严重告警 - alert: CPU使用率过高 expr: avg(rate(node_cpu_seconds_total{mode!='idle'}[5m])) by (instance) * 100 > 80 for: 5m labels: severity: warning annotations: summary: "CPU使用率过高" description: "实例 {{ $labels.instance }} CPU使用率超过80%,当前值:{{ $value | humanizePercentage }}" - alert: CPU使用率危急 expr: avg(rate(node_cpu_seconds_total{mode!='idle'}[5m])) by (instance) * 100 > 90 for: 3m labels: severity: critical annotations: summary: "CPU使用率危急" description: "实例 {{ $labels.instance }} CPU使用率超过90%,当前值:{{ $value | humanizePercentage }}" # 内存使用率超过85%,触发警告 - alert: 内存使用率过高 expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100 > 85 for: 5m labels: severity: warning annotations: summary: "内存使用率过高" description: "实例 {{ $labels.instance }} 内存使用率超过85%,当前值:{{ $value | humanizePercentage }}"- name: 容器监控告警 rules: # 容器CPU使用率超过90%,持续3分钟 - alert: 容器CPU使用率过高 expr: avg(rate(container_cpu_usage_seconds_total[3m])) by (container_name) * 100 > 90 for: 3m labels: severity: warning annotations: summary: "容器CPU使用率过高" description: "容器 {{ $labels.container_name }} CPU使用率超过90%,当前值:{{ $value | humanizePercentage }}"- name: 微服务监控告警 rules: # 服务接口错误率超过5%,持续2分钟 - alert: 微服务接口错误率过高 expr: sum(rate(http_server_requests_seconds_count{status=~"5.."}[2m])) / sum(rate(http_server_requests_seconds_count[2m])) * 100 > 5 for: 2m labels: severity: critical annotations: summary: "微服务接口错误率过高" description: "微服务接口错误率超过5%,当前值:{{ $value | humanizePercentage }}"  6. 启动服务,完成搭建# 启动所有服务docker-compose up -d# 查看服务状态,确保所有服务正常运行docker-compose ps# 查看日志,排查启动异常docker-compose logs -f启动成功后,访问对应端口验证:Prometheus:http://服务器IP:9090 (可查看采集目标、告警规则)Grafana:http://服务器IP:3000 (默认账号密码admin/admin,首次登录需修改)Alertmanager:http://服务器IP:9093 (可查看告警记录、静默规则)7. Grafana可视化配置(关键步骤)Grafana默认无监控面板,需对接Prometheus数据源,导入预制面板(无需手动拖拽):登录Grafana,点击左侧「Configuration」→「Data Sources」,点击「Add data source」,选择「Prometheus」;在URL中输入「http://prometheus:9090」,点击「Save & Test」,提示“Data source is working”即为成功;导入预制面板:点击左侧「Dashboards」→「Import」,输入面板ID(服务器监控用8919,Docker监控用893,Spring Boot监控用12856),选择已配置的Prometheus数据源,点击「Import」;导入完成后,即可在Grafana中查看直观的监控面板,支持自定义调整面板样式、指标展示。三、告警优化:解决漏报、误报、泛滥三大痛点很多人搭建完监控体系后,会陷入“告警泛滥”“误报频发”“关键告警漏报”的困境,核心原因是告警规则、路由配置不合理。以下是生产环境高频优化技巧,直接复用即可。1. 优化告警规则:避免误报,精准触发设置合理的「for」时间:避免瞬时波动触发告警(如CPU瞬时冲高到80%,持续5分钟再触发,而非立即触发);细化告警阈值:按服务/设备重要性区分阈值(如核心服务器CPU阈值80%,非核心服务器90%);使用「rate()」函数:计算一段时间内的平均指标,避免瞬时值误触发(如rate(node_cpu_seconds_total[5m]));添加「annotations」描述:告警信息中包含实例、当前值、处理建议,便于运维人员快速响应(如上文告警规则中的description)。2. 优化Alertmanager:避免告警泛滥,精准分发合理分组(group_by):按「alertname、instance、service」分组,同一类型、同一实例的告警合并发送,避免多条重复告警;设置重复发送间隔(repeat_interval):核心告警1小时重复一次,非核心告警2-4小时重复一次,避免频繁骚扰;启用告警抑制(inhibit_rules):关联告警抑制(如CPU高告警触发后,抑制内存高告警),减少无效告警;按 severity 分渠道分发:critical(严重)告警发送到企业微信+电话,warning(警告)告警仅发送企业微信,避免过度告警。3. 优化数据采集:提升监控准确性,避免漏报调整采集间隔(scrape_interval):核心服务/设备采集间隔设为10-15s,非核心设为30s-1min,平衡性能与准确性;增加采集超时时间:避免网络波动导致采集失败,在scrape_configs中添加「scrape_timeout: 10s」;监控采集目标状态:在Prometheus中添加「up」指标告警(up==0表示采集失败),避免因采集失败导致漏报。4. 实战优化案例(可直接复用)场景:核心微服务接口错误率告警,避免瞬时错误触发误报,同时确保严重错误及时通知:四、生产环境落地避坑指南踩坑1:数据未持久化,容器重启后监控数据丢失 → 解决方案:配置Docker volumes挂载,如本文Docker Compose中的prometheus_data、grafana_data;踩坑2:告警规则过于简单,导致误报频发 → 解决方案:添加for时间、细化阈值、使用rate()函数,避免瞬时波动触发;踩坑3:Alertmanager未配置告警抑制,关联告警泛滥 → 解决方案:按severity配置抑制规则,避免同一实例的关联告警重复发送;踩坑4:Grafana面板导入后无数据 → 解决方案:检查Prometheus数据源配置是否正确,采集目标是否正常(Prometheus的Targets页面查看);踩坑5:采集间隔过短,导致Prometheus资源占用过高 → 解决方案:核心服务15s,非核心30s以上,避免过度采集;踩坑6:告警渠道配置错误,导致告警无法接收 → 解决方案:先测试告警渠道(如企业微信发送测试消息),再配置到Alertmanager。 
  • [技术干货] 微服务架构下的服务网格 Istio 实战:流量治理、安全与可观测性一站式落地
    随着微服务规模从几十到上百甚至上千,传统的 “代码埋点 + 配置中心” 的治理方式早已力不从心 —— 服务间调用链路混乱、流量管控粒度粗、安全认证散落在各服务、问题排查全靠日志大海捞针… 而Istio作为当前最主流的服务网格(Service Mesh)框架,通过 “数据面 + 控制面” 的无侵入架构,完美解决了微服务治理的痛点。本文从实战角度,带你掌握 Istio 核心能力:流量治理、服务安全、可观测性,零基础也能落地。随着微服务规模从几十到上百甚至上千,传统的 “代码埋点 + 配置中心” 的治理方式早已力不从心 —— 服务间调用链路混乱、流量管控粒度粗、安全认证散落在各服务、问题排查全靠日志大海捞针… 而Istio作为当前最主流的服务网格(Service Mesh)框架,通过 “数据面 + 控制面” 的无侵入架构,完美解决了微服务治理的痛点。本文从实战角度,带你掌握 Istio 核心能力:流量治理、服务安全、可观测性,零基础也能落地。 一、先搞懂:Istio 到底是什么? Service Mesh(服务网格)是微服务的 “网络中间件”,Istio 则是它的 “标杆实现”: 🧩 架构分层:控制面(Istiod):负责配置管理、服务发现、策略下发,核心大脑;数据面(Envoy 代理):以 Sidecar 模式注入到每个服务 Pod 中,拦截所有进出流量,无需修改业务代码。 ✨ 核心价值:无侵入实现流量管控、安全认证、监控追踪,让业务开发专注业务,治理交给 Istio。🎯 适用场景:K8s 环境下的微服务集群(这也是 Istio 的主要落地场景)。 二、实战 1:流量治理 —— 精准控制服务间流量 流量治理是 Istio 最核心的能力,覆盖灰度发布、故障注入、流量分流、熔断限流等场景,以下是高频实战场景: 1. 灰度发布(金丝雀发布) 场景:将 10% 的流量路由到新版本服务(v2),90% 保留在 v1,验证新版本稳定性。   # 定义目标规则:区分v1和v2版本 apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: order-service spec: host: order-service # 服务名 subsets: - name: v1 labels: version: v1 - name: v2 labels: version: v2 # 定义虚拟服务:流量分流规则 apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: order-service spec: hosts: - order-service http: - route: - destination: host: order-service subset: v1 weight: 90 # 90%流量到v1 - destination: host: order-service subset: v2 weight: 10 # 10%流量到v2部署后,仅需修改 weight 参数,即可平滑将流量切到 100% v2,全程无服务中断。 2. 故障注入 —— 模拟服务异常 场景:测试下游服务超时 / 错误时,上游服务的容错能力(无需修改代码)。 apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: payment-service spec: hosts: - payment-service http: - fault: abort: httpStatus: 500 # 注入500错误 percentage: value: 30 # 30%的请求返回500 route: - destination: host: payment-service subset: v1 通过该配置,可模拟 30% 的支付请求失败,验证订单服务的重试 / 降级逻辑是否生效。 3. 熔断限流 —— 保护服务不被打垮 当 user-service 出现异常时,Istio 会自动熔断,避免故障扩散到整个集群。apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: user-service spec: host: user-service trafficPolicy: connectionPool: tcp: maxConnections: 100 # 最大TCP连接数 http: http1MaxPendingRequests: 100 # 最大挂起请求数 maxRequestsPerConnection: 10 # 每个连接最大请求数 outlierDetection: consecutiveErrors: 5 # 连续5次错误触发熔断 interval: 30s # 检测间隔 baseEjectionTime: 30s # 熔断后剔除时间三、实战 2:服务安全 —— 零代码实现认证与加密 微服务间的 “通信安全” 是刚需,Istio 提供了开箱即用的安全能力,无需在业务代码中写认证逻辑: 1. 双向 TLS(mTLS)—— 服务间加密通信 一键开启集群内所有服务的双向 TLS 认证,所有流量自动加密:   apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication metadata: name: default namespace: default spec: mtls: mode: STRICT # 强制开启mTLS开启后:只有携带合法 Istio 证书的服务才能通信,杜绝非法服务接入;所有服务间流量自动通过 TLS 加密,无需配置 HTTPS 证书。2. 授权策略 —— 精细化控制访问权限场景:仅允许 order-service 访问 payment-service,拒绝其他服务调用:  apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: payment-service-auth namespace: default spec: selector: matchLabels: app: payment-service action: ALLOW rules: - from: - source: principals: ["cluster.local/ns/default/sa/order-service-sa"] # 仅允许order-service的服务账号 to: - operation: methods: ["POST"] # 仅允许POST方法四、实战 3:可观测性 —— 全方位监控追踪Istio 内置了对 Prometheus、Grafana、Jaeger 的原生支持,无需手动埋点,即可实现:1. 指标监控(Metrics)部署 Istio 后,自动采集以下核心指标:服务调用成功率、延迟、QPS;流量分布、错误率、熔断次数;Sidecar 代理的资源占用。通过 Grafana Istio 仪表盘,可一键查看集群级 / 服务级 / 接口级的监控数据,快速定位性能瓶颈。2. 分布式追踪(Tracing)仅需在服务中传递x-request-id头,Istio 即可自动生成全链路追踪数据,对接 Jaeger 后:可视化展示请求从入口网关到各微服务的完整链路;定位链路中耗时最长的服务 / 接口;关联日志和指标,快速排查 “偶发超时 / 错误” 问题。3. 访问日志(Logging) 配置 Sidecar 输出详细访问日志,包含:[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"   日志包含请求方法、路径、响应码、耗时、上游服务等关键信息,可接入 ELK 进行检索分析。五、落地建议 & 避坑指南✅ 落地步骤(循序渐进)先在测试环境部署 Istio,仅注入核心服务(如网关、订单、支付);先启用监控和日志能力,熟悉 Istio 的基础运维;逐步接入流量治理规则(先灰度,再熔断,最后故障注入);最后启用 mTLS 和授权策略,完成安全加固。🚫 避坑点不要一次性给所有服务注入 Sidecar,避免资源占用突增;控制面(Istiod)需单独配置资源限制,避免成为性能瓶颈;虚拟服务规则优先级需理清,避免规则冲突导致流量异常;监控数据需设置保留策略,避免 Prometheus 磁盘占满。总结Istio 通过 “无侵入” 的方式,为微服务架构提供了流量治理、安全、可观测性三大核心能力,解决了传统微服务治理的痛点:流量治理:支持灰度发布、故障注入、熔断限流,无需修改业务代码;服务安全:一键开启 mTLS 加密和精细化授权,降低安全开发成本;可观测性:自动采集指标、追踪、日志,实现全链路问题排查。对于中大型微服务集群,Istio 不是 “可选项” 而是 “必选项”—— 它让微服务治理从 “零散的代码埋点” 升级为 “平台化的统一管控”,大幅提升运维效率和系统稳定性。 
总条数:764 到第
上滑加载中