-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontent.json
More file actions
1 lines (1 loc) · 132 KB
/
content.json
File metadata and controls
1 lines (1 loc) · 132 KB
1
{"meta":{"title":"Wei Echo","subtitle":"高效稳定 · 简洁易用 · 灵活扩展","description":"致力于中小型技术团队高效稳定的开发框架,全力打造简洁易用、灵活扩展的技术团队解决方案","author":"Wei Echo","url":"https://github.com/weiecho","root":"/"},"pages":[{"title":"分类","date":"2019-09-07T06:11:44.000Z","updated":"2019-09-07T07:02:14.062Z","comments":true,"path":"categories/index.html","permalink":"https://github.com/weiecho/categories/index.html","excerpt":"","text":""},{"title":"archives","date":"2019-09-07T02:43:41.000Z","updated":"2019-09-07T07:37:44.969Z","comments":true,"path":"archives/index.html","permalink":"https://github.com/weiecho/archives/index.html","excerpt":"","text":""},{"title":"标签","date":"2019-09-07T06:20:06.000Z","updated":"2019-09-07T07:02:07.740Z","comments":true,"path":"tags/index.html","permalink":"https://github.com/weiecho/tags/index.html","excerpt":"","text":""},{"title":"友情链接","date":"2019-09-07T03:53:31.000Z","updated":"2019-09-07T13:19:13.083Z","comments":false,"path":"links/index.html","permalink":"https://github.com/weiecho/links/index.html","excerpt":"","text":"柴伙二维码平台柴伙二维码云平台,汇聚全国100万精品微信小程序、微信群二维码、微信红包群、陌陌、QQ、个人号、群组及公众号等二维码发布推广,为用户提供一个安全、靠谱的互联网应用导航商店和商务合作推广平台。 阿里云计算平台阿里云是阿里巴巴集团旗下公司,是全球领先的云计算及人工智能科技公司。提供云服务器、云数据库、云安全、企业应用等云计算服务,以及大数据、人工智能解决方案,精准定制基于场景的行业解决方案。 微信公众平台微信公众平台,给个人、企业和组织提供业务服务与用户管理能力的全新服务平台。 融云互联网通信云服务商融云是安全、可靠的全球互联网通信云服务商,向开发者和企业提供即时通讯和实时音视频通信云服务。融云可提供多种部署模式:公有云、私有云及混合云,服务覆盖全球所有国家及地区。已有25万开发者和上千家企业用户通过融云实现了场景化沟通。 友盟数据智能服务商友盟是国内领先的第三方全域数据智能服务商。专注为互联网企业提供一站式数据分析运营服务近10年。为开发者提供更灵活、更智能、更专业的数据采集、分析、管理功能,AI赋能业务增长。"}],"posts":[{"title":"Elastic-Monitor 服务监控报警","slug":"doc_1128","date":"2020-09-12T07:36:05.000Z","updated":"2020-09-10T09:54:55.318Z","comments":true,"path":"2020/09/12/doc_1128/","link":"","permalink":"https://github.com/weiecho/2020/09/12/doc_1128/","excerpt":"","text":"策略配置说明 1、黑名单策略配置主要用于关键功能点报警,周期为20秒,可结合各项指标的interval设定数据分析间隔时间,message内包含keywords词组即报警,可以通过配置declaringClass + methodName + keywords组合方式实现项目的全局 / 细粒度报警,周期线程接近于实时的快速检测保证服务关键业务快速报警响应。 业务功能范围:访问异常报警、业务问题项报警、各类可预期性报警。 123456789101112131415elastic: monitor: blacklist: cron: \"0/20 * * * * ?\" strategy: - alertBot: c678f3a0d6b8a19ab07c62a847994aaf3e684cfa7a41827dec7d91568b78ca1e subject: XX关键点报警 serviceName: payment-sms-provider declaringClass: \"*\" methodName: \"*\" limit: 0 #频次阈值 interval: 300 #5分钟 keywords: - Alert - Call 2、白名单策略配置主要用于核心功能点报警,周期为30秒/次,可结合各项指标的interval设定数据分析间隔时间,message内未包含keywords词组即报警,可以通过配置declaringClass + methodName + keywords组合方式实现项目的全局 / 细粒度报警,周期线程接近于实时的快速检测保证服务关键业务快速报警响应。 业务功能范围:关键业务点必须有Token、预设防非法攻击参数等。 1234567891011121314elastic: monitor: whitelist: cron: \"0/30 * * * * ?\" strategy: - alertBot: c678f3a0d6b8a19ab07c62a847994aaf3e684cfa7a41827dec7d91568b78ca1e subject: XX关键点报警 serviceName: payment-sms-provider declaringClass: \"*\" methodName: \"*\" limit: 1 #频次阈值 interval: 300 #5分钟 keywords: - mobile 3、环比策略配置主要用于服务业务快速增长点/下降点预知和压力点防灾,周期为1分钟/次,可结合各项指标的interval设定数据分析间隔时间,可设置日志level、环比天数relative、浮动比例 limit,可以通过配置declaringClass + methodName + level组合方式实现项目的全局 / 细粒度报警,及时感知服务点激增爆点,预算服务抗压策略。 业务功能范围:服务访问量对比、日志异常量对比、服务全量日志量对比、关键业务点日志量比对。 12345678910111213elastic: monitor: relative: cron: \"0 0/5 * * * ?\" strategy: - alertBot: a483f4b1375a5a33b068c292413562c6aef6b32d7d1ae150c4d47d32f4af9322 subject: 服务访问量提醒 serviceName: payment-sms-provider declaringClass: \"com.opay.trace.TraceIdFilter\" methodName: \"invoke\" relative: 7 #与第N天数据比较 level: INFO limit: 100 #浮动比例 100% 4、失败频次策略配置主要用于服务业务点功能频次分析,周期为1分/次,可设置日志level、频次阈值limit,可以通过配置declaringClass + methodName + successKeyword/failureKeyword组合方式实现项目的全局 / 细粒度报警,及时感知服务核心业务交易状况和压力值,快速提醒相关人员做出关键业务点承压防范。 业务功能范围:错误记录超量提醒、核心业务点超阈值报警、新上功能压力测算等。 1234567891011121314elastic: monitor: frequency: cron: \"0 0/1 * * * ?\" strategy: - alertBot: a483f4b1375a5a33b068c292413562c6aef6b32d7d1ae150c4d47d32f4af9322 subject: RECEIVEMONEY失败记录超量提醒 serviceName: payment-channel-provider declaringClass: \"*\" methodName: \"*\" successKeyword: \"ALERT-SUM-RECEIVEMONEY-SUCCESS\" failureKeyword: \"ALERT-SUM-RECEIVEMONEY-FAIL\" limit: 10 #浮动比例 10% interval: 900 #10分钟 5、黑名单信息策略配置主要用于服务业务关键性信息提醒(单次查询内第一条信息),周期为10秒/次,可结合各项指标的interval设定数据分析间隔时间,可设置日志level、频次阈值limit,可以通过配置declaringClass + methodName + keywords组合方式实现项目的全局 / 细粒度关键词报警,及时感知服务核心业务交易出现问题点,快速提醒相关人员做出关键业务修正。 业务功能范围:错误信息提醒,关键业务点状况提醒等。 12345678910111213elastic: monitor: blackinfo: cron: \"0/10 * * * * ?\" strategy: - alertBot: a483f4b1375a5a33b068c292413562c6aef6b32d7d1ae150c4d47d32f4af9322 subject: TV充值退票 serviceName: payment-channel-callback declaringClass: \"*\" methodName: \"*\" interval: 10 #10秒 keywords: - CALLBACK-REQUEST 6、异常提醒策略配置主要用于服务业务点throw异常分析,周期为1分/次,可结合各项指标的interval设定数据分析间隔时间,可以通过配置declaringClass + methodName + keywords 组合方式实现项目的全局 / 细粒度报警,及时感知服务核心关键业务异常状况,快速提醒相关人员做出关键业务点服务状况检查。 业务功能范围:服务调用异常提醒、核心业务异常报警等。 1234567891011121314elastic: monitor: exceptions: cron: \"0 * * * * ?\" strategy: - alertBot: 2429618fec9ea28924cb4077d898e51c0053b7d693b7313daadecfb08057560a subject: 服务接口调用异常 serviceName: payment-graphql-web declaringClass: \"*\" methodName: \"*\" limit: 0 #频次阈值 interval: 300 #5分钟 keywords: - billCenterFacade.lookupBillCenterTransactions 7、节点策略配置主要用于实时监测服务在活状态,周期为30秒/次,可以通过配置节点IP+端口,保障各类服务安全稳健运行。 业务功能范围:HTTP服务在活监测、TCP服务在活监测、其他监控在活状态。 123456789elastic: monitor: nodes: cron: \"0/30 * * * * ?\" strategy: - alertBot: 7906fd7214b0935195862464fa14dc340e36ce4f2ba3bd1085b5ea935110dbda serviceName: payment-sms-provider nodes: - 10.112.21.120:11009 8、日报策略配置主要用于每天凌晨(北京8:00)推送项目运行报告,周期为1天/次,帮助您每天跟踪了解服务的访问量、日志量等。 业务功能范围:服务运行状况报告。 1234567elastic: monitor: diary: cron: \"0 0 8 * * ?\" strategy: - alertBot: a483f4b1375a5a33b068c292413562c6aef6b32d7d1ae150c4d47d32f4af9322 serviceName: payment-sms-provider 9、自检策略配置1) 监控服务自检提醒,周期为北京10,16,20点(可配),管理人员每天感知监控服务在活状态; 2) 监控服务主从自检,周期为1分/次(固定),所有策略由主节点监测,防止重复检查和报警,主节点宕机3分钟后从节点升级为主节点,同时推送相关信息。 功能范围:服务在活状况检测、监控服务自检保障。 elastic: monitor: health: cron: “0 0 10,16,20 * * ?” #自检提醒周期 strategy: alertBot: c678f3a0d6b8a19ab07c62a847994aaf3e684cfa7a41827dec7d91568b78ca1e 关键配置项释义 配置项 说明 备注 alertBot 报警机器人Key 群机器人ID,需设置关键词“服务” cron cron定时周期 各策略循环周期 declaringClass 调用类 对应ELK字段,全部设置为“*” keywords 关键词列表 message消息体内包含的关键词 level 消息等级 对应ELK字段,全部设置为“ALL” limit 频次阈值/浮动比例 频次阈值-固定值,浮动比例-10 -> 10% (90%~110%) methodName 调用方法 对应ELK字段,全部设置为“*” nodes 服务节点 IP+端口,TCP配置为“tcp://ip:port”(tcp://10.112.22.14:2181) relative 环比天数 与前N天对比,单位:天 serviceName 项目服务名称 ELK日志服务名称 projectName interval 间隔时间 监控调用间隔时间 subject 消息主题 报警项消息主题说明,在消息头显示 * 每个业务指标需确保1分钟内消息不超过20条 - alertBot钉钉机器人限制 *","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"监控报警","slug":"监控报警","permalink":"https://github.com/weiecho/tags/%E7%9B%91%E6%8E%A7%E6%8A%A5%E8%AD%A6/"}]},{"title":"xxl-job分布式定时任务策略验证说明","slug":"exp_1118","date":"2020-09-10T03:27:01.000Z","updated":"2020-09-10T03:28:05.880Z","comments":true,"path":"2020/09/10/exp_1118/","link":"","permalink":"https://github.com/weiecho/2020/09/10/exp_1118/","excerpt":"","text":"XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。 测试机器:116、143、220 1、FIRST(第一个) — 固定选择注册列表的第一个机器测试1:运行3个执行器服务,注册列表排序143、220、116,应该每次都在143服务执行(符合预期)。 测试2: 关闭143服务,任务应该路由到220上执行(符合预期)。 测试3: 关闭220服务,任务应该路由到116上执行(符合预期)。 2、LAST(最后一个) — 固定选择注册列表的最后一个机器测试1:运行3个执行器服务,注册列表排序143、220、116,应该每次都在116服务执行(符合预期)。 测试2: 关闭116服务,任务应该路由到220上执行(符合预期)。 测试3: 关闭220服务,任务应该路由到143上执行(符合预期)。 3、ROUND(轮询) — 循环选择执行注册列表的一个机器测试1:运行3个执行器服务,注册列表排序143、220、116,依次在3个服务执行(符合预期)。 测试2:设置调度时间为2秒,当调度再次调度到143个服务时,后一次调度会阻塞2s左右,阻塞策略针对单执行器生效(符合预期)。 测试3: 关闭220服务,自动调整(符合预期)。 4、RANDOM(随机) — 随机选择注册列表的一个机器测试1:运行3个执行器服务,注册列表排序143、220、116,随机在3个服务执行(符合预期)。 测试2: 关闭220服务,自动调整(符合预期)。 5、CONSISTENT_HASH(一致性HASH) — 每个任务按照Hash算法固定选择某一台机器,且所有任务均匀散列在不同机器上测试1:运行3个执行器服务,注册列表排序143、220、116,配置3个任务,同一任务固定在一台服务器执行(符合预期)。 测试2:关闭220服务,自动重新负载,将220上执行的任务调度到另一个服务上执行(符合预期)。 6、LEAST_FREQUENTLY_USED(最不经常使用) — 使用频率最低的机器优先被选举测试1:运行3个执行器服务,注册列表排序143、220、116,服务自动选择合适执行服务器(符合预期)。 7、LEAST_RECENTLY_USED(最近最久未使用) — 最久为使用的机器优先被选举测试1:运行3个执行器服务,注册列表排序143、220、116,服务自动选择合适执行服务器(符合预期)。 8、FAILOVER(故障转移) — 按照顺序依次进行心跳检测,第一个心跳检测成功的机器选定为目标执行器并发起调度测试1:运行3个执行器服务,注册列表排序143、220、116,先触发一次心跳检查,选择在活的执行服务器(符合预期)。 测试2:如果所有的执行器都故障,不执行路由,直接调度失败(服务全部关闭时直接爆执行器地址为空,没有模拟出该情况)。 9、BUSYOVER(忙碌转移) — 按照顺序依次进行空闲检测,第一个空闲检测成功的机器选定为目标执行器并发起调度测试1:运行3个执行器服务,注册列表排序143、220、116,先自动触发一次空闲检查,选择空闲的执行服务器(符合预期)。 测试2:如果所有的执行器都忙碌,不执行路由,直接调度失败(job thread is running or has trigger queue)(符合预期)。 10、SHARDING_BROADCAST(分片广播) — 广播触发对应集群中所有机器执行一次任务,同时系统自动传递分片参数,可根据分片参数开发分片任务测试1:运行3个执行器服务,注册列表排序143、220、116,每次会触发执行服务器(符合预期)。 测试2:获取并打印分片广播参数(ShardingUtil.getShardingVo()),得到对应的index和total值(符合预期)。 11、 阻塞策略:单机串行、丢弃后续调度、覆盖之前调度测试1:运行3个执行器服务(服务等待6s),设置调用时间5s/次,阻塞策略单机串行,服务每次在143执行,且等待后继续执行(符合预期)。 测试2:运行3个执行器服务(服务等待6s),设置调用时间5s/次,阻塞策略丢弃后续调度,间隔性出现调度失败(block strategy effect:Discard Later)(符合预期)。 测试3:运行3个执行器服务(服务等待6s),设置调用时间5s/次,阻塞策略覆盖之前调度,全部出现调度成功,执行失败(block strategy effect:Cover Early [job running,killed])(符合预期)。 12、使用建议1)阻塞策略针对是的每个执行器节点的执行状况的处理,不是执行器集群的执行状况,请在使用时特别注意; 2)普通服务建议设置第一个/最后一个路由模式(主备)或一致性hash,防止出现未做好幂等多次执行相同服务的状况; 3)需要集群分片方式加快执行,可以使用分片广播方式,根据index和total做好分片处理逻辑; 4)阻塞策略根据需要可以选择单机串行 / 丢弃后续调度; 5)其他路由策略状况下请做好任务的幂等处理再尝试配置,同时根据业务设置好任务间隔时间和处理数据量。 ⚠️线上问题实例 问题:发现两个服务器上毫秒级差别内执行相同单号的业务记录。 配置:路由策略 - 轮询, 任务时间 - 1分钟/次,阻塞策略 - 单机串行 查询对应时段的任务状况显示: 任务执行时间1分钟触发一次,两个节点交替触发,02:33:00 / 02:34:00 两次触发的任务分布在两台机器上执行,一次处理量667,另一次处理547,业务未做幂等处理,导致两次任务处理到相同数据;单机串行阻塞策略 02:35:00 / 02:36:00 两次任务推串行推迟执行,属于正常逻辑。 优化方案: 1、设置为路由策略为 第一个 / 最后一个 / 一致性hash,降低在多节点执行风险; 2、如果特别核心业务建议加入幂等处理逻辑; 3、限制每次服务处理数据量,保证设置的任务时间范围内能够执行完成。","categories":[{"name":"经验分享","slug":"经验分享","permalink":"https://github.com/weiecho/categories/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/"}],"tags":[{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"开源工具","slug":"开源工具","permalink":"https://github.com/weiecho/tags/%E5%BC%80%E6%BA%90%E5%B7%A5%E5%85%B7/"},{"name":"定时任务","slug":"定时任务","permalink":"https://github.com/weiecho/tags/%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1/"},{"name":"xxl-job","slug":"xxl-job","permalink":"https://github.com/weiecho/tags/xxl-job/"}]},{"title":"Jenkins集成SonarQube代码质量分析平台","slug":"stu_1118","date":"2020-09-01T09:02:25.000Z","updated":"2020-09-01T09:20:35.294Z","comments":true,"path":"2020/09/01/stu_1118/","link":"","permalink":"https://github.com/weiecho/2020/09/01/stu_1118/","excerpt":"","text":"SonarQube 是一个开源的代码质量分析平台,便于管理代码的质量,可检查出项目代码的漏洞和潜在的逻辑问题。同时,它提供了丰富的插件,支持多种语言的检测, 如 Java、Python、Groovy、C、C++等几十种编程语言的检测。 SonarQube主要的核心价值体现在如下几个方面:检查代码是否遵循编程标准:如命名规范,编写的规范等。 检查设计存在的潜在缺陷:SonarQube 通过插件 Findbugs、Checkstyle 等工具检测代码存在的缺陷。 检测代码的重复代码量:SonarQube 可 以展示项目中存在大量复制粘贴的代码。 检测代码中注释的程度:源码注释过多或者太少都不好,影响程序的可读可理解性。 检测代码中包、类之间的关系:分析类之间的关系是否合理,复杂度情况。 一个SonarQube服务器启动3个主要流程:Web服务器,供开发人员,管理人员浏览高质量快照并配置SonarQube实例 基于Elasticsearch的Search Server从UI返回搜索 计算引擎服务器负责处理代码分析报告并将其保存在SonarQube数据库中 一个SonarQube数据库存储:SonarQube实例的配置(安全性,插件设置等) 项目,视图等的质量快照 服务器上安装了多个SonarQube插件,可能包括语言,SCM,集成,身份验证和治理插件在构建/持续集成服务器上运行一个或多个SonarScanner来分析项目 具体搭建使用参考:SonarQube搭建","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://github.com/weiecho/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"开源工具","slug":"开源工具","permalink":"https://github.com/weiecho/tags/%E5%BC%80%E6%BA%90%E5%B7%A5%E5%85%B7/"},{"name":"流控降级","slug":"流控降级","permalink":"https://github.com/weiecho/tags/%E6%B5%81%E6%8E%A7%E9%99%8D%E7%BA%A7/"},{"name":"sentinel","slug":"sentinel","permalink":"https://github.com/weiecho/tags/sentinel/"}]},{"title":"lemon-echo 项目源码结构","slug":"doc_1140","date":"2020-08-28T08:24:16.000Z","updated":"2020-09-10T09:35:41.834Z","comments":true,"path":"2020/08/28/doc_1140/","link":"","permalink":"https://github.com/weiecho/2020/08/28/doc_1140/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 项目源码采用maven模块化切分,将所有功能划分为三大块:控制模块、组件模块、服务模块,通过三个大模块再细分具体大功能模块,通过pom控制核心组件的版本和功能,保障所有服务的功能规范统一。","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"lemon-echo 部署架构说明","slug":"doc_1127","date":"2020-08-18T10:27:35.000Z","updated":"2020-08-28T08:24:21.255Z","comments":true,"path":"2020/08/18/doc_1127/","link":"","permalink":"https://github.com/weiecho/2020/08/18/doc_1127/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 用户访问APP、WEB、H5页面通过LBS算法调用到最佳的nginx服务器,nginx通过规则转发调用到指定的服务或服务网关,gatway经过鉴权、风控等安全校验后通过consul注册中心LB路由到指定的业务服务,业务服务根据需要调用对应的数据支持端、RPC服务短信或第三方服务端,完成业务功能后返回对应的数据。 部署架构说明 整个部署架构分为入口访问组、核心服务组、基础支撑组和服务监控组。 1、LBS域名指向服务域名,开通https、防ddocs等安全性功能。 2、入口访问组包含nginx、potal web、activity web、gateway服务,nginx需要开通外网流量权限,gateway需打通与核心业务组网段调用,potal web和activity web为前端网页服务,可视情况与nginx服务同机器部署或单独部署。 3、核心服务组根据各服务压测和预估QPS状况,部署相应量级的服务节点,为保障服务高可用,每个服务至少部署两个节点。 4、基础支撑组需开放核心业务组网络相互访问,部署consul注册中心集群,consul集群请独立部署并至少部署3个server节点和2+个client节点,DB至少保证主从节点配置,rabbitmq集群使用镜像模式保障服务的高可用,redis根据服务需要主从、集群部署,其他支持服务根据需要部署相应套件。 5、服务监控组需开放核心业务组网络相互访问,zabbix、prometheus、zipkin server根据服务需要部署相应节点套件,ELK部署至少3个master节点和3个data节点,数据节点建议内存30G,master节点建议10G,聚合节点等根据需要配置,日志类索引根据需要设置n*3个Primaries(如无特殊需要Replicas设置为0),日志索引名称按天存储。日志收集采用filebeat -> kafka -> logstash -> elasticsearch套件,logstash路由pipeline简化配置和服务管理。","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"lemon-echo 规划架构说明","slug":"doc_1126","date":"2020-08-12T15:11:35.000Z","updated":"2020-08-28T08:24:54.986Z","comments":true,"path":"2020/08/12/doc_1126/","link":"","permalink":"https://github.com/weiecho/2020/08/12/doc_1126/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 lemon-echo架构考虑多设备、多应用场景,从应用入口区分了各类应用入口的控制和管理,在功能方面分为应用入口、服务网关、核心服务、公共模块、风控模块、运营管理后台、数据支持等模块。 规划架构说明 应用入口应用入口可以接受APP、WEB、小程序、A应用、B应用、外部应用等应用接入,利用服务的项目管理功能可以实现无限扩展的应用接入方式,从而达到类中台的服务架构体系。 服务网关服务网关主要考虑安全、流控、风控等风险因素,接入参数验证、身份验证、路由策略、流控策略、风控验证等安全模块,保障整体服务安全稳定运行。 核心服务核心服务为项目主要业务服务,目前规划分为聚合服务、用户服务、帐户服务、商品服务、订单服务、交易服务、对账服务、清算服务、消息服务、授权服务、营销服务、售后服务等。市场运营需求可以增加推广服务、广告服务,即时沟通类需求可以扩展IM服务,直播类需求可以扩展直播服务,打赏服务等。 公共模块公共模块作为业务的支持服务,主要包含授权服务、报警服务、消息服务、单号生成器、注册中心、配置中心、定时任务、分布式锁、分库分表模块,服务成熟后可逐步考虑接入生物识别、内容识别、数据服务等模块。 风控模块风控模块为服务安全等核心领域,包含安全认证、资质审查、用户分级、黑白名单、风险预警、风险处置、支付风险、信用风险、征信相关等,可以根据需要完善该模块内容保障整体服务等安全性。 运营管理后台运营管理后台为管理整个服务的入口,通过精确的权限管控分配用户是使用功能,对系统用户、帐户、订单、交易、对账、投诉等信息的查看和维护操作。 数据支持数据支持分为内部数据支持和三方支持,其中内部数据支持包含mysql、redis、rabbit mq、promethes、elk、innerdb等,三方支持包含短信服务、消息服务、OSS文件存储、支付通道、实名认证、生物检测等功能。","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"lemon-echo 概要说明","slug":"doc_1125","date":"2020-07-28T12:21:55.000Z","updated":"2020-07-28T12:21:55.684Z","comments":true,"path":"2020/07/28/doc_1125/","link":"","permalink":"https://github.com/weiecho/2020/07/28/doc_1125/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 lemon-echo微服务架构是基于springcloud的微服务框架设计体系,以人员、时效、成本、品质为基础设计思路,极度适用于小中型开发设计团队,可通过简单调整扩展支持中大型开发设计团队。框架设计过程中整合实际项目经验,利用接口化、消息队列、模块化、服务化、异步化等技术方案保障服务稳定性和可扩展性。 根据互联网产品多年经验分析,我们的产品无论从任何角度为切入点,最终都希望完成用户支付-服务的闭环思维,在本架构体系设计时期直接将用户、帐户、商品、订单、交易、消息作为功能架构的基础模块体系,从而结合实际项目体系完成整体微服务体系搭建,以协助团队快速集成完善的开发结构体系。 依托功能预代入模式的完善架构体系思想,后续功能开发仅需对相应业务逻辑进行部分调整、增加对应的服务模块(如IM、聊天室等),利用类似二次开发方式极大降低开发团队的技术壁垒,降低微服务开发及治理难度,结合代码快速生成器可以在10分钟内完成简单功能开发,非常快发迭代开发的技术团队,尤其适用于50人以下的技术开发团队。","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"lemon-echo HTTP状态码说明","slug":"doc_1124","date":"2020-07-27T14:18:43.000Z","updated":"2020-07-24T06:03:59.173Z","comments":true,"path":"2020/07/27/doc_1124/","link":"","permalink":"https://github.com/weiecho/2020/07/27/doc_1124/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 1、成功 2XX (Successful 2XX)1234567200 成功(OK)201 已创建(Created)202 已接受请求(Accepted)203 非权威性的信息(Non-Authoritative Information)204 无内容(No Content)205 重置内容(Reset Content)206 部分内容(Partial Content) 2、重定向 3XX (Redirection 3XX)12345678300 可选重定向(Multiple Choices)301 永久重定向(Moved Permanently)302 临时重定向(Found / Moved Temporarily)303 看其他(See Other)304 未修改(Not Modified)305 必须使用代理(Use Proxy)306 未使用(Unused)307 临时重定向(Temporary Redirect) 3、客户端错误 4XX (Client Error 4XX)123456789101112131415161718400 请求异常(Bad Request)401 无授权(Unauthorized)402 所需付款 (Payment Required)403 禁止访问(Forbidden)404 地址不存在 (Not Found)405 方法不允许 (Method Not Allowed)406 非可接受的(Not Acceptable)407 需要代理身份验证(Proxy Authentication Required)408 请求超时 (Request Timeout)409 冲突(Conflict)410 网页已经失效(Gone)411 所需长度(Length Required )412 先决条件失败(Precondition Failed)413 请求实体太大(Payload Too Large)414 请求URI太长(URI Too Long)415 不支持的媒体类型(Unsupported Media Type)416 不能满足所请求的范围(Requested Range Not Satisfiable)417 预期结果失败(Expectation Failed) 4、服务端错误 5XX(Server Error 5XX)123456500 内部服务器错误(Internal Server Error)501 未执行(Not Implemented)502 坏网关 (Bad Gateway)503 服务不可用(Service Unavailable)504 网关超时(Gateway Timeout)505 不支持的HTTP版本(HTTP Version Not Supported )","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"lemon-echo异常码规则说明","slug":"doc_1123","date":"2020-07-25T12:32:11.000Z","updated":"2020-07-24T06:00:30.510Z","comments":true,"path":"2020/07/25/doc_1123/","link":"","permalink":"https://github.com/weiecho/2020/07/25/doc_1123/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 1、HTTP状态码12345200 成功(OK)400 请求异常(Bad Request)401 未登录授权403 无访问权限 500 内部服务器错误(Internal Server Error) 2、业务错误码(400/500)1234567891011201 参数异常(Incorrect Argument)11400 操作失败(Normal Error)11401 未登录授权(Unauthorized)11403 无访问权限(No Permission)11405 [服务器]运行时异常(Runtime Error)11406 [服务器]空值异常(NullPointer Error)11407 [服务器]IO异常(IO Error)11408 [服务器]数组越界异常(Array index out of bounds Error)11409 [服务器]网络异常(Socket Error)11429 服务器繁忙,请稍后再试(Too Many Requests) 3、其他业务服务12345678115XX 网关服务异常116XX 授权服务异常12XXX 用户服务异常13XXX 消息服务异常14XXX 交易服务异常15XXX 帐户服务异常16XXX 文件服务异常17XXX 售后服务异常","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"lemon-echo业务状态码说明","slug":"doc_1122","date":"2020-07-23T05:54:06.000Z","updated":"2020-07-24T05:59:11.387Z","comments":true,"path":"2020/07/23/doc_1122/","link":"","permalink":"https://github.com/weiecho/2020/07/23/doc_1122/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 1、单状态模式(0~9)12345678-1 全部0 待处理1 处理中5 已取消6 已关闭9 已完成其他为中间状态 2、多状态模式(0~9)12345600 待处理10 处理中50 已取消(自动) 51 用户取消 52 商家取消60 已关闭90 已完成(自动) 91 用户完成其他为中间状态","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"lemon-echo文件存储OSS样式","slug":"doc_1121","date":"2020-07-18T08:54:13.000Z","updated":"2020-07-24T05:56:34.587Z","comments":true,"path":"2020/07/18/doc_1121/","link":"","permalink":"https://github.com/weiecho/2020/07/18/doc_1121/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 默认使用:域名/sample.jpg?x-oss-process=style/stylename 1、正方形图square-mini 强制 高 120 宽 120 代码: image/auto-orient,1/resize,m_fixed,w_120,h_120/quality,q_90 square-small 强制 高 360 宽 360 代码: image/auto-orient,1/resize,m_fixed,w_360,h_360/quality,q_90 square-medium 强制 高 750 宽 750 代码: image/auto-orient,1/resize,m_fixed,w_750,h_750/quality,q_90 2、长方形图rectangle-mini 强制 宽 120 高自适应 代码: image/auto-orient,1/resize,m_lfit,w_120/quality,q_90 rectangle-small 强制 宽 360 高自适应 代码: image/auto-orient,1/resize,m_lfit,w_360/quality,q_90 rectangle-medium 强制 宽 750 高自适应 代码: image/auto-orient,1/resize,m_lfit,w_750/quality,q_90","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"lemon-echo编号规则说明","slug":"doc_1120","date":"2020-07-16T12:24:23.000Z","updated":"2020-07-15T05:59:21.511Z","comments":true,"path":"2020/07/16/doc_1120/","link":"","permalink":"https://github.com/weiecho/2020/07/16/doc_1120/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 1、用户ID规则:n位/预期号池量90亿+n序号+2随机 n序列号:1000000001~99999999992随机:00~99 2、用户账号规则:8-9位/预期号池量80亿/去靓号4位同号-4位连号8~10伪随机 8~10伪随机:100000000~9999999999 3、用户靓号规则:6-8位/预期号池量5000w/6位号-4位同号-4位连号6-8指定号 6-8指定号:100000~99999999 4、订单号规则:15位/预期号池量100亿/可按年重置1年份+2业务类型+10序号+2随机 1年份:n % 10 + 1 (2020年元年)2类型:A类单 11 B类单 1210序列号:0000000001~99999999992随机:00~99 5、交易单号规则:16位/预期号池量10000亿/可按年重置1年份+2业务类型+12序号+1随机 1年份:n % 10 + 1 (2020年元年)2类型:充值 01 支付 02 退款 05 提现 0912序列号:000000000001~9999999999991随机:0~9 6、SerialID规则:BIGINT/Serial控制/业务ID1~>无限量 7、自增ID规则:BIGINT/设置自增1~>无限量","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"lemon-echo核心功能说明","slug":"doc_1119","date":"2020-07-15T03:31:47.000Z","updated":"2020-07-15T03:30:55.940Z","comments":true,"path":"2020/07/15/doc_1119/","link":"","permalink":"https://github.com/weiecho/2020/07/15/doc_1119/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 1、服务采用rest + json返回数据,正常数据直接返回数据对象,提示码/异常统一封装ResultError返回,正常状况下controller只需返回正常数据对象就可以,service业务异常抛出由框架DefaultGlobalExceptionHandler统一处理。 123456789101112131415161718192021222324252627带结果返回实例@GetMapping(\"/menus\")public List<Menu> getMenus(Long projectId) { List<Menu> list = menuService.getMenus(projectId); return list;}无结果返回实例:@PostMapping(\"/code\")public void mobileCode(AuthType authType, String mobile) { mobileCodeService.sendMobileCode(authType, mobile);}业务代码实例:public void sendMobileCode(final AuthType authType, final Long userId) { String mobile = userAuthService.getMobileByUserId(userId); if (StringUtils.isEmpty(mobile)) { throw new BizServiceException(F11615); } this.sendMobileCode(authType, mobile);}异常码返回Json(http状态码大于300):{ code: 11615, msg: \"未绑定手机号码\"} 2、服务功能配置采用预配置方式,需继承基础功能包内的配置类并注解@Configuration 1234@Configurationpublic class MybatisConfig extends MybatisConfigurator {} 3、服务引入auth-rpc进行权限校验,在WebMvcConfig配置相应的权限拦截器即可实现,需要控制权限的接口仅需加上注解@RequestPermissions({xxx}) 1234567891011121314151617181920212223配置权限拦截:@Configurationpublic class WebMvcConfig extends WebMvcConfigurator { @Bean public PermissionInterceptor permissionInterceptor() { return new PermissionInterceptor(); } /**加入拦截器 */ @Override public void addInterceptors(InterceptorRegistry registry) { super.addInterceptors(registry); registry.addInterceptor(permissionInterceptor()) .addPathPatterns(\"/portal/**\"); }}接口权限配置@RequestPermissions({\"user_freeze\"})@PostMapping(\"/portal/user/freeze\")public void freeze(Long userId, FreezeTime freezeTime, String reason) { userFreezeService.freeze(userId, freezeTime, reason);} 4、rabbit消息队列在实际开发中,绝大部分情况下仅需使用topic模式和延时模式,框架封装并简化了rabbit的topic模式和延时模式功能,生产和消费时的方法采用相同的方法,降低多种方法的配置和学习成本。 12345678910111213141516171819202122消费端声明消息队列@Configurationpublic class RabbitConfig extends RabbitConfigurator { @Override public Collection<QueueBinding> getQueueBinding() { List<QueueBinding> queueBindings = new ArrayList<>(); queueBindings.add(new QueueBinding(USER_UNFREEZE, \"user.topic\", \"user.unfreeze\")); return queueBindings; }}消费端消费队列消息@RabbitListener(queues = {USER_UNFREEZE})public void unfreezeUser(Long userId) { userAuthService.unfreeze(userId);}生产端生产队列消息public void unfreezeUser(Long userId) { rabbitTopicSender.send(USER_UNFREEZE, userId);} 注: RoutingKey命名规则:生产服务名称.业务功能如:USER_UNFREEZE = “user.unfreeze”; Queue命名规则:消费服务名称_RoutingKey如:USER_UNFREEZE = “auth_user.unfreeze”; 5、分布式锁采用redis特性作为锁凭证中心,封装了@DistributionLock和@LockKey降低对系统业务的侵入性,同时利用LockKey参数细分控制每个锁元素,增大服务的吞吐量。 12345帐户入账时锁定对应帐户类型+用户ID@DistributionLockpublic void increase(@LockKey AccountType accountType, @LockKey Long userId, AccountTradePo accountTrade) {} 6、利用@cache进行数据缓存,可选择使用本地caffeine缓存器和远程redis缓存器,根据业务灵活使用缓存可以保障业务对高效稳定。 123456789@Cacheable(value=\"userCaches\", key=\"'user_' + #userId\", cacheManager=\"caffeineCacheManager\")public UserPo getUserInfoById(Long userId) {return userPo;}@Cacheable(value=\"userCaches\", key=\"'user_' + #userId\", cacheManager=\"redisCacheManager\")public UserPo getUserInfoById(Long userId) {return userPo;} 7、定时任务采用xxl-job分布式调度中心,利用统一调度策略(单点执行/分片执行),完成定时业务需求。 12345@XxlJob(\"pendUnFreezeUserHandler\")public ReturnT<String> pendUnFreezeUserHandler(String param) throws Exception { XxlJobLogger.log(\"job exec unfreeze user.\"); return ReturnT.SUCCESS;} 8、项目pom引入auth-rpc后,在WebMvcConfig使用拦截器设置需要的权限规则 1234567891011@Beanpublic PermissionInterceptor permissionInterceptor() { return new PermissionInterceptor();}/**加入拦截器 */@Overridepublic void addInterceptors(InterceptorRegistry registry) { super.addInterceptors(registry); registry.addInterceptor(permissionInterceptor()).addPathPatterns(\"/portal/**\");} 9、接口请求时经过授权检查会解析x-auth-token,在请求的header参数增加用户ID参数x-user-id,业务参数使用时可以直接获取改值。 1234@PostMapping(\"/api/withdraw/apply\")public void applyWithdraw(@RequestHeader(value = AUTH_USER_ID) Long userId, Long bankCardId, BigDecimal coins) {} 10、接口请求数据均需要携带header参数: 12345678910AUTH_SCOPE = \"x-auth-scope\"; //授权作用域AUTH_TOKEN = \"x-auth-token\"; //访问授权码CLIENT_NAME = \"x-client-name\"; //客户端名称CLIENT_IMEI = \"x-client-imei\"; //客户端设备号CLIENT_TYPE = \"x-client-type\"; //客户端类型CLIENT_VERSION = \"x-client-version\"; //客户端版本APP_VERSION = \"x-app-version\"; //客户端应用版本APP_CHANNEL = \"x-app-channel\"; //客户端应用渠道BUNDLE_ID = \"x-bundle-id\"; //app包名(IOS: bundle id, 安卓: package name)TIMESTAMP = \"x-timestamp\"; //时间戳","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"Maven项目本地仓库引用强制刷新","slug":"exp_1116","date":"2020-07-13T08:39:26.000Z","updated":"2020-07-14T01:41:25.430Z","comments":true,"path":"2020/07/13/exp_1116/","link":"","permalink":"https://github.com/weiecho/2020/07/13/exp_1116/","excerpt":"","text":"很多时候我们会遇到realse版本的包发布到maven仓库使用后,出现了一点问题需要修复,但是又想让大家静默升级或者遇到一些包之间到引用混乱,需要重拉整理仓库引用我们可以使用mvn dependency:purge-local-repository命令来进行全局刷新但很多时候我们需要的只是个别包的强刷,下面简单说明下个别包的强刷 1)点击右侧Maven Projects的 M图标(Execute Maven Goal),填入命令点击执行即可强制刷新引用命令:dependency:purge-local-repository -Dinclude=”com.ctrip.framework.apollo:apollo-client” -U idea:idea 2)检查项目引用apollo-client是否更新为版本 1.4.1 3)如果不是全局查找一下是否有项目强制设置版本为1.4.0,如果存在设置去除版本号,再刷新检查引用","categories":[{"name":"经验分享","slug":"经验分享","permalink":"https://github.com/weiecho/categories/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/"}],"tags":[{"name":"spring","slug":"spring","permalink":"https://github.com/weiecho/tags/spring/"},{"name":"idea","slug":"idea","permalink":"https://github.com/weiecho/tags/idea/"},{"name":"maven","slug":"maven","permalink":"https://github.com/weiecho/tags/maven/"}]},{"title":"lemon-echo项目数据库约定","slug":"doc_1118","date":"2020-07-11T12:13:06.000Z","updated":"2020-07-10T02:41:36.301Z","comments":true,"path":"2020/07/11/doc_1118/","link":"","permalink":"https://github.com/weiecho/2020/07/11/doc_1118/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 1、数据库全部使用小写字母,下划线分割,包括库名,表名,字段名,索引名 2、不能使用数据库保留字,比如:key,desc,delete,order等 3、索引列不能存储null,可以为空串”” 4、使用innodb存储引擎,使用utf8mb4 5、每张表都要有一个整型类型自增长主键id,不允许使用联合主键 6、轻约束设计,不建议表之间设计外键,以提升性能和避免设计的复杂性 7、冗余设计(反范式化),避免后续大表关联查询,可考虑冗余部分字段 8、普通索引命名idx_(前缀) + 列名,唯一索引命名udx_(前缀) + 列名 9、避免在索引列进行函数运算、!=/<>、not in等的使用(索引不能被使用) 10、varchar(M) M代表的意思是存储的最大字符数,不是字节数。M的值如果没有特别需要,建议不超过255(超过后存储方式会变化) 11、不要使用blob,text,longblob,longtext等超长的数据类型。对于要存储log日志的需求,建议程序端使用外部文件存储的方式 12、线上库truncate table xx、drop table xx操作需要邮件提前通知各部门,以防误删","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"lemon-echo项目代码规范","slug":"doc_1117","date":"2020-07-11T08:23:46.000Z","updated":"2020-07-10T02:38:19.860Z","comments":true,"path":"2020/07/11/doc_1117/","link":"","permalink":"https://github.com/weiecho/2020/07/11/doc_1117/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 1、if else语句不超过三层,代码嵌套层次达3层以上时,一般人理解起来都会困难,尽量避免用到else,可以使用if(xx) return替代。 2、每个if while for等语句,都不要省略大括号{}。 3、公用逻辑抽取成公用方法,并加以注释说明。 4、在实体字段、类、方法使用Java Doc注释方式 /** **/,方法注释时除非特殊说明不强制要求对方法每个参数进行注释,注释宜少而精,不宜多而滥,更不能误导。 5、在代码中加入 //TODO: ,IDE会提示让你知道你还有什么事没有做,如已经处理过的重写方法需要将自动生成的TODO注释删除。 6、如果某个方法是故意留空不写,需要注释说明 123if (!exists(order)) { //nothing to do} 7、变量的声明,初始化和被使用尽量放到一起。 8、能用局部变量的,不要使用实例变量,能用实例变量的,不要使用类变量。变量的生存期越短,以为着它被误用的机会越小,同一时刻要关注的变量的状态越少。 9、尽量不要用参数来带回方法运算结果,而是使用return返回。 10、尽量使用HashMap、ArrayList、StringBuilder,除非线程安全需要,否则不推荐使用Hashtable、Vector、StringBuffer,后三者由于使用同步机制而导致了性能开销。 11、字符串变量和字符串常量equals的时候将字符串常量写在前面 “abc”.equals(obj),这么做可以避免空指针异常。 12、把一个基本数据类型转为字符串,基本数据类型.toString()是最快的方式、String.valueOf(数据)次之、数据+””最慢。 13、尽量不捕获Java类库中定义的继承自RuntimeException的运行时异常类,而是使用全局处理方法统一记录日志并处理。 14、打印日志时候,使用log而不是System.out.println(),注意日志级别 info/warn/error。 15、不要想着等完成了功能,再来优化代码的格式和结构,等真的把功能完成,很少有人会再愿意回头调整代码。","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"lemon-echo项目命名规范","slug":"doc_1116","date":"2020-07-10T00:30:46.000Z","updated":"2020-07-10T02:32:14.386Z","comments":true,"path":"2020/07/10/doc_1116/","link":"","permalink":"https://github.com/weiecho/2020/07/10/doc_1116/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 1、统一:对于同一个概念,在程序中用同一种表示方法,比如对于供应商,既可以用supplier,也可以用provider,但是我们只能选定一个使用。 2、达意:标识符能准确的表达出它所代表的意义,比如: newSupplier, OrderPaymentService等;而 supplier1, service2,idtts等则不是好的命名方式。 3、简洁:在统一和达意的前提下,用尽量少的标识符。如果不能达意,宁愿不要简洁。 4、驼峰法则:Java中除了包名,静态常量等特殊情况,大部分情况下标识符使用驼峰法则,即单词之间不使用特殊符号分割,而是通过首字母大写来分割。比如: supplierName, addNewContract,而不是 supplier_name, add_new_contract。 5、英文 vs 拼音:尽量使用通俗易懂的英文单词,如果不会可以向队友求助,避免拼音与英文混用。 6、包名 & 类名:包名使用小写字母,如 com.xxx.service,类名要首字母大写,比如 SupplierService。","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"lemon-echo模块划分原则","slug":"doc_1115","date":"2020-07-09T02:55:12.000Z","updated":"2020-07-09T02:54:35.902Z","comments":true,"path":"2020/07/09/doc_1115/","link":"","permalink":"https://github.com/weiecho/2020/07/09/doc_1115/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 1、项目业务模块划分原则:高内聚、低耦合、可复用、可扩展、可维护。 2、根据具体的业务子类型、操作类型等再分为子业务模块,参考业务部门、业务类型、服务对象等依据分为各大业务模块。 3、新增需求若与原业务模块关联不大,或较少调用关系,则可定义为新的子业务模块。 4、让程序模块单元的职责单一,可以使你在编写这段程序时关注更少的东西,从而降低难度,减少出错。 5、先业务后技术,先逻辑后物理,服务的稳定性优先,通过拆分解耦 6、尽量避免事务,适当采用异步解耦,适当使用缓存","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"lemon-echo微服务架构说明","slug":"doc_1114","date":"2020-07-07T03:16:35.000Z","updated":"2020-07-09T02:53:24.144Z","comments":true,"path":"2020/07/07/doc_1114/","link":"","permalink":"https://github.com/weiecho/2020/07/07/doc_1114/","excerpt":"","text":"高效稳定 · 简洁易用 · 灵活扩展项目地址:lemon-echo微服务架构 weiecho微服务架构是基于springcloud + consul的微服务框架设计体系,以人员、时效、成本、品质为基础设计思路,极度适用于小中型开发设计团队,可通过简单调整扩展支持中大型开发设计团队。框架设计过程中整合实际项目经验,利用接口化、消息队列、模块化、服务化、异步化等技术方案保障服务稳定性和可扩展性。 根据互联网产品多年经验分析,我们的产品无论从任何角度为切入点,最终都希望完成用户支付-服务的闭环思维,在weiecho的架构体系设计时期直接将用户、帐户、商品、订单、交易、消息作为功能架构的基础模块体系,从而结合实际项目体系完成整体微服务体系搭建,以协助团队快速集成完善的开发结构体系。 依托功能预代入模式的完善架构体系思想,后续功能开发仅需对相应业务逻辑进行部分调整、增加对应的服务模块(如IM、聊天室等),利用类似二次开发方式极大降低开发团队的技术壁垒,降低微服务开发及治理难度,结合代码快速生成器可以在10分钟内完成简单功能开发,非常快发迭代开发的技术团队,尤其适用于50人以下的技术开发团队。 规划架构说明weiecho架构考虑多设备、多应用场景,从应用入口区分了各类应用入口的控制和管理,在功能方面分为应用入口、服务网关、核心服务、公共模块、风控模块、运营管理后台、数据支持等模块。 应用入口应用入口可以接受APP、WEB、小程序、A应用、B应用、外部应用等应用接入,利用服务的项目管理功能可以实现无限扩展的应用接入方式,从而达到类中台的服务架构体系。 服务网关服务网关主要考虑安全、流控、风控等风险因素,接入参数验证、身份验证、路由策略、流控策略、风控验证等安全模块,保障整体服务安全稳定运行。 核心服务核心服务为项目主要业务服务,目前规划分为聚合服务、用户服务、帐户服务、商品服务、订单服务、交易服务、对账服务、清算服务、消息服务、授权服务、营销服务、售后服务等。市场运营需求可以增加推广服务、广告服务,即时沟通类需求可以扩展IM服务,直播类需求可以扩展直播服务,打赏服务等。 公共模块公共模块作为业务的支持服务,主要包含授权服务、报警服务、消息服务、单号生成器、注册中心、配置中心、定时任务、分布式锁、分库分表模块,服务成熟后可逐步考虑接入生物识别、内容识别、数据服务等模块。 风控模块风控模块为服务安全等核心领域,包含安全认证、资质审查、用户分级、黑白名单、风险预警、风险处置、支付风险、信用风险、征信相关等,可以根据需要完善该模块内容保障整体服务等安全性。 运营管理后台运营管理后台为管理整个服务的入口,通过精确的权限管控分配用户是使用功能,对系统用户、帐户、订单、交易、对账、投诉等信息的查看和维护操作。 数据支持数据支持分为内部数据支持和三方支持,其中内部数据支持包含mysql、redis、rabbit mq、promethes、elk、innerdb等,三方支持包含短信服务、消息服务、OSS文件存储、支付通道、实名认证、生物检测等功能。 部署架构说明用户访问APP、WEB、H5页面通过LBS算法调用到最佳的nginx服务器,nginx通过规则转发调用到指定的服务或服务网关,gatway经过鉴权、风控等安全校验后通过consul注册中心LB路由到指定的业务服务,业务服务根据需要调用对应的数据支持端、RPC服务短信或第三方服务端,完成业务功能后返回对应的数据。 整个部署架构分为入口访问组、核心服务组、基础支撑组和服务监控组。 1、LBS域名指向服务域名,开通https、防ddocs等安全性功能。 2、入口访问组包含nginx、potal web、activity web、gateway服务,nginx需要开通外网流量权限,gateway需打通与核心业务组网段调用,potal web和activity web为前端网页服务,可视情况与nginx服务同机器部署或单独部署。 3、核心服务组根据各服务压测和预估QPS状况,部署相应量级的服务节点,为保障服务高可用,每个服务至少部署两个节点。 4、基础支撑组需开放核心业务组网络相互访问,部署consul注册中心集群,consul集群请独立部署并至少部署3个server节点和2+个client节点,DB至少保证主从节点配置,rabbitmq集群使用镜像模式保障服务的高可用,redis根据服务需要主从、集群部署,其他支持服务根据需要部署相应套件。 服务监控组需开放核心业务组网络相互访问,zabbix、prometheus、zipkin server根据服务需要部署相应节点套件,ELK部署至少3个master节点和3个data节点,数据节点建议内存30G,master节点建议10G,聚合节点等根据需要配置,日志类索引根据需要设置n*3个Primaries(如无特殊需要Replicas设置为0),日志索引名称按天存储。日志收集采用filebeat -> kafka -> logstash -> elasticsearch套件,logstash路由pipeline简化配置和服务管理。 控制中心模块服务网关 gateway服务网关基于springcloud原生gateway实现,为整个微服务架构提供简单、有效和统一的API路由管理方式,结合服务的授权体系、风控体系、sentinel流控体系、swagger接口文档等方便统一的管理微服务体系,同时保障服务的安全稳定运行。 流控后台 sentinel-dashboardsentinel流控后台是面向微服务的轻量级流量控制框架,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 任务调度 xxl-job-adminxxl-job任务调度中心是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。 链路追踪 zipkinzipkin链路追踪基于 Google Dapper 实现,用来收集各个服务器上请求链路的跟踪数据,并通过提供的 REST API 接口来辅助查询跟踪数据以实现对分布式系统的监控程序,从而及时发现系统中的存在的风险性问题。 公共组建模块公共配置 configurator公共配置模块整理和优化了服务的常用配置,采用配置但不启用的方式进行标准化处理,服务仅需继承相应类并加上注解@Configuration就可以启用功能。 公共资源 framework公共资源模块聚合类一些常用但公共处理类,增强服务语法的统一性和功能的准确性,减少大量重复造轮子的现象。 序列号组件 serialno序列号生成组件能够自动产生指定功能的递增序列号,采用服务独立自主管理序列号的方式,降低使用独立序列号服务的耦合性,采用redis作为预生成序列号池缓存区,加速服务的ID获取的处理速度。 消息组件封装 rabbit-mq消息组件封装默认封装的是rabbit的topic模式,结合延迟插件默认生成普通topic交换机和延迟队列交换机,在生产端调用发送消息是是否为延迟消息,消费配置queue时选择是否为延迟队列。一般情况下topic模式+延迟队列能够完全满足服务的各种消息需求。 分布式锁组件 distribution-lock分布式锁组件提供了分布式服务锁的功能,采用redis作为锁的计算核心,可以直接在方法上注解声明锁,同时采用注解方法参数作为降低锁粒度,从而更加灵活完善的支撑业务功能。 分库分表组件 sharding-db分库分表组件封装了sharding-jdbc作为功能内核,调整优化了配置方式和支持类型,可在大量不改变配置文件的状况扩展出单库数据源、主从数据源、分库数据源三种配置模式,极大的方便服务升级改造。 流控降级组件 sentinel-client流控降级组件封装了sentinel作为功能内核,调整优化了分布式配置存取、实时监控数据持久存储和流控熔断异常处理逻辑,可以实时查看服务状况、动态调整服务的熔断或流控阈值,结合流控熔断监控报警实时保障服务的安全稳定。 标准服务结构weiecho标准服务包含xxx-app(服务启动入口)、xxx-core(业务功能核心)、xxx-enum(服务全局枚举)、xxx-job(定时任务包)、xxx-rpc(rpc服务接口SDK)模块,考虑初期业务量、维护人员、服务维护难度及大部分微服务功能等状况,标准服务结构采用单服务聚合部署方式,降低开发维护难度,加速服务业务功能迭代开发上线。 本框架为保障服务接口的安全及一致性,利用强约束的方式保障所有问题暴露在上线部署前,约定服务提供方编写远程调用接口SDK提供给调用方。 模块继承规则: 1、xxx-app可引入xxx-core、xxx-job、xxx-rpc模块; 2、xxx-core可引入xxx-enum模块,支撑业务核心功能模块,可服务业务量状况拆分出event(MQ事件)模块走独立服务入口; 3、xxx-job根据需要使用xxx-app服务入口或独立服务走任务服务入口; 4、xxx-rpc可引入xxx-enum模块,也可以根据需要使用xxx-app服务入口或独立服务走任务服务入口。 服务启动入口 xxx-appxxxApplication.java为服务启动入口类,主要包含springboot服务启动main方法和部分启动注解; cn.echo.xxx.config为服务配置包,主要包含服务初始化各项配置类,如:database、redis、cache、mq、mvc、job等配置; cn.echo.xxx.controller为接口控制包,包含api(业务接口)、portal(后台接口)、rpc(rpc接口)控制实现类,其中rpc为继承xxx-rpc模块等实现类; cn.echo.xxx.execption为服务异常处理包,默认包含GlobalExceptionHandler继承实现全局异常处理类cn.echo.framework.response.DefaultGlobalExceptionHandler。 业务功能核心 xxx-corecn.echo.xxx.core.dao为数据处理包,主要包含mybatis调用数据源接口类; cn.echo.xxx.core.entity为数据实体包,主要包含数据库表对应字段实体类; cn.echo.xxx.core.pojo为业务实体包,主要为业务上下文封装需要的相关实体类; cn.echo.xxx.core.event为MQ事件包,主要包含constant(常量)、receiver(接收处理)、sender(发送处理),其中constant主要包含queue、routing key常量定义; cn.echo.xxx.core.service为业务逻辑接口包,主要定义业务逻辑功能接口,impl为逻辑接口的实现类。 服务全局枚举 xxx-enumcn.echo.xxx.em.enums为全局枚举包,主要配合业务需要定义各类枚举; cn.echo.xxx.em.response为全局服务响应码包,主要特殊业务状况下返回的信息提示码(警告、异常等),此异常码在服务创建时统一分配前缀,各服务维护自己的异常码,异常码类继承自框架类cn.echo.framework.response.ResultCode。 定时任务包 xxx-jobcn.echo.xxx.job为定时任务实现包,利用xxljob实现任务调度工作,根据最新2.2.0版本实现,在方法体注解@XxlJob(“xxxHandler”)并按照官方语法即可完成任务开发,结合后台配置规则实现动态任务调度管理。 远程调用接口SDK xxx-rpccn.echo.xxx.rpc.client远程调用SDK接口包,用于定义FeignClient提供给调用方的接口; cn.echo.xxx.rpc.dto远程调用SDK接口实体包,主要为SDK接口上下文封装需要的相关实体类。","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"架构","slug":"架构","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84/"},{"name":"lemon-echo","slug":"lemon-echo","permalink":"https://github.com/weiecho/tags/lemon-echo/"}]},{"title":"Sentinel流控降级原则","slug":"stu_1117","date":"2020-07-02T06:06:55.000Z","updated":"2020-07-03T06:10:14.732Z","comments":true,"path":"2020/07/02/stu_1117/","link":"","permalink":"https://github.com/weiecho/2020/07/02/stu_1117/","excerpt":"","text":"项目地址:sentinel流控防护 基本原则 Sentinel 是围绕着资源来工作的。 编码时,只需要关心如何定义资源,即哪些方法/代码块需要保护,而不需要关注如何保护这个资源。 通过添加规则来保护资源,规则添加即时生效。 规则配置原则 按照应用处理能力进行流控: 按服务提供方流控原则 削峰填谷原则 冷启动原则 联动控制原则 强依赖隔离原则 弱依赖降级原则 系统保护原则,详情请参见[系统保护篇] 弱依赖降级当若依赖的第三方应用出错不会影响而整体流程,则称之为弱依赖。对于弱依赖不稳定时,需要配置降级原则来保护系统稳定性。 在实际业务中,应用通常会调用依赖方(远程服务、数据库、第三方 API 等)来完成服务。例如,支付的时需要远程调用银联提供的 API。然而依赖方的稳定性是不能保证的。若依赖方出现不稳定的情况,则请求和调用依赖方的方法的的响应时间变长,线程产生堆积,最终可能耗尽自身的线程数,导致应用本身不可用。 在复杂链路中,若某一环不稳定,就可能会层层渲染,最终导致整个链路都不可用。 针对以上情况,可以使用对依赖方配置降级原则来保证系统稳定性。 ###强依赖隔离 若依赖的第三方应用或组件,或者应用自身的内部方法出错会影响而整体流程,则称之为强依赖。对于强依赖,需要配置隔离原则来保护系统稳定性。 当强依赖出现不稳定的时候,可以通过配置并发线程数隔离原则来限制不稳定的强依赖并发数,隔离强依赖。配置并发线程数隔离原则后,无需再进行线程池隔离,sentinel 会控制资源的线程数。当请求数超过阈值时,sentinel 将拒绝多余的请求,直到堆积的线程处理完成,以此来达到信号量隔离的效果。 线程数目超出时,设置 快速失败 能够有效地防止自己被慢调用所影响。 系统防护系统防护即从整体维度对应用入口流量进行控制,结合应用的 Load、总体平均 RT、入口 QPS 和线程数等几个维度的监控指标,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。 一般性系统自适应保护的思路是根据硬指标即系统的负载来做系统过载保护。即当系统负载高于某个阈值,就禁止或者减少流量的进入;若负载恢复,则恢复流量的进入。这样会造成两个不可避免的问题: 若根据负载的情况来调节流量的通过率,则会产生延迟。若当前通过率的调整会导致负载增大,那么至少要过 1 秒之后才能被观测到;同理,若当前通过率调整会使负载降低,也需要 1 秒之后才能继续调整。这种方法会浪费系统的处理能力。导致我们看到的负载曲线产生锯齿。 通过率恢复慢。在下游应用不可靠,应用响应时间很长,从而导致负载很高的场景中,若下游应用恢复时,应用响应时间也会随之减短,此时通过率理应会大幅度增大。但由于此时负载仍然很高,所以通过率的恢复慢。 为解决上述问题,sentinel在系统自适应保护的做法是:用每分钟的负载作为启动控制流量,使用请求的响应时间以及当前系统正在处理的请求速率来决定通过的流量。旨在在系统不被拖垮的情况下,提高系统的吞吐率。","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://github.com/weiecho/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"开源工具","slug":"开源工具","permalink":"https://github.com/weiecho/tags/%E5%BC%80%E6%BA%90%E5%B7%A5%E5%85%B7/"},{"name":"流控降级","slug":"流控降级","permalink":"https://github.com/weiecho/tags/%E6%B5%81%E6%8E%A7%E9%99%8D%E7%BA%A7/"},{"name":"sentinel","slug":"sentinel","permalink":"https://github.com/weiecho/tags/sentinel/"}]},{"title":"Sentinel系统防护","slug":"stu_1116","date":"2020-06-20T02:23:41.000Z","updated":"2020-07-03T06:06:06.058Z","comments":true,"path":"2020/06/20/stu_1116/","link":"","permalink":"https://github.com/weiecho/2020/06/20/stu_1116/","excerpt":"","text":"系统防护即从整体维度对应用入口流量进行控制,结合应用的 Load、总体平均 RT、入口 QPS 和线程数等几个维度的监控指标,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。 项目地址:sentinel流控防护 背景信息长期以来,系统自适应保护的思路是根据硬指标即系统的负载来做系统过载保护。即当系统负载高于某个阈值,就禁止或者减少流量的进入;若负载恢复,则恢复流量的进入。这样会造成两个不可避免的问题: 若根据负载的情况来调节流量的通过率,则会产生延迟。若当前通过率的调整会导致负载增大,那么至少要过 1 秒之后才能被观测到;同理,若当前通过率调整会使负载降低,也需要 1 秒之后才能继续调整。这种方法会浪费系统的处理能力。导致我们看到的负载曲线产生锯齿。 通过率恢复慢。在下游应用不可靠,应用响应时间很长,从而导致负载很高的场景中,若下游应用恢复时,应用响应时间也会随之减短,此时通过率理应会大幅度增大。但由于此时负载仍然很高,所以通过率的恢复慢。 为解决上述问题,sentinel 应用流控降级在系统自适应保护的做法是:用每分钟的负载作为启动控制流量,使用请求的响应时间以及当前系统正在处理的请求速率来决定通过的流量。旨在在系统不被拖垮的情况下,提高系统的吞吐率。 功能原理我们把系统处理请求的过程想象为一个水管,到来的请求是往这个水管灌水,当系统处理顺畅的时候,请求不需要排队,直接从水管中穿过,这个请求的RT是最短的;反之,当请求堆积的时候,那么处理请求的时间则会变为:排队时间 + 最短处理时间。 功能原理 若用 T 来表示水管内部的水量,用 RT 来表示请求的处理时间,用 P 来表示进来的请求数,那么一个请求从进入水管道到从水管出来,这个水管会存在 P * RT 个请求。即当 T ≈ QPS * Avg(RT) 的时候,可以认为系统的处理能力和允许进入的请求个数达到了平衡,系统的负载不会继续增加。当入口的流量是水管出来的流量的最大的值的时候,水管的处理能力达到最大利用。 系统规则系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),例如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。系统规则支持四种阈值类型: Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值且系统当前的并发线程数超过系统容量时才会触发系统保护。 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护。 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://github.com/weiecho/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"开源工具","slug":"开源工具","permalink":"https://github.com/weiecho/tags/%E5%BC%80%E6%BA%90%E5%B7%A5%E5%85%B7/"},{"name":"流控降级","slug":"流控降级","permalink":"https://github.com/weiecho/tags/%E6%B5%81%E6%8E%A7%E9%99%8D%E7%BA%A7/"},{"name":"sentinel","slug":"sentinel","permalink":"https://github.com/weiecho/tags/sentinel/"}]},{"title":"shardingsphere不支持LocalDateTime/LocalDate","slug":"exp_1117","date":"2020-06-17T07:56:39.000Z","updated":"2020-07-13T08:40:31.743Z","comments":true,"path":"2020/06/17/exp_1117/","link":"","permalink":"https://github.com/weiecho/2020/06/17/exp_1117/","excerpt":"","text":"12345678shardingsphere默认使用等jdk版本是1.7,所以并没有支持jdk1.8+的LocalDateTime等特性我已经在fork上扩展了这个特性,并将JDK的功能升级到jdk1.8。主要验证了支持 Mybatis5+4.0.0-RC2-1.8https://github.com/lonyee1989/incubator-shardingsphere/tree/4.0.0-RC2-1.8 直接上实现代码fork代码 1、package org.apache.shardingsphere.shardingjdbc.jdbc.core.resultset; 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657/** * Convert value via expected class type. * * @param value original value * @param convertType expected class type * @return converted value */public static Object convertValue(final Object value, final Class<?> convertType) { if (null == value) { return convertNullValue(convertType); } if (value.getClass() == convertType) { return value; } if (LocalDateTime.class.equals(convertType)) { return convertLocalDateTimeValue(value, convertType); } if (LocalDate.class.equals(convertType)) { return convertLocalDateValue(value, convertType); } if (LocalTime.class.equals(convertType)) { return convertLocalTimeValue(value, convertType); } if (value instanceof Number) { return convertNumberValue(value, convertType); } if (value instanceof Date) { return convertDateValue(value, convertType); } if (value instanceof byte[]) { return convertByteArrayValue(value, convertType); } if (String.class.equals(convertType)) { return value.toString(); } else { return value; }}......private static Object convertLocalDateTimeValue(final Object value, final Class<?> convertType) { Timestamp timestamp = (Timestamp) value; return timestamp.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();}private static Object convertLocalDateValue(final Object value, final Class<?> convertType) { Timestamp timestamp = (Timestamp) value; return timestamp.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();}private static Object convertLocalTimeValue(final Object value, final Class<?> convertType) { Timestamp timestamp = (Timestamp) value; return timestamp.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();} 2、package org.apache.shardingsphere.shardingjdbc.jdbc.core.resultset; 123456789101112131415@Overridepublic <T> T getObject(final int columnIndex, final Class<T> type) throws SQLException { if (LocalDateTime.class.equals(type) || LocalDate.class.equals(type) || LocalTime.class.equals(type)) { return (T) ResultSetUtil.convertValue(mergeResultSet.getValue(columnIndex, Timestamp.class), type); } throw new SQLFeatureNotSupportedException(\"getObject with type\");}@Overridepublic <T> T getObject(final String columnLabel, final Class<T> type) throws SQLException { if (LocalDateTime.class.equals(type) || LocalDate.class.equals(type) || LocalTime.class.equals(type)) { return (T) ResultSetUtil.convertValue(mergeResultSet.getValue(columnLabel, Timestamp.class), type); } throw new SQLFeatureNotSupportedException(\"getObject with type\");} 3、package org.apache.shardingsphere.shardingjdbc.jdbc.core.resultset; 123456789101112131415@Overridepublic <T> T getObject(final int columnIndex, final Class<T> type) throws SQLException { if (LocalDateTime.class.equals(type) || LocalDate.class.equals(type) || LocalTime.class.equals(type)) { return (T) ResultSetUtil.convertValue(resultSet.getValue(columnIndex, Timestamp.class), type); } throw new SQLFeatureNotSupportedException(\"getObject with type\");}@Overridepublic <T> T getObject(final String columnLabel, final Class<T> type) throws SQLException { if (LocalDateTime.class.equals(type) || LocalDate.class.equals(type) || LocalTime.class.equals(type)) { return (T) ResultSetUtil.convertValue(resultSet.getValue(columnLabel, Timestamp.class), type); } throw new SQLFeatureNotSupportedException(\"getObject with type\");} 4、package org.apache.shardingsphere.shardingjdbc.jdbc.unsupported; 123456789@Overridepublic <T> T getObject(final int columnIndex, final Class<T> type) throws SQLException { throw new SQLFeatureNotSupportedException(\"getObject with type\");}@Overridepublic <T> T getObject(final String columnLabel, final Class<T> type) throws SQLException { throw new SQLFeatureNotSupportedException(\"getObject with type\");}","categories":[{"name":"经验分享","slug":"经验分享","permalink":"https://github.com/weiecho/categories/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/"}],"tags":[{"name":"shardingsphere","slug":"shardingsphere","permalink":"https://github.com/weiecho/tags/shardingsphere/"},{"name":"spring","slug":"spring","permalink":"https://github.com/weiecho/tags/spring/"},{"name":"架构设计","slug":"架构设计","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/"}]},{"title":"Sentinel熔断降级","slug":"stu_1115","date":"2020-06-06T06:22:42.000Z","updated":"2020-07-03T06:01:01.495Z","comments":true,"path":"2020/06/06/stu_1115/","link":"","permalink":"https://github.com/weiecho/2020/06/06/stu_1115/","excerpt":"","text":"熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。 项目地址:sentinel流控防护 除流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。 由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。 Sentinel 熔断降级支持以下几种策略: RT 模式(秒级):若持续进入 5 个请求,它们资源的平均响应时间都超过阈值(秒级平均 RT,以 ms 为单位),资源调用会被熔断。在接下的降级时间窗口(在降级规则中配置,以 s 为单位)之内,对这个方法的调用都会自动地返回(抛出 DegradeException)。 异常比例模式(秒级):当资源的每秒异常数占通过量的比值超过阈值之后,资源进入降级状态,即在接下的降级时间窗口(在降级规则中配置,以 s 为单位))之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。 异常数模式(分钟级):当资源最近 1 分钟的异常数目超过阈值之后会进行熔断。","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://github.com/weiecho/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"开源工具","slug":"开源工具","permalink":"https://github.com/weiecho/tags/%E5%BC%80%E6%BA%90%E5%B7%A5%E5%85%B7/"},{"name":"流控降级","slug":"流控降级","permalink":"https://github.com/weiecho/tags/%E6%B5%81%E6%8E%A7%E9%99%8D%E7%BA%A7/"},{"name":"sentinel","slug":"sentinel","permalink":"https://github.com/weiecho/tags/sentinel/"}]},{"title":"Sentinel流量控制(限流)","slug":"stu_1114","date":"2020-05-25T05:18:42.000Z","updated":"2020-07-03T03:24:54.203Z","comments":true,"path":"2020/05/25/stu_1114/","link":"","permalink":"https://github.com/weiecho/2020/05/25/stu_1114/","excerpt":"","text":"流控,即流量控制(Flow Control),根据流量、并发线程数、响应时间等指标,把随机到来的流量调整成合适的形状,即流量塑形。避免应用被瞬时的流量高峰冲垮,从而保障应用的高可用性。 项目地址:sentinel流控防护 流量控制有以下几个角度:运行指标,例如 QPS、并发线程数等。 资源的调用关系,例如资源的调用链路,资源和资源之间的关系,调用来源等。 控制效果,例如直接拒绝、Warm Up(预热)、排队等待等。 一条流控规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果: 资源名:即流控规则的作用对象 阈值:流控阈值 阈值类型:流控阈值类型(QPS 或并发线程数) 来源应用:流控规则针对的调用来源,若为 default 则不区分调用来源 流控方式:调用关系限流策略 流控模式:即流控效果,包括快速失败、Warm Up、排队等待模式 运行指标流量控制支持通过以下运行指标进行流量塑形: 基于 QPSQPS 模式根据资源的实时 QPS 进行流量控制。当 QPS 超过指定阈值时采取相应的控制策略。 基于线程数线程数模式按照资源的并发线程数(即该资源正在执行的线程数)进行流量控制。 并发线程数限流用于保护业务线程数不被耗尽。例如,当应用所依赖的下游应用由于某种原因导致服务不稳定、响应延迟增加,对于调用者来说,意味着吞吐量下降和更多的线程数占用,极端情况下甚至导致线程池耗尽。为应对太多线程占用的情况,业内有使用隔离的方案,比如通过不同业务逻辑使用不同线程池来隔离业务自身之间的资源争抢(线程池隔离)。这种隔离方案虽然隔离性比较好,但是代价就是线程数目太多,线程上下文切换的 overhead 比较大,特别是对低延时的调用有比较大的影响。Sentinel 并发线程数限流不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目,如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。 控制效果流控方式(控制效果)指的是,当阈值类型为 QPS 时,选择如何控制流量,处理被拦截的流量,实现流量塑形。流量控制的手段包括以下几种:快速失败、Warm Up、排队等待。 说明 控制效果仅对 QPS 限流生效。 快速失败快速失败方式是默认的流量控制方式,当 QPS 超过规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出 FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。 Warm Up当系统长期处于空闲的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过 Warm Up 模式(预热模式),让通过的流量缓慢增加,经过设置的预热时间以后,到达系统处理请求速率的设定值。 Warm Up 模式默认会从设置的 QPS 阈值的 1/3 开始慢慢往上增加至 QPS 设置值。 排队等待排队等待模式下会严格控制请求通过的间隔时间,即请求会匀速通过,允许部分请求排队等待,通常用于消息队列削峰填谷等场景。需设置具体的超时时间,当计算的等待时间超过超时时间时请求就会被拒绝。 例如,QPS 配置为 5,则代表请求每 200 ms 才能通过一个,多出的请求将排队等待通过。超时时间代表最大排队时间,超出最大排队时间的请求将会直接被拒绝。排队等待模式下,QPS 设置值不要超过 1000(请求间隔 1 ms)。 排队等待","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://github.com/weiecho/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"开源工具","slug":"开源工具","permalink":"https://github.com/weiecho/tags/%E5%BC%80%E6%BA%90%E5%B7%A5%E5%85%B7/"},{"name":"流控降级","slug":"流控降级","permalink":"https://github.com/weiecho/tags/%E6%B5%81%E6%8E%A7%E9%99%8D%E7%BA%A7/"},{"name":"sentinel","slug":"sentinel","permalink":"https://github.com/weiecho/tags/sentinel/"}]},{"title":"Sentinel流控降级快速入门","slug":"stu_1113","date":"2020-05-02T04:18:12.000Z","updated":"2020-07-03T03:25:00.915Z","comments":true,"path":"2020/05/02/stu_1113/","link":"","permalink":"https://github.com/weiecho/2020/05/02/stu_1113/","excerpt":"","text":"Sentinel以流量为切入点,从流量控制、熔断降级、系统保护等多个维度来帮助您保障服务的稳定性,提供更专业稳定的流量防护手段、秒级的流量水位分布分析功能。 项目地址:sentinel流控防护 使用场景Sentinel广泛用于秒杀场景、消息削峰填谷、集群流量控制、实时熔断等场景中,从多个维度保障您的业务稳定性。 在一个常见的分布式应用中,如下图所示。一个请求先通过终端到达 Gateway,再经过防火墙和网络负载均衡,其中还包括调用下游的其它服务和第三方应用,才能到达前端网络服务。AHAS 应用流控降级在不同的层次以流量为切面提供秒级实时的流量分析(例如在客户端层提供流量实时监控和水位诊断分析功能),帮助运维人员采取针对性的防护措施,全方位地保护应用的稳定性。 Sentinel服务 功能特性秒级流量分析功能,动态规则实时推送。专业多样化的防护手段: 入口流量控制:按照服务容量进行流量控制,常用于应用入口,例如: Gateway、前端应用、服务提供方等。 热点隔离:将热点和普通流量隔离出来,避免无效热点抢占正常流量的容量。 对依赖方隔离 / 降级:对应用和应用之间、应用内部采用隔离 / 降级手段,将不稳定的依赖的对应用的影响减至最小,从而保证应用的稳定性。 系统防护:Sentinel可以根据系统的能力(例如 Load、CPU 使用率等)来动态调节入口的流量,保证系统稳定性。实时的单机监控能力,强大的聚合监控和历史监控查询能力。","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://github.com/weiecho/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"开源工具","slug":"开源工具","permalink":"https://github.com/weiecho/tags/%E5%BC%80%E6%BA%90%E5%B7%A5%E5%85%B7/"},{"name":"流控降级","slug":"流控降级","permalink":"https://github.com/weiecho/tags/%E6%B5%81%E6%8E%A7%E9%99%8D%E7%BA%A7/"},{"name":"sentinel","slug":"sentinel","permalink":"https://github.com/weiecho/tags/sentinel/"}]},{"title":"Sharding-db接入使用说明","slug":"doc_1113","date":"2020-03-02T04:26:35.000Z","updated":"2020-07-03T03:09:12.316Z","comments":true,"path":"2020/03/02/doc_1113/","link":"","permalink":"https://github.com/weiecho/2020/03/02/doc_1113/","excerpt":"","text":"ShardingSphere是开源的分布式数据库中间件解决方案组成的生态圈,由Sharding-jdbc、Sharding-Proxy等组成,提供标准化的数据分片、安全控制、分布式事务和数据库治理功能,本文主要介绍sharding-db在项目中的使用。 Sharding-db是对Sharding-jdbc的功能封装,方便功能的对接,统一项目团队对数据源的对接 项目地址:sharding-db Sharding-jdbc分片过程 Sharding-jdbc根据SQL语句进行词语解析,上下文匹配数据库和表的分片策略生成路由路径,将分表配置中的逻辑库表改写为真实库表SQL语句,发送到底层数据源执行,将从各个数据节点获取的多数据结果集,组合成为一个结果集并正确的返回至请求客户端。 POM配置 12345<dependency> <groupId>cn.weiecho</groupId> <artifactId>sharding-db</artifactId> <version>1.0.3</version></dependency> Database配置123456789101112131415161718//单数据源模式@Configurationpublic class DatabaseConfig extends DatabaseSingletonConfigurator {}//主从数据源模式@Configurationpublic class DatabaseConfig extends DatabaseMasterSlaveConfigurator {}//分表数据源模式@Configurationpublic class DatabaseConfig extends DatabaseShardingConfigurator {} 配置文件1234567891011121314151617181920212223242526272829303132333435363738sharding.jdbc: default-data-source-name: ms_ds_0 data-sources: ds_master: driver-class-name: com.mysql.cj.jdbc.Driver type: com.zaxxer.hikari.HikariDataSource jdbc-url: jdbc:mysql://127.0.0.1:3306/test_db?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull username: root password: root initial-size: 1 minimum-idle: 3 maximum-pool-size: 20 idle-timeout: 60000 max-lifetime: 180000 connection-test-query: select 1 test-while-idle: true test-on-borrow: true connection-init-sql: set names utf8mb4 ds_slave: driver-class-name: com.mysql.cj.jdbc.Driver type: com.zaxxer.hikari.HikariDataSource jdbc-url: jdbc:mysql://127.0.0.1:3307/test_db?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull username: root password: root initial-size: 1 minimum-idle: 3 maximum-pool-size: 20 idle-timeout: 60000 max-lifetime: 180000 connection-test-query: select 1 test-while-idle: true test-on-borrow: true connection-init-sql: set names utf8mb4 master-slave-rules: - name: ms_ds_0 master-data-source-name: ds_master slave-data-source-names: ds_slave load-balance-strategy: round_robin 分表策略配置重写DatabaseShardingConfigurator 的分表策略实现相关功能 1234567891011121314/** * 配置分表策略TableRule */public Collection<TableRuleConfiguration> tableRuleConfigs() { return Collections.emptyList();}/** * 配置绑定表分组BindingTable * 关联多表查询的时候避免笛卡尔积的组合出现 */public Collection<String> bindingTableGroups() { return Collections.emptyList();} 数据安全配置(脱敏)敏感数据脱敏,重写DatabaseShardingConfigurator的加密规则实现相关功能 1234567/** * 数据脱敏策略EncryptRule */public EncryptRuleConfiguration encryptRuleConfig() { return null;} 广播表策略用于数据源分片下,每个数据源都保存相同表全量数据,如字典表,配置表等 12345678/** * 配置广播表列表BroadcastTables * */public Collection<String> broadcastTables() { return Collections.emptyList();} 强制路由至主库12HintManager hintManager = HintManager.getInstance();hintManager.setMasterRouteOnly(); 推荐使用try with resource方式 1234try (HintManager hintManager = HintManager.getInstance()) { hintManager.setMasterRouteOnly();} 强制路由至指定读库12HintManager hintManager = HintManager.getInstance();hintManager.setDatabaseShardingValue(1); 推荐使用try with resource方式 1234try (HintManager hintManager = HintManager.getInstance()) { hintManager.setDatabaseShardingValue(1);}","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"数据源","slug":"数据源","permalink":"https://github.com/weiecho/tags/%E6%95%B0%E6%8D%AE%E6%BA%90/"},{"name":"分库分表","slug":"分库分表","permalink":"https://github.com/weiecho/tags/%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8/"},{"name":"shardingsphere","slug":"shardingsphere","permalink":"https://github.com/weiecho/tags/shardingsphere/"}]},{"title":"修复shardingsphere-4.0.0不能正常配置问题","slug":"exp_1115","date":"2019-12-10T13:21:36.000Z","updated":"2020-07-03T06:00:06.402Z","comments":true,"path":"2019/12/10/exp_1115/","link":"","permalink":"https://github.com/weiecho/2019/12/10/exp_1115/","excerpt":"","text":"目前官方已经邀请我调整了说明文档,文档已经和最新代码一致! 如果您准备自己调整配置注入方式,可以参考本次修复过程。 Sharingsphere在根据官方配置为Master-slave rule configuration模式时启动会报错如下: Master-slave 原因在4.0.0-x版本中,将代码迁移至apache时,小伙伴傲娇的将参数实现改成了如下,同时没有了无参数构造函数。 新版本MasterSlaveRuleConfiguration代码 再看看3.0.x原版的旧代码实现状况 旧版本MasterSlaveRuleConfiguration代码 官方示例居然还有无参数创建的示例,试问是怎么做到的 shardingsphere官方文档示例 从这点看有被改写忽略的问题,同时按照官方配置,出现如上的配置启动报错问题!!! 我是犀利的分割线 —- 下面是硬写解决方案 创建新类MasterSlaveRuleConfig.java,复制官方新版本MasterSlaveRuleConfiguration,改为如下: 改写MasterSlaveRuleConfiguration 1、@Getter改为@Data,支持配置读写 2、去掉内部private对象的final限定 3、加入MasterSlaveRuleConfiguration无参数构造函数 配置改造完成,下面是调整配置函数: 重写配置MasterSlaveRuleConfiguration MasterSlaveRuleConfig配置在 sharding.master-slave-rule 下面,和官方一致。 服务启动~~~~~ happy time 😄","categories":[{"name":"经验分享","slug":"经验分享","permalink":"https://github.com/weiecho/categories/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/"}],"tags":[{"name":"shardingsphere","slug":"shardingsphere","permalink":"https://github.com/weiecho/tags/shardingsphere/"},{"name":"spring","slug":"spring","permalink":"https://github.com/weiecho/tags/spring/"},{"name":"架构设计","slug":"架构设计","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/"}]},{"title":"lemon-rabbitmq实现rabbitMQ的解耦方式","slug":"doc_1111","date":"2019-12-02T02:34:12.000Z","updated":"2020-07-08T03:16:30.613Z","comments":true,"path":"2019/12/02/doc_1111/","link":"","permalink":"https://github.com/weiecho/2019/12/02/doc_1111/","excerpt":"","text":"项目地址:lemon-rabbitmq lemon-rabbitmq 消息生产端 lemon-rabbitmq-protocol 消息协议层 lemon-rabbitmq-consumer 消息消费端 消息协议层通过Jackson2序列化/反序列化,实现消息传递和对象接收 消息生产端1、通过发送带有消费端服务类名称和方法请求头,控制消费端调用执行消费发送的信息 2、利用消息回调接口ConfirmCallback确保消息安全发送至broker服务器,处理效率比事物方式更高 1234567891011121314151617public void sendMessage(final String serviceName, final String serviceMethodName,final String correlationId, Object request) { logger.info(\"sendMessage [this.{}, serviceMethodName:{} serviceName:{} correlationId: {}]\", this.getClass(), serviceMethodName, serviceName, correlationId); rabbitTemplate.setConfirmCallback(this); rabbitTemplate.setCorrelationKey(correlationId); rabbitTemplate.convertAndSend(routingkey, request, new MessagePostProcessor() { @Override public Message postProcessMessage(Message message) throws AmqpException { message.getMessageProperties().setAppId(appId); message.getMessageProperties().setTimestamp(new Date()); message.getMessageProperties().setMessageId(UUID.randomUUID().toString()); message.getMessageProperties().setCorrelationId(correlationId.getBytes()); message.getMessageProperties().setHeader(\"ServiceMethodName\", serviceMethodName); message.getMessageProperties().setHeader(\"ServiceName\", serviceName); return message; } }, new CorrelationData(correlationId));} 消息消费端1、监听MQ消息,利用method.invoke调用指定的服务类名称和方法,消费接收到的消息 2、使用Ack/Nack手动确认消息处理状态,保证broker消息被正确消费 12345678910111213141516171819public void onMessage(Message message, Channel channel) throws IOException { System.out.println(\"----- received\" + message.getMessageProperties()); try { Object msg = messageConverter.fromMessage(message); if (!appId.equals(message.getMessageProperties().getAppId())){ channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false); throw new SecurityException(\"非法应用appId:\" + message.getMessageProperties().getAppId()); } Object service = ctx.getBean(message.getMessageProperties().getHeaders().get(\"ServiceName\").toString()); String serviceMethodName = message.getMessageProperties().getHeaders().get(\"ServiceMethodName\").toString(); Method method = service.getClass().getMethod(serviceMethodName, msg.getClass()); method.invoke(service, msg); //确认消息成功消费 channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { System.out.println(\"------ err\"+ e.getMessage()); channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false); }}","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"springboot","slug":"springboot","permalink":"https://github.com/weiecho/tags/springboot/"},{"name":"mq","slug":"mq","permalink":"https://github.com/weiecho/tags/mq/"},{"name":"ack/nack","slug":"ack-nack","permalink":"https://github.com/weiecho/tags/ack-nack/"}]},{"title":"代码习惯在细节","slug":"exp_1112","date":"2019-11-05T07:12:12.000Z","updated":"2020-07-03T02:04:19.223Z","comments":true,"path":"2019/11/05/exp_1112/","link":"","permalink":"https://github.com/weiecho/2019/11/05/exp_1112/","excerpt":"","text":"分布式服务框架维护人员增多或变更,会出现质量的下降的问题,尤其是框架代码,要时刻牢记的细节。可能下面要讲的这些,大家都会觉得很简单,很基础,但要做到时刻牢记。在每一行代码中都考虑这些因素,是需要很大耐心的。 防止空指针和下标越界这是我最不喜欢看到的异常,尤其在核心框架中,我更愿看到信息详细的参数不合法异常。这也是一个编写健壮程序的开发人员,在写每一行代码都应在潜意识中防止的异常。基本上要能确保每一次写完的代码,在不测试的情况下,都不会出现这两个异常才算合格。 保证线程安全性和可见性对于框架的开发人员,对线程安全性和可见性的深入理解是最基本的要求。需要开发人员,在写每一行代码时都应在潜意识中确保其正确性。因为这种代码,在小并发下做功能测试时,会显得很正常。但在高并发下就会出现莫明其妙的问题,而且场景很难重现,极难排查。 尽早失败和前置断言尽早失败也应该成为潜意识,在有传入参数和状态变化时,均在入口处全部断言。一个不合法的值和状态,在第一时间就应报错,而不是等到要用时才报错。因为等到要用时,可能前面已经修改其它相关状态,而在程序中很少有人去处理回滚逻辑。这样报错后,其实内部状态可能已经混乱,极易在一个隐蔽分支上引发程序不可恢复。 分离可靠操作和不可靠操作这里的可靠是狭义的指是否会抛出异常或引起状态不一致,比如,写入一个线程安全的 Map,可以认为是可靠的,而写入数据库等,可以认为是不可靠的。开发人员必须在写每一行代码时,都注意它的可靠性与否,在代码中尽量划分开,并对失败做异常处理,并为容错,自我保护,自动恢复或切换等补偿逻辑提供清晰的切入点,保证后续增加的代码不至于放错位置,而导致原先的容错处理陷入混乱。 异常防御,但不忽略异常这里讲的异常防御,指的是对非必须途径上的代码进行最大限度的容忍,包括程序上的 BUG,比如:获取程序的版本号,会通过扫描 Manifest 和 jar 包名称抓取版本号,这个逻辑是辅助性的,但代码却不少,初步测试也没啥问题,但应该在整个 getVersion() 中加上一个全函数的 try-catch 打印错误日志,并返回基本版本,因为 getVersion() 可能存在未知特定场景异常,或被其他的开发人员误修改逻辑(但一般人员不会去掉 try-catch),而如果它抛出异常会导致主流程异常,这是我们不希望看到的。但这里要控制个度,不要随意 try-catch,更不要无声无息的吃掉异常。 缩小可变域和尽量 final如果一个类可以成为不变类(Immutable Class),就优先将它设计成不变类。不变类有天然的并发共享优势,减少同步或复制,而且可以有效帮忙分析线程安全的范围。就算是可变类,对于从构造函数传入的引用,在类中持有时,最好将字段 final,以免被中途误修改引用。不要以为这个字段是私有的,这个类的代码都是我自己写的,不会出现对这个字段的重新赋值。要考虑的一个因素是,这个代码可能被其他人修改,他不知道你的这个弱约定,final 就是一个不变契约。 降低修改时的误解性,不埋雷前面不停的提到代码被其他人修改,这也开发人员要随时紧记的。这个其他人包括未来的自己,你要总想着这个代码可能会有人去改它。我应该给修改的人一点什么提示,让他知道我现在的设计意图,而不要在程序里面加潜规则,或埋一些容易忽视的雷,比如:你用 null 表示不可用,size 等于 0 表示黑名单,这就是一个雷,下一个修改者,包括你自己,都不会记得有这样的约定,可能后面为了改某个其它 BUG,不小心改到了这里,直接引爆故障。对于这个例子,一个原则就是永远不要区分 null 引用和 empty 值。 提高代码的可测性这里的可测性主要指 Mock 的容易程度,和测试的隔离性。至于测试的自动性,可重复性,非偶然性,无序性,完备性(全覆盖),轻量性(可快速执行),一般开发人员,加上 JUnit 等工具的辅助基本都能做到,也能理解它的好处,只是工作量问题。这里要特别强调的是测试用例的单一性(只测目标类本身)和隔离性(不传染失败)。现在的测试代码,过于强调完备性,大量重复交叉测试,看起来没啥坏处,但测试代码越多,维护代价越高。经常出现的问题是,修改一行代码或加一个判断条件,引起 100 多个测试用例不通过。时间一紧,谁有这个闲功夫去改这么多形态各异的测试用例?久而久之,这个测试代码就已经不能真实反应代码现在的状况,很多时候会被迫绕过。最好的情况是,修改一行代码,有且只有一行测试代码不通过。如果修改了代码而测试用例还能通过,那也不行,表示测试没有覆盖到。另外,可 Mock 性是隔离的基础,把间接依赖的逻辑屏蔽掉。可 Mock 性的一个最大的杀手就是静态方法,尽量少用。","categories":[{"name":"经验分享","slug":"经验分享","permalink":"https://github.com/weiecho/categories/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/"}],"tags":[{"name":"springboot","slug":"springboot","permalink":"https://github.com/weiecho/tags/springboot/"},{"name":"cloud","slug":"cloud","permalink":"https://github.com/weiecho/tags/cloud/"},{"name":"分布式","slug":"分布式","permalink":"https://github.com/weiecho/tags/%E5%88%86%E5%B8%83%E5%BC%8F/"}]},{"title":"Apollo分布式配置中心快速入门","slug":"stu_1112","date":"2019-11-02T04:21:22.000Z","updated":"2020-07-03T02:32:12.986Z","comments":true,"path":"2019/11/02/stu_1112/","link":"","permalink":"https://github.com/weiecho/2019/11/02/stu_1112/","excerpt":"","text":"Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。 项目地址:apollo分布式配置中心 apollo 1、关键词AppId:唯一指定项目/配置的id,需在项目设置指定app.id ENV:当前获取的配置环境,对应DEV/FAT/UAT/PRO等 Namespace:根据命名空间划分每一类配置的 Cluster:多集群环境状况下的配置实现,默认为default 关联:可以关联的Public Namespace覆盖特殊属性 2、操作点发布:将调整后未发布的配置部署至应用可用状态 回滚:回滚至确实有修改的上一发布版本 灰度:可根据服务节点IP或AppId(public) 部分生效配置,可以全量发布 创建Cluster:创建不同的配置集群 创建/关联Namespace:创建或关联Namespace 3、核心点项目AppId:请为每一个服务创建并配置独立的appId 宿主机ENV:当前应用所在的环境,请设置 /opt/settings/server.properties apollo.meta:当前应用环境连接的注册中心地址,请设置/opt/settings/server.properties Private:当前AppId私有的命名空间配置属性 Public:所有项目可以公用的命名空间配置属性 多Namespace:项目中可配置多个命名空间,namespaces: bootstrap,application,dubbo Public关联/覆盖:如需修改Public配置,请关联Namepace到当前项目配置后覆盖属性","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://github.com/weiecho/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"开源工具","slug":"开源工具","permalink":"https://github.com/weiecho/tags/%E5%BC%80%E6%BA%90%E5%B7%A5%E5%85%B7/"},{"name":"配置中心","slug":"配置中心","permalink":"https://github.com/weiecho/tags/%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83/"},{"name":"apollo","slug":"apollo","permalink":"https://github.com/weiecho/tags/apollo/"}]},{"title":"JVM性能优化建议","slug":"exp_1113","date":"2019-10-20T14:30:31.000Z","updated":"2020-07-31T08:04:36.284Z","comments":true,"path":"2019/10/20/exp_1113/","link":"","permalink":"https://github.com/weiecho/2019/10/20/exp_1113/","excerpt":"","text":"123456优化建议:1、一般建议Xms等于Xmx,好处是避免每次gc后,调整堆的大小,减少系统内存分配开销2、串行垃圾收集器(Serial + Serial Old | -XX:+UseSerialGC)3、并行垃圾收集器(Parellel + Parellel Old),吞吐量优先(JVM server 模式 默认)4、并发垃圾收集器(ParNew + CMS)响应时间优先5、本次优化说明的JDK版本为 1.8 通用配置1、java -Xmx2g -Xms2g -XX:MetaspaceSize=256m -XX:+UseConcMarkSweepGC 并发大,对象小2、java -Xmx2g -Xms2g -Xmn512m -XX:MetaspaceSize=256m -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=2 -XX:+UseCMSCompactAtFullCollection 并发大,对象大3、java -Xmx4g -Xms4g -Xmn2g -XX:MetaspaceSize=512m -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=2 -XX:+UseCMSCompactAtFullCollection 核心参数 说明 默认值 备注 -Xms 最小堆内存 默认为物理内存的1/64,不会超过1G -Xmx 最大堆内存 默认为物理内存的1/4 -Xmn 新生代内存大小 默认值为-Xmx的3/8,老年代内存则为5/8 优先级较NewRatio高 -XX:NewRatio 新生代与老生代的内存的比值 2 -XX:SurvivorRatio Eden和2个存活区内存的比值 8 -XX:MetaspaceSize 元空间最小值 元空间并不在虚拟机中,而是使用本地内存 -XX:MaxMetaspaceSize 元空间最大值 -Xss 栈大小 1M -XX:ParallelGCThreads 并行收集器的线程数 默认为服务器CPU数目 此值最好配置与处理器数目相等 同样适用于CMS不用设置 -XX:PretenureSizeThreshold 手动指定对象大小 当对象达到指定大小时直接存放到老年代中,由于新生代大多使用复制算法,为了节省复制消耗 -XX:MaxTenuringThreshold 手动设置对象在新生代中存活年龄(存活次数) 15 -XX:+UseConcMarkSweepGC 手动指定老年代使用CMS收集器 -XX:-CMSParallelRemarkEnabled 手动配置开启并行标记,节省年轻代标记时间 废弃 -XX:CMSInitiatingOccupancyFraction=80 手动指定当老年代已用空间达到80%时,触发老年代回收(默认92%) -1 -XX:+UseCMSCompactAtFullCollection 在进行Full GC时对内存进行压缩 JDK1.6以前不需要配置,默认开启 -XX:CMSFullGCsBeforeCompaction=2 与XX:+UseCMSCompactAtFullCollection关联使用标识着每经过多少次Full GC 0 触发对内存进行一次压缩,默认是0次","categories":[{"name":"经验分享","slug":"经验分享","permalink":"https://github.com/weiecho/categories/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/"}],"tags":[{"name":"spring","slug":"spring","permalink":"https://github.com/weiecho/tags/spring/"},{"name":"架构设计","slug":"架构设计","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/"},{"name":"JVM","slug":"JVM","permalink":"https://github.com/weiecho/tags/JVM/"}]},{"title":"设计实现的健壮性","slug":"exp_1114","date":"2019-10-07T14:30:31.000Z","updated":"2020-07-03T02:03:46.069Z","comments":true,"path":"2019/10/07/exp_1114/","link":"","permalink":"https://github.com/weiecho/2019/10/07/exp_1114/","excerpt":"","text":"日志日志是发现问题、查看问题一个最常用的手段。日志质量往往被忽视,没有日志使用上的明确约定。重视 Log 的使用,提高 Log 的信息浓度。日志过多、过于混乱,会导致有用的信息被淹没。 要有效利用这个工具要注意: 严格约定WARN、ERROR级别记录的内容WARN 表示可以恢复的问题,无需人工介入。ERROR 表示需要人工介入问题。有了这样的约定,监管系统发现日志文件的中出现 ERROR 字串就报警,又尽量减少了发生。过多的报警会让人疲倦,使人对报警失去警惕性,使 ERROR 日志失去意义。再辅以人工定期查看 WARN 级别信息,以评估系统的“亚健康”程度。 日志中,尽量多的收集关键信息出问题时的现场信息,即排查问题要用到的信息。如服务调用失败时,要给出使用 Dubbo 的版本、服务提供者的 IP、使用的是哪个注册中心;调用的是哪个服务、哪个方法等等。这些信息如果不给出,那么事后人工收集的,问题过后现场可能已经不能复原,加大排查问题的难度。如果可能,给出问题的原因和解决方法。这让维护和问题解决变得简单,而不是寻求精通者(往往是实现者)的帮助。 同一个或是一类问题不要重复记录多次同一个或是一类异常日志连续出现几十遍的情况,还是常常能看到的。人眼很容易漏掉淹没在其中不一样的重要日志信息。要尽量避免这种情况。在可以预见会出现的情况,有必要加一些逻辑来避免。 如为一个问题准备一个标志,出问题后打日志后设置标志,避免重复打日志。问题恢复后清除标志。 虽然有点麻烦,但是这样做保证日志信息浓度,让监控更有效。 界限设置资源是有限的,CPU、内存、IO 等等。不要因为外部的请求、数据不受限的而崩溃。 线程池(ExectorService)的大小和饱和策略Server 端用于处理请求的 ExectorService 设置上限。ExecutorService 的任务等待队列使用有限队列,避免资源耗尽。当任务等待队列饱和时,选择一个合适的饱和策略。这样保证平滑劣化。 在一些设计中,饱和策略是丢弃数据,等待结果也只是请求的超时。 达到饱和时,说明已经达到服务提供方的负荷上限,要在饱和策略的操作中日志记录这个问题,以发出监控警报。记得注意不要重复多次记录哦。(注意,缺省的饱和策略不会有这些附加的操作。)根据警报的频率,已经决定扩容调整等等,避免系统问题被忽略。 集合容量如果确保进入集合的元素是可控的且是足够少,则可以放心使用。这是大部分的情况。如果不能保证,则使用有有界的集合。当到达界限时,选择一个合适的丢弃策略。 容错-重试-恢复高可用组件要容忍其依赖组件的失败。 服务注册中心目前服务注册中心使用了数据库来保存服务提供者和消费者的信息。注册中心集群不同注册中心也通过数据库来进行同步数据,以感知其它注册中心上提供者的变化。注册中心会在内存中保存一份提供者和消费者数据,数据库不可用时,注册中心独立对外提供服务以保证正常运转,只是拿不到其它注册中心的数据。当数据库恢复时,重试逻辑会将内存中修改的数据写回数据库,并拿到数据库中新数据。 服务的消费者服务消费者从注册中心拿到提供者列表后,会保存提供者列表到内存和磁盘文件中。这样注册中心宕机后消费者可以正常运转,甚至可以在注册中心宕机过程中重启消费者。消费者启动时,发现注册中心不可用,会读取保存在磁盘文件中提供者列表。重试逻辑保证注册中心恢复后,更新信息。 重试延迟策略数据库上的活锁注册中心会定时更新数据库一条记录的时间戳,这样集群中其它的注册中心感知它是存活。过期注册中心和它的相关数据 会被清除。数据库正常时,这个机制运行良好。但是数据库负荷高时,其上的每个操作都会很慢。这就出现: A 注册中心认为 B 过期,删除 B 的数据。 B 发现自己的数据没有了,重新写入自己的数据的反复操作。这些反复的操作又加重了数据库的负荷,恶化问题。 可以使用下面逻辑:当 B 发现自己数据被删除时(写入失败),选择等待这段时间再重试。重试时间可以选择指数级增长,如第一次等 1 分钟,第二次 10 分钟、第三次 100 分钟。 这样操作减少后,保证数据库可以冷却(Cool Down)下来。 Client 重连注册中心当一个注册中心停机时,其它的 Client 会同时接收事件,而去重连另一个注册中心。Client 数量相对比较多,会对注册中心造成冲击。避免方法可以是 Client 重连时随机延时 3 分钟,把重连分散开。","categories":[{"name":"经验分享","slug":"经验分享","permalink":"https://github.com/weiecho/categories/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"spring","slug":"spring","permalink":"https://github.com/weiecho/tags/spring/"},{"name":"架构设计","slug":"架构设计","permalink":"https://github.com/weiecho/tags/%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/"}]},{"title":"XXL-JOB分布式任务调度平台","slug":"tool_1112","date":"2019-10-03T05:23:12.000Z","updated":"2020-09-10T03:24:19.107Z","comments":true,"path":"2019/10/03/tool_1112/","link":"","permalink":"https://github.com/weiecho/2019/10/03/tool_1112/","excerpt":"","text":"XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。 项目地址:xxl-job分布式任务调度平台 简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; 动态:支持动态修改任务状态、启动/停止任务,以及终止运行中任务,即时生效; 调度中心HA(中心式):调度采用中心式设计,“调度中心”自研调度组件并支持集群部署,可保证调度中心HA; 执行器HA(分布式):任务分布式执行,任务”执行器”支持集群部署,可保证任务执行HA; 注册中心: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行。同时,也支持手动录入执行器地址; 弹性扩容缩容:一旦有新执行器机器上线或者下线,下次调度时将会重新分配任务; 路由策略:执行器集群部署时提供丰富的路由策略,包括:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等; 故障转移:任务路由策略选择”故障转移”情况下,如果执行器集群中某一台机器故障,将会自动Failover切换到一台正常的执行器发送调度请求。 阻塞处理策略:调度过于密集执行器来不及处理时的处理策略,策略包括:单机串行(默认)、丢弃后续调度、覆盖之前调度; 任务超时控制:支持自定义任务超时时间,任务运行超时将会主动中断任务; 任务失败重试:支持自定义任务失败重试次数,当任务失败时将会按照预设的失败重试次数主动进行重试;其中分片任务支持分片粒度的失败重试; 任务失败告警;默认提供邮件方式失败告警,同时预留扩展接口,可方便的扩展短信、钉钉等告警方式; 分片广播任务:执行器集群部署时,任务路由策略选择”分片广播”情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数开发分片任务; 动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。 事件触发:除了”Cron方式”和”任务依赖方式”触发任务执行之外,支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务,可根据业务事件灵活触发。 任务进度监控:支持实时监控任务进度; Rolling实时日志:支持在线查看调度结果,并且支持以Rolling方式实时查看执行器输出的完整的执行日志; GLUE:提供Web IDE,支持在线开发任务逻辑代码,动态发布,实时编译生效,省略部署上线的过程。支持30个版本的历史版本回溯。 脚本任务:支持以GLUE模式开发和运行脚本任务,包括Shell、Python、NodeJS、PHP、PowerShell等类型脚本; 命令行任务:原生提供通用命令行任务Handler(Bean任务,”CommandJobHandler”);业务方只需要提供命令行即可; 任务依赖:支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔; 一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行; 自定义任务参数:支持在线配置调度任务入参,即时生效; 调度线程池:调度系统多线程触发调度运行,确保调度精确执行,不被堵塞; 数据加密:调度中心和执行器之间的通讯进行数据加密,提升调度信息安全性; 邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件; 推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用; 运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等; 全异步:任务调度流程全异步化设计实现,如异步调度、异步运行、异步回调等,有效对密集调度进行流量削峰,理论上支持任意时长任务的运行; 跨平台:原生提供通用HTTP任务Handler(Bean任务,”HttpJobHandler”);业务方只需要提供HTTP链接即可,不限制语言、平台; 国际化:调度中心支持国际化设置,提供中文、英文两种可选语言,默认为中文; 容器化:提供官方docker镜像,并实时更新推送dockerhub,进一步实现产品开箱即用; 线程池隔离:调度线程池进行隔离拆分,慢任务自动降级进入”Slow”线程池,避免耗尽调度线程,提高系统稳定性; 用户管理:支持在线管理系统用户,存在管理员、普通用户两种角色; 权限控制:执行器维度进行权限控制,管理员拥有全量权限,普通用户需要分配执行器权限后才允许相关操作。","categories":[{"name":"常用工具","slug":"常用工具","permalink":"https://github.com/weiecho/categories/%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7/"}],"tags":[{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"开源工具","slug":"开源工具","permalink":"https://github.com/weiecho/tags/%E5%BC%80%E6%BA%90%E5%B7%A5%E5%85%B7/"},{"name":"定时任务","slug":"定时任务","permalink":"https://github.com/weiecho/tags/%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1/"},{"name":"xxl-job","slug":"xxl-job","permalink":"https://github.com/weiecho/tags/xxl-job/"}]},{"title":"XXL-JOB分布式任务快速入门","slug":"stu_1111","date":"2019-09-05T07:21:11.000Z","updated":"2020-07-03T02:06:28.839Z","comments":true,"path":"2019/09/05/stu_1111/","link":"","permalink":"https://github.com/weiecho/2019/09/05/stu_1111/","excerpt":"","text":"XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。 项目地址:xxl-job分布式任务调度平台 模块 调度中心 xxl-job-admin 公共依赖 xxl-job-core 任务执行器 opay-xxx 集群 调度中心集群 DB配置保持一致 登陆账号配置保持一致 集群机器时钟保持一致建议:推荐通过nginx为调度中心集群做负载均衡,分配域名 调度中心访问、执行器回调配置、调用API服务等操作均通过该域名进行。 执行器集群 执行器回调地址保持一致xxl.job.admin.addresses 执行器集群内AppName保持一致xxl.job.executor.appname 任务关键点 执行器 任务描述 路由策略 FIRST(第一个)固定选择第一个机器 LAST(最后一个)固定选择最后一个机器 ROUND(轮询) RANDOM(随机)随机选择在线的机器 CONSISTENT_HASH(一致性HASH)每个任务按照Hash算法固定选择某一台机器,且所有任务均匀散列在不同机器上 LEAST_FREQUENTLY_USED(最不经常使用)使用频率最低的机器优先被选举 LEAST_RECENTLY_USED(最近最久未使用)最久为使用的机器优先被选举 FAILOVER(故障转移)按照顺序依次进行心跳检测,第一个心跳检测成功的机器选定为目标执行器并发起调度 BUSYOVER(忙碌转移)按照顺序依次进行空闲检测,第一个空闲检测成功的机器选定为目标执行器并发起调度 SHARDING_BROADCAST(分片广播)广播触发对应集群中所有机器执行一次任务,同时系统自动传递分片参数,可根据分片参数开发分片任务 Cron表达式 运行模式 BEAN GLUE JobHandler任务bean名称@JobHandler 阻塞策略 单机串行进入单机执行器后,进入FIFO队列并以串行方式运行 丢弃后续调度进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败 覆盖之前调度进入单机执行器后,发现执行器存在运行的调度任务,将会终止运行中的调度任务并清空队列 负责人 其他 子任务ID 超时时间 重试次数 报警邮件 任务参数 注意事项 日志文件目录需要权限默认 /data/applogs/xxl-job/jobhandler 设置日志保存天数xxl.job.executor.logretentiondays=-1 //大于3生效 执行日志需要通过 “XxlJobLogger.log” 打印执行日志 admin执行任务时报错 Communications link failure数据库链接地址加上 &autoReconnect=true&failOverReadOnly=false","categories":[{"name":"学习笔记","slug":"学习笔记","permalink":"https://github.com/weiecho/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}],"tags":[{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"开源工具","slug":"开源工具","permalink":"https://github.com/weiecho/tags/%E5%BC%80%E6%BA%90%E5%B7%A5%E5%85%B7/"},{"name":"定时任务","slug":"定时任务","permalink":"https://github.com/weiecho/tags/%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1/"}]},{"title":"服务开发核心思想","slug":"exp_1111","date":"2019-09-03T04:30:12.000Z","updated":"2020-07-03T02:06:50.143Z","comments":true,"path":"2019/09/03/exp_1111/","link":"","permalink":"https://github.com/weiecho/2019/09/03/exp_1111/","excerpt":"","text":"保障服务可扩展性的七大原则1、按功能划分 2、水平切分 3、尽量避免事务 4、适当采用异步解耦 5、次流程改进为异步 6、虚拟化所有层次 7、适当使用缓存 服务拆分开发的四项原则1、先业务后技术,先逻辑后物理 2、奥卡姆剃刀:如无必须勿增实体 3、正交性:抽象出模块间无业务相关的重复代码 4、稳定性原则:服务的稳定性优先,通过拆分解耦 可参考的技术方案:接口化、消息队列、模块化、服务化、异步化","categories":[{"name":"经验分享","slug":"经验分享","permalink":"https://github.com/weiecho/categories/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/"}],"tags":[{"name":"springboot","slug":"springboot","permalink":"https://github.com/weiecho/tags/springboot/"},{"name":"cloud","slug":"cloud","permalink":"https://github.com/weiecho/tags/cloud/"},{"name":"分布式","slug":"分布式","permalink":"https://github.com/weiecho/tags/%E5%88%86%E5%B8%83%E5%BC%8F/"}]},{"title":"Hutool工具包类库","slug":"tool_1111","date":"2019-09-02T12:33:12.000Z","updated":"2020-07-03T02:06:37.677Z","comments":true,"path":"2019/09/02/tool_1111/","link":"","permalink":"https://github.com/weiecho/2019/09/02/tool_1111/","excerpt":"","text":"Hutool是一个Java工具包,也只是一个工具包,它帮助我们简化每一行代码,减少每一个方法,让Java语言也可以“甜甜的”。Hutool最初是我项目中“util”包的一个整理,后来慢慢积累并加入更多非业务相关功能,并广泛学习其它开源项目精髓,经过自己整理修改,最终形成丰富的开源工具集。 项目地址:hutool工具包 日期工具通过DateUtil类,提供高度便捷的日期访问、处理和转换方式。 HTTP客户端通过HttpUtil对HTTP客户端的封装,实现便捷的HTTP请求,并简化文件上传操作。 转换工具通过Convert类中的相应静态方法,提供一整套的类型转换解决方案,并通过ConverterRegistry工厂类自定义转换。 配置文件工具通过Setting对象,提供兼容Properties文件的更加强大的配置文件工具,用于解决中文、分组等JDK配置文件存在的诸多问题。 日志工具Hutool的日志功能,通过抽象Log接口,提供对Slf4j、LogBack、Log4j、JDK-Logging的全面兼容支持。 JDBC工具类通过db模块,提供对MySQL、Oracle等关系型数据库的JDBC封装,借助ActiveRecord思想,大大简化数据库操作。","categories":[{"name":"常用工具","slug":"常用工具","permalink":"https://github.com/weiecho/categories/%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7/"}],"tags":[{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"},{"name":"spring","slug":"spring","permalink":"https://github.com/weiecho/tags/spring/"},{"name":"开源工具","slug":"开源工具","permalink":"https://github.com/weiecho/tags/%E5%BC%80%E6%BA%90%E5%B7%A5%E5%85%B7/"}]},{"title":"开发者约定","slug":"doc_1110","date":"2019-09-01T03:10:12.000Z","updated":"2020-07-08T03:28:05.939Z","comments":true,"path":"2019/09/01/doc_1110/","link":"","permalink":"https://github.com/weiecho/2019/09/01/doc_1110/","excerpt":"","text":"本文档约定了服务开发人员的代码规范,从而增强代码的一致性和可维护性 1、接口地址和参数严格区分大小写,接口尽量全部小写,参数使用驼峰命名; 2、接口默认以请求参数形式传入参数,响应返回JSON格式数据; 3、H5内所有资源引用打包自动带上日期版本号,防止发布版本引用资源在浏览器缓存导致功能异常(如:./jquery-1.11.0.js?v=201806051011) 4、接口请求数据均需要携带header参数: 参数名 必填 类型 说明 x-auth-scope 是 string 授权作用域 x-auth-token 是 string 授权的token x-app-version 是 string 应用版本(固定 1.0.0) x-device 是 integer 设备类型(1:IOS 2:Android 3:wap 4: 微信 5: H5) x-device-name 是 string 设备/浏览器名称(如:huawei/Chrome) x-timestamp 是 long 10位时间戳 5、接口返回数据JSON格式标准: 正常状况下返回http状态码为200 异常或相关提示是http状态码大于等于400 业务异常时http状态码为400,系统故障时http状态码为500 正常状况下接口直接返回业务数据(void时返回空) 异常时返回错误码和错误信息(JSON格式) 参数名 类型 说明 code integer 错误码 msg string 错误信息 带返回数据示例: 12345{ \"userId\": \"1488512189\", \"nickName\": \"哈哈\", \"vip\": \"12\"} 异常返回示例: 1234{ \"msg\": \"短信验证码发送失败\", \"code\": \"13007\"}","categories":[{"name":"开源文档","slug":"开源文档","permalink":"https://github.com/weiecho/categories/%E5%BC%80%E6%BA%90%E6%96%87%E6%A1%A3/"}],"tags":[{"name":"微服务","slug":"微服务","permalink":"https://github.com/weiecho/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"},{"name":"开发规范","slug":"开发规范","permalink":"https://github.com/weiecho/tags/%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83/"},{"name":"java","slug":"java","permalink":"https://github.com/weiecho/tags/java/"}]}]}