首页 文章 精选 留言 我的

精选列表

搜索[java],共10000篇文章
优秀的个人博客,低调大师

O2OA V4.3763 稳定版发布,Java 办公开发平台迎来大量更新

O2OA团队于2020-03-16发布了新的软件版本 V4.3367,该版本除了修复了大量的系统BUG之外,也提供了几个较有看点的新功能: 一、通用办公系统首页 这个是协同办公平台的默认首页,它提供待办事项,需要参加的会议,日程管理等等,让员工更能关注自己的工作。 通用办公首页 待办已办的展现、信息的展现、会议、云文件以及日程的展现,主要是展现用户自己关心的办公信息数据 左铡系统应用列表 当然,用户也可以根据企业自身的需求,定义自己符合要求的首页,这个只是默认的页面样式 门户效果一 门户效果二 二、国标版式公文编辑器 版式文件也是平台在公文业务上的一个特色,公司自研了完全符合《党政机关公文格式》(GB/T 9704-2012)标准的版式文件组件,也是一种在线正文编辑的组件。它支持IE10+以及其他主流浏览器,支持移动端直接展现,脱离控件安装,展现效率高,展现效果好。 版式公文编辑器特点: 完全符合《党政机关公文格式》(GB/T 9704-2012)标准 支持公文要素排版软件,实现文档显示、版式文件生成、打印、印刷的效果完全一致 纯HTML编辑,无需加载任何插件和控件 支持所有主流浏览器(IE10+) 智能排版、版面整体自动调优、自动格式化 编辑展现格式一致,速度快。 支持移动端直接查看和编辑 表单和正文数据动态绑定 支持从Word和WPS等文档编辑工具中复制,并自动格式化 支持导出Word文件 移动端展现效果 版式公文编辑器原理: 版式公文编辑器优点: 1、展现效果完全符合《党政机关公文格式》(GB/T 9704-2012)标准,用户不需要再进行样式调整; 2、完全基于HTML实现,不依赖任何控件安装,有效降低使用安装难度; 3、展现速度快,效果好,支持主流浏览器以及各类移动端直接使用。 三、更加精准的流程流转记录 O2OA团队对流程引擎进行了大量的优化,可以提供更加精准备的流程流转过程记录,可追溯流程的真实流转情况。 四、流程表单一键下载功能 新版本O2OA支持一键将表单页面,公文正文以及所有附件打包成一个zip包提供下载,为用户下载流程内容提供了更为方便的操作方式 O2OA是基于J2EE架构,集成移动办公、智能办公,支持私有化部署,自适应负载能力的,能够很大程度上节约企业软件开发成本的基于AGPL协议开放源代码的企业信息化系统需求定制开发解决方案,对外提供专业的开发运维等技术服务。 最新版本 O2OA V4.3763 O2OA平台主要能力介绍: 流程管理:全功能流程引擎。基于任务驱动,开放式服务驱动,高灵活性、扩展性,事件定义丰富。包含人工、自动、拆分、合并、并行、定时、服务调用、子流程等功能。应用场景丰富,可轻松实现公文、合同、项目管理等复杂工作流应用。 信息管理:具有权限控制能力的内容管理平台。支持自定义栏目、分类,表格,表单,多级权限系统,能轻松实现知识管理、通知公司、规章制度、文件管理等内容发布系统。 门户管理:具体可视化表单编辑的,支持HTML直接导入的,支持各类数据源,外部应用集成能力的,所见即所得的门户管理平台。适用于实现企业信息化门户系统,可以轻松结合O2OA提供的认证设置与其他系统进行单点认证集成。 服务管理:可以在前端脚本的形式,开发和自定义web服务,实现与后端服务数据交互的能力。 数据中心:可以通过配置轻松实现数据透视图展示,数据统计、数据可视化图表开发等等功能。 智能办公:拥有语音办公、人脸识别、指纹认证、智能文档纠错、智能填表推荐等智能办公特色 移动办公:支持安卓\IOS手机APP办公,支持与企业微信和钉钉集成,支持企业私有化微信部署 开箱即用:O2OA还提供如考勤管理、日程管理、会议管理、脑图管理、便签、云文件、企业社区、执行力管理等开箱即用的应用供企业选择 最新版本服务器安装包下载[o2server_V4.3763]: windows 64Bit : http://download.o2oa.net/download/o2server_20200316073520_windows.zip Linux 64Bit : http://download.o2oa.net/download/o2server_20200316073520_linux.zip MacOS : http://download.o2oa.net/download/o2server_20200316073520_macos.zip AIX : http://download.o2oa.net/download/o2server_20200316073520_aix.zip 中标麒麟(龙芯):http://download.o2oa.net/download/o2server_20200316073520_neokylin_loongson.zip 银河麒麟(飞腾):http://download.o2oa.net/download/o2server_20200316073520_kylinos_phytium.zip raspberrypi(树莓派):http://download.o2oa.net/download/o2server_20200316073520_raspberrypi.zip 官方网盘下载: 百度云盘:https://pan.baidu.com/s/1oBQ1atXGyXdLaYE5uAqF1w 提取码: pnk9 腾讯微云:https://share.weiyun.com/5krUMjj 此版本还包含以下更新内容: 新增功能: [平台能力]新增平台首页相关配置。 [平台能力]新增全新主题模式,10种配色,更快的速度,更少的内存占用。 [平台能力]新增平台默认为扁平风格新版本系统首页。 [平台能力]新增管理员切换用户的功能。 [系统架构]新增静态web资源通过接口上传并分发到各集群环境功能。 [系统架构]新增资源上传分发通过socket分发以保证单独的web服务器节点也能上传资源。 [流程引擎]新增待办、已办、待阅、已阅分页列表。 [流程引擎]新增回退路由相关能力。 [流程表单]流程表单上增加正文、附件一键打包下载功能。 [流程引擎]新增功能:根据路由上的“优先路由”设置,给提交框设置“默认决策”。 [流程引擎]新增管理员上传附件到指定用户。 [流程引擎]流程会签新增分支功能在查找分支节点的时候增加选择节点的过滤。 [流程表单]手写板组件新增保存图片大小的参数、内容管理增加新建界面检查草稿、是否填写标题的配置。 [流程表单]新增国标版式公文编辑器文件版本控制能力。 [流程表单]增加流程附件修改名称功能。 [流程表单]新增导出工单的表单信息为Html、Word或者Pdf功能。 [内容管理]新增打印表单相关功能。 [内容管理]新增新的自定义按钮,增加打印功能。 [数据中心]新增视图操作条信息存储。 [数据中心]增加单独运行映射功能。 [服务平台]新增企业邮件解决方案:腾讯企业邮。 [服务平台]新增服务脚本预编译。 [云文件]新增Office预览功能(预览需要连到O2云)。 [消息提醒]新增管理员对待办进行提醒接口,可用于时效提醒。 [移动办公]新版移动端云盘功能升级。 [移动办公]新增企业微信扫码登录功能。 [移动办公]新增钉钉扫码登录功能。 [移动办公]新增企业微信待办消息可点击链接消息打开待办信息。 [移动办公]新增钉钉待办消息可点击超链接消息打开待办信息。 系统优化: [系统能力]优化了前端资源载入方式,提升平台页面展现效率。 [系统架构]默认开启NodeAgent的Socket服务。 [系统架构]默认安装包中不再自带Informix驱动包。 [流程引擎]通过jobid打开流程文档,提供多个work时会显示work列表供用户选择。 [流程引擎]让流程调度可以指定处理人。 [流程引擎]优化流程日志记录方式——Record对象。 [流程引擎]优化重置处理人功能。 [流程引擎]调度功能优化,调度可以选择人员。 [流程引擎]回滚功能优化。可以选择回滚到任意节点。 [流程引擎]召回功能优化。可以召回到指定的已处理人员。 [流程表单]修改checkClose方法,适配Chrome浏览器信标。 [内容管理]优化二级页面中显示列表的时候会两次加载数据的问题。 [内容管理]优化二级页面中复制文档的操作。 [组织同步]钉钉和企业微信组织和人员同步过程优化。 [移动办公]流程管理IOS流程发布去掉了必填标题的表单。 [移动办公]流程管理Android流程发布去掉了必填标题的表单。 [移动办公]钉钉工作表单操作按钮UI相关优化(钉钉UI规范)。 问题修复: [系统认证]OAUTH设置Info返回属性的问题。 [系统功能]修复了打开页面时出现空标签的问题。 [系统功能]修复了Chrome上检查新建时同步请求报错的问题。 [系统架构]修复了集群下流程起草数组越界问题:CRC32计算值可能为负数,需要取绝对值 [流程平台]通过管理接口无法删除已完成工作的问题。 [流程引擎]修复了某些情况下流程授权不生效的问题。 [流程引擎]修复了某些情况下流程转交错误的问题。 [流程引擎]修复了因授权引起的无法判断当前处理人是否存在的错误。 [流程表单]修复了版式文件在编辑模式下,保存文档时,正文内容偶尔不会被保存下来的问题。 [流程表单]修复了人员属性的组织类型判断错误的问题 [流程表单]修复了表单打印不分页的问题。 [流程表单]修复了视图导出为Excel和搜索内容不匹配问题。 [流程表单]修复了某些情况下Ntko控件打开附件不正常的问题。 [流程表单]修复了表单数据网格、单选按钮、人员组织的问题。 [流程表单]修复了版式文件编辑器编辑状态下不能保存内容的问题。 [流程表单]修复了表单信息转为Pdf后展现格式错误的问题。 [流程表单]修复了流程附件批量下载允许指定名称并可以指定site下载。 [流程表单]修复了日期组件格式化的时候使用中文显示不正常的问题。 [样式模板]修复了某些情况下样式模板Html中少了mouseover事件绑定,导致无法显示刷新按钮的问题。 [内容管理]修复了文档列表分页向前翻页数据不准确的问题。 [内容管理]修复了在IE下附件上传存储的名称带路径问题处理。 [内容管理]修复了内容管理和信息平台栏目分类数量不正确的问题。 [内容管理]修复了某些情况下文档权限失效的问题。 [内容管理]修复了取消分类导入视图设定报错的问题。 [内容管理]修复了设置导入导出视图分类出现错误的问题。 [内容管理]修复了Chrome浏览器中栏目配置首页显示不正常的问题。 [内容管理]修复了信息列表分页查询报错的问题。 [内容管理]修复了内容管理无法从Excel导入数据的问题。 [内容管理]修复了Cipher身份发布内容在某些情况下权限失效的问题。 [内容管理]修复了内容管理publishConent接口无法保存的问题。 [数据中心]修复了数据中心自建表和查询语句不能拷贝的问题。 [数据中心]修复了数据中心标题显示错误的问题 [个人设置]修复了个人设置中某些情况下常用意见配置不正常的问题。 [应用管理]修复了某些情况下应用导出导致系统错误的问题。 [考勤管理]修复了考勤管理中请假信息修改不生效的相关问题。 [移动办公]修复了流程管理App待阅查看后不会转为已阅的问题。 [移动办公]修复了某些情况下IOS有些机器首次安装启动的时候在启动界面没反应的问题。 [移动办公]修复了某些情况下移动端App内容管理编辑和保存无法使用的问题。 [移动办公]修复了某些情况下移动端App内容管理关联流程发起后服务调用出错的问题。 [移动办公]修复了企业微信上无法查看附件的问题。 [移动办公]修复了某些情况下移动端提交框没有覆盖的问题。 [移动办公]修复了某些情况下移动端信息平台打开不正常的问题。

优秀的个人博客,低调大师

4种Java线程池用法以及线程池的作用和优点,你都知道了没?

一、如下方式存在的问题 new Thread() { @Override public void run() { // 业务逻辑 } }.start(); 1、首先频繁的创建、销毁对象是一个很消耗性能的事情;2、如果用户量比较大,导致占用过多的资源,可能会导致我们的服务由于资源不足而宕机;3、综上所述,在实际的开发中,这种操作其实是不可取的一种方式。 二、使用线程池有什么优点 1、线程池中线程的使用率提升,减少对象的创建、销毁;2、线程池可以控制线程数,有效的提升服务器的使用资源,避免由于资源不足而发生宕机等问题; 三、线程池的四种使用方式 1、newCachedThreadPool创建一个线程池,如果线程池中的线程数量过大,它可以有效的回收多余的线程,如果线程数不足,那么它可以创建新的线程。 public static void method() throws Exception { ExecutorService executor = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) { final int index = i; Thread.sleep(1000); executor.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " " + index); } }); } } 执行结果 通过分析我看可以看到,至始至终都由一个线程执行,实现了线程的复用,并没有创建多余的线程。如果当我们的业务需要一定的时间进行处理,那么将会出现什么结果。我们来模拟一下。 可以明显的看出,现在就需要几条线程来交替执行。不足:这种方式虽然可以根据业务场景自动的扩展线程数来处理我们的业务,但是最多需要多少个线程同时处理缺是我们无法控制的;优点:如果当第二个任务开始,第一个任务已经执行结束,那么第二个任务会复用第一个任务创建的线程,并不会重新创建新的线程,提高了线程的复用率;2、newFixedThreadPool这种方式可以指定线程池中的线程数。举个栗子,如果一间澡堂子最大只能容纳20个人同时洗澡,那么后面来的人只能在外面排队等待。如果硬往里冲,那么只会出现一种情景,摩擦摩擦...首先测试一下最大容量为一个线程,那么会不会是我们预测的结果。 public static void method_01() throws InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(1); for (int i = 0; i < 10; i++) { Thread.sleep(1000); final int index = i; executor.execute(() -> { try { Thread.sleep(2 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " " + index); }); } executor.shutdown(); } 执行结果 我们改为3条线程再来看下结果 优点:两个结果综合说明,newFixedThreadPool的线程数是可以进行控制的,因此我们可以通过控制最大线程来使我们的服务器打到最大的使用率,同事又可以保证及时流量突然增大也不会占用服务器过多的资源。3、newScheduledThreadPool该线程池支持定时,以及周期性的任务执行,我们可以延迟任务的执行时间,也可以设置一个周期性的时间让任务重复执行。 该线程池中有以下两种延迟的方法。scheduleAtFixedRate测试一 public static void method_02() { ScheduledExecutorService executor = Executors.newScheduledThreadPool(5); executor.scheduleAtFixedRate(new Runnable() { @Override public void run() { long start = new Date().getTime(); System.out.println("scheduleAtFixedRate 开始执行时间:" + DateFormat.getTimeInstance().format(new Date())); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } long end = new Date().getTime(); System.out.println("scheduleAtFixedRate 执行花费时间=" + (end - start) / 1000 + "m"); System.out.println("scheduleAtFixedRate 执行完成时间:" + DateFormat.getTimeInstance().format(new Date())); System.out.println("======================================"); } }, 1, 5, TimeUnit.SECONDS); } 执行结果 测试二 总结:以上两种方式不同的地方是任务的执行时间,如果间隔时间大于任务的执行时间,任务不受执行时间的影响。如果间隔时间小于任务的执行时间,那么任务执行结束之后,会立马执行,至此间隔时间就会被打乱。scheduleWithFixedDelay测试一 public static void method_03() { ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); executor.scheduleWithFixedDelay(new Runnable() { @Override public void run() { long start = new Date().getTime(); System.out.println("scheduleWithFixedDelay 开始执行时间:" + DateFormat.getTimeInstance().format(new Date())); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } long end = new Date().getTime(); System.out.println("scheduleWithFixedDelay执行花费时间=" + (end - start) / 1000 + "m"); System.out.println("scheduleWithFixedDelay执行完成时间:" + DateFormat.getTimeInstance().format(new Date())); System.out.println("======================================"); } }, 1, 2, TimeUnit.SECONDS); } 执行结果 测试二 public static void method_03() { ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); executor.scheduleWithFixedDelay(new Runnable() { @Override public void run() { long start = new Date().getTime(); System.out.println("scheduleWithFixedDelay 开始执行时间:" + DateFormat.getTimeInstance().format(new Date())); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } long end = new Date().getTime(); System.out.println("scheduleWithFixedDelay执行花费时间=" + (end - start) / 1000 + "m"); System.out.println("scheduleWithFixedDelay执行完成时间:" + DateFormat.getTimeInstance().format(new Date())); System.out.println("======================================"); } }, 1, 2, TimeUnit.SECONDS); } 执行结果 总结:同样的,跟scheduleWithFixedDelay测试方法一样,可以测出scheduleWithFixedDelay的间隔时间不会受任务执行时间长短的影响。4、newSingleThreadExecutor这是一个单线程池,至始至终都由一个线程来执行。 public static void method_04() { ExecutorService executor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 5; i++) { final int index = i; executor.execute(() -> { try { Thread.sleep(2 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " " + index); }); } executor.shutdown(); } 执行结果 四、线程池的作用 线程池的作用主要是为了提升系统的性能以及使用率。文章刚开始就提到,如果我们使用最简单的方式创建线程,如果用户量比较大,那么就会产生很多创建和销毁线程的动作,这会导致服务器在创建和销毁线程上消耗的性能可能要比处理实际业务花费的时间和性能更多。线程池就是为了解决这种这种问题而出现的。 欢迎大家关注我的公种浩【程序员追风】,文章都会在里面更新,整理的资料也会放在里面。同样思想的设计还有很多,比如数据库连接池,由于频繁的连接数据库,然而创建连接是一个很消耗性能的事情,所有数据库连接池就出现了。 最后 欢迎大家一起交流,喜欢文章记得点个赞哟,感谢支持!

优秀的个人博客,低调大师

从零开始搭建Java开发环境第二篇:如何在windows10里安装MySQL

1 下载安装包 1.1 压缩包 https://dev.mysql.com/downloads/mysql/ [外链图片转存失败(img-oesO8K09-1566652568838)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")] 1.2 安装包 使用安装包安装则无需后续步骤 https://dev.mysql.com/downloads/file/?id=488055 [外链图片转存失败(img-Y3x59iO4-1566652568839)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")] 2 配置环境变量 [外链图片转存失败(img-RBgnyR9U-1566652568840)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")] 3 初始化MySQL [外链图片转存失败(img-pVrsH1g4-1566652568841)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")] 在MySQL路径下输入命令mysqld --initialize --user=mysql --console [外链图片转存失败(img-4a4YX8nO-1566652568842)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")] 3.1 记住你的初始密码 [外链图片转存失败(img-IQFQj1kT-1566652568842)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")] 2019-08-24T11:55:10.299750Z 0 [System] [MY-013169] [Server] F:DEVenvmysql-8.0.17-winx64binmysqld.exe (mysqld 8.0.17) initializing of server in progress as process 27232 2019-08-24T11:55:10.355861Z 0 [Warning] [MY-013242] [Server] --character-set-server: 'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous. 2019-08-24T11:55:33.531673Z 5 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: k;k;w6OJEZ#Q 2019-08-24T11:55:45.353166Z 0 [System] [MY-013170] [Server] F:DEVenvmysql-8.0.17-winx64binmysqld.exe (mysqld 8.0.17) initializing of server has completed 4 启动服务 [外链图片转存失败(img-LVA4VR9p-1566652568842)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")] 接着就是输入mysqld -install进行服务的添加 输入net start mysql启动服务 输入mysql -u root -p进行登录数据库,这时提示需要密码,然后就是用你上面的密码登录 修改密码语句:ALTER USER root@localhost IDENTIFIED BY '123456'; 修改密码为:123456 如果控制台乱码,可以改编码为utf-8 如果用git bash遇到问题,可以使用Windows自带的cmd或者powershell

优秀的个人博客,低调大师

还不知道如何实践微服务的Java程序员,这遍文章千万不要错过!

作者:古霜卡比 前言 本文将介绍微服务架构和相关的组件,介绍他们是什么以及为什么要使用微服务架构和这些组件。本文侧重于简明地表达微服务架构的全局图景,因此不会涉及具体如何使用组件等细节。要理解微服务,首先要先理解不是微服务的那些。通常跟微服务相对的是单体应用,即将所有功能都打包成在一个独立单元的应用程序。从单体应用到微服务并不是一蹴而就的,这是一个逐渐演变的过程。本文将以一个网上超市应用为例来说明这一过程。 最初的需求 几年前,小明和小皮一起创业做网上超市。小明负责程序开发,小皮负责其他事宜。当时互联网还不发达,网上超市还是蓝海。只要功能实现了就能随便赚钱。所以他们的需求很简单,只需要一个网站挂在公网,用户能够在这个网站上浏览商品、购买商品;另外还需一个管理后台,可以管理商品、用户、以及订单数据。 功能清单: 网站用户注册、登录功能商品展示下单管理后台用户管理商品管理订单管理由于需求简单,小明左手右手一个慢动作,网站就做好了。管理后台出于安全考虑,不和网站做在一起,小明右手左手慢动作重播,管理网站也做好了。总体架构图如下: 小明挥一挥手,找了家云服务部署上去,网站就上线了。上线后好评如潮,深受各类肥宅喜爱。小明小皮美滋滋地开始躺着收钱。随着业务发展……好景不长,没过几天,各类网上超市紧跟着拔地而起,对小明小皮造成了强烈的冲击。在竞争的压力下,小明小皮决定开展一些营销手段:开展促销活动。比如元旦全场打折,春节买二送一,情人节狗粮优惠券等等。拓展渠道,新增移动端营销。除了网站外,还需要开发移动端APP,微信小程序等。精准营销。利用历史数据对用户进行分析,提供个性化服务。……这些活动都需要程序开发的支持。小明拉了同学小红加入团队。小红负责数据分析以及移动端相关开发。小明负责促销活动相关功能的开发。因为开发任务比较紧迫,小明小红没有好好规划整个系统的架构,随便拍了拍脑袋,决定把促销管理和数据分析放在管理后台里,微信和移动端APP另外搭建。通宵了几天后,新功能和新应用基本完工。这时架构图如下: 这一阶段存在很多不合理的地方:网站和移动端应用有很多相同业务逻辑的重复代码。数据有时候通过数据库共享,有时候通过接口调用传输。接口调用关系杂乱。单个应用为了给其他应用提供接口,渐渐地越改越大,包含了很多本来就不属于它的逻辑。应用边界模糊,功能归属混乱。管理后台在一开始的设计中保障级别较低。加入数据分析和促销管理相关功能后出现性能瓶颈,影响了其他应用。数据库表结构被多个应用依赖,无法重构和优化。所有应用都在一个数据库上操作,数据库出现性能瓶颈。特别是数据分析跑起来的时候,数据库性能急剧下降。开发、测试、部署、维护愈发困难。即使只改动一个小功能,也需要整个应用一起发布。有时候发布会不小心带上了一些未经测试的代码,或者修改了一个功能后,另一个意想不到的地方出错了。为了减轻发布可能产生的问题的影响和线上业务停顿的影响,所有应用都要在凌晨三四点执行发布。发布后为了验证应用正常运行,还得盯到第二天白天的用户高峰期……团队出现推诿扯皮现象。关于一些公用的功能应该建设在哪个应用上的问题常常要争论很久,最后要么干脆各做各的,或者随便放个地方但是都不维护。尽管有着诸多问题,但也不能否认这一阶段的成果:快速地根据业务变化建设了系统。不过紧迫且繁重的任务容易使人陷入局部、短浅的思维方式,从而做出妥协式的决策。在这种架构中,每个人都只关注在自己的一亩三分地,缺乏全局的、长远的设计。长此以往,系统建设将会越来越困难,甚至陷入不断推翻、重建的循环。 是时候做出改变了 幸好小明和小红是有追求有理想的好青年。意识到问题后,小明和小红从琐碎的业务需求中腾出了一部分精力,开始梳理整体架构,针对问题准备着手改造。要做改造,首先你需要有足够的精力和资源。如果你的需求方(业务人员、项目经理、上司等)很强势地一心追求需求进度,以致于你无法挪出额外的精力和资源的话,那么你可能无法做任何事……在编程的世界中,最重要的便是抽象能力。微服务改造的过程实际上也是个抽象的过程。小明和小红整理了网上超市的业务逻辑,抽象出公用的业务能力,做成几个公共服务:用户服务商品服务促销服务订单服务数据分析服务各个应用后台只需从这些服务获取所需的数据,从而删去了大量冗余的代码,就剩个轻薄的控制层和前端。这一阶段的架构如下: 这个阶段只是将服务分开了,数据库依然是共用的,所以一些烟囱式系统的缺点仍然存在:数据库成为性能瓶颈,并且有单点故障的风险。数据管理趋向混乱。即使一开始有良好的模块化设计,随着时间推移,总会有一个服务直接从数据库取另一个服务的数据的现象。数据库表结构可能被多个服务依赖,牵一发而动全身,很难调整。如果一直保持共用数据库的模式,则整个架构会越来越僵化,失去了微服务架构的意义。因此小明和小红一鼓作气,把数据库也拆分了。所有持久化层相互隔离,由各个服务自己负责。另外,为了提高系统的实时性,加入了消息队列机制。架构如下: 完全拆分后各个服务可以采用异构的技术。比如数据分析服务可以使用数据仓库作为持久化层,以便于高效地做一些统计计算;商品服务和促销服务访问频率比较大,因此加入了缓存机制等。还有一种抽象出公共逻辑的方法是把这些公共逻辑做成公共的框架库。这种方法可以减少服务调用的性能损耗。但是这种方法的管理成本非常高昂,很难保证所有应用版本的一致性。数据库拆分也有一些问题和挑战:比如说跨库级联的需求,通过服务查询数据颗粒度的粗细问题等。但是这些问题可以通过合理的设计来解决。总体来说,数据库拆分是一个利大于弊的。微服务架构还有一个技术外的好处,它使整个系统的分工更加明确,责任更加清晰,每个人专心负责为其他人提供更好的服务。在单体应用的时代,公共的业务功能经常没有明确的归属。最后要么各做各的,每个人都重新实现了一遍;要么是随机一个人(一般是能力比较强或者比较热心的人)做到他负责的应用里面。在后者的情况下,这个人在负责自己应用之外,还要额外负责给别人提供这些公共的功能——而这个功能本来是无人负责的,仅仅因为他能力较强/比较热心,就莫名地背锅(这种情况还被美其名曰能者多劳)。结果最后大家都不愿意提供公共的功能。长此以往,团队里的人渐渐变得各自为政,不再关心全局的架构设计。从这个角度上看,使用微服务架构同时也需要组织结构做相应的调整。所以说做微服务改造需要管理者的支持。改造完成后,小明和小红分清楚各自的锅。两人十分满意,一切就像是麦克斯韦方程组一样漂亮完美。然而…… 没有银弹 春天来了,万物复苏,又到了一年一度的购物狂欢节。眼看着日订单数量蹭蹭地上涨,小皮小明小红喜笑颜开。可惜好景不长,乐极生悲,突然嘣的一下,系统挂了。以往单体应用,排查问题通常是看一下日志,研究错误信息和调用堆栈。而微服务架构整个应用分散成多个服务,定位故障点非常困难。小明一个台机器一台机器地查看日志,一个服务一个服务地手工调用。经过十几分钟的查找,小明终于定位到故障点:促销服务由于接收的请求量太大而停止响应了。其他服务都直接或间接地会调用促销服务,于是也跟着宕机了。在微服务架构中,一个服务故障可能会产生雪崩效用,导致整个系统故障。其实在节前,小明和小红是有做过请求量评估的。按照预计,服务器资源是足以支持节日的请求量的,所以肯定是哪里出了问题。不过形势紧急,随着每一分每一秒流逝的都是白花花的银子,因此小明也没时间排查问题,当机立断在云上新建了几台虚拟机,然后一台一台地部署新的促销服务节点。几分钟的操作后,系统总算是勉强恢复正常了。整个故障时间内估计损失了几十万的销售额,三人的心在滴血……事后,小明简单写了个日志分析工具(量太大了,文本编辑器几乎打不开,打开了肉眼也看不过来),统计了促销服务的访问日志,发现在故障期间,商品服务由于代码问题,在某些场景下会对促销服务发起大量请求。这个问题并不复杂,小明手指抖一抖,修复了这个价值几十万的Bug。问题是解决了,但谁也无法保证不会再发生类似的其他问题。微服务架构虽然逻辑设计上看是完美的,但就像积木搭建的华丽宫殿一样,经不起风吹草动。微服务架构虽然解决了旧问题,也引入了新的问题:微服务架构整个应用分散成多个服务,定位故障点非常困难。稳定性下降。服务数量变多导致其中一个服务出现故障的概率增大,并且一个服务故障可能导致整个系统挂掉。事实上,在大访问量的生产场景下,故障总是会出现的。服务数量非常多,部署、管理的工作量很大。开发方面:如何保证各个服务在持续开发的情况下仍然保持协同合作。测试方面:服务拆分后,几乎所有功能都会涉及多个服务。原本单个程序的测试变为服务间调用的测试。测试变得更加复杂。小明小红痛定思痛,决心好好解决这些问题。对故障的处理一般从两方面入手,一方面尽量减少故障发生的概率,另一方面降低故障造成的影响。 监控 - 发现故障的征兆 在高并发分布式的场景下,故障经常是突然间就雪崩式爆发。所以必须建立完善的监控体系,尽可能发现故障的征兆。微服务架构中组件繁多,各个组件所需要监控的指标不同。比如Redis缓存一般监控占用内存值、网络流量,数据库监控连接数、磁盘空间,业务服务监控并发数、响应延迟、错误率等。因此如果做一个大而全的监控系统来监控各个组件是不大现实的,而且扩展性会很差。一般的做法是让各个组件提供报告自己当前状态的接口(metrics接口),这个接口输出的数据格式应该是一致的。然后部署一个指标采集器组件,定时从这些接口获取并保持组件状态,同时提供查询服务。最后还需要一个UI,从指标采集器查询各项指标,绘制监控界面或者根据阈值发出告警。大部分组件都不需要自己动手开发,网络上有开源组件。小明下载了RedisExporter和MySQLExporter,这两个组件分别提供了Redis缓存和MySQL数据库的指标接口。微服务则根据各个服务的业务逻辑实现自定义的指标接口。然后小明采用Prometheus作为指标采集器,Grafana配置监控界面和邮件告警。这样一套微服务监控系统就搭建起来了: 定位问题 - 链路跟踪 在微服务架构下,一个用户的请求往往涉及多个内部服务调用。为了方便定位问题,需要能够记录每个用户请求时,微服务内部产生了多少服务调用,及其调用关系。这个叫做链路跟踪。我们用一个Istio文档里的链路跟踪例子来看看效果: 从图中可以看到,这是一个用户访问productpage页面的请求。在请求过程中,productpage服务顺序调用了details和reviews服务的接口。而reviews服务在响应过程中又调用了ratings的接口。整个链路跟踪的记录是一棵树: 要实现链路跟踪,每次服务调用会在HTTP的HEADERS中记录至少记录四项数据:traceId:traceId标识一个用户请求的调用链路。具有相同traceId的调用属于同一条链路。spanId:标识一次服务调用的ID,即链路跟踪的节点ID。parentId:父节点的spanId。requestTime & responseTime:请求时间和响应时间。另外,还需要调用日志收集与存储的组件,以及展示链路调用的UI组件。 以上只是一个极简的说明,关于链路跟踪的理论依据可详见Google的Dapper了解了理论基础后,小明选用了Dapper的一个开源实现Zipkin。然后手指一抖,写了个HTTP请求的拦截器,在每次HTTP请求时生成这些数据注入到HEADERS,同时异步发送调用日志到Zipkin的日志收集器中。这里额外提一下,HTTP请求的拦截器,可以在微服务的代码中实现,也可以使用一个网络代理组件来实现(不过这样子每个微服务都需要加一层代理)。链路跟踪只能定位到哪个服务出现问题,不能提供具体的错误信息。查找具体的错误信息的能力则需要由日志分析组件来提供。 分析问题 - 日志分析 日志分析组件应该在微服务兴起之前就被广泛使用了。即使单体应用架构,当访问数变大、或服务器规模增多时,日志文件的大小会膨胀到难以用文本编辑器进行访问,更糟的是它们分散在多台服务器上面。排查一个问题,需要登录到各台服务器去获取日志文件,一个一个地查找(而且打开、查找都很慢)想要的日志信息。 因此,在应用规模变大时,我们需要一个日志的“搜索引擎”。以便于能准确的找到想要的日志。另外,数据源一侧还需要收集日志的组件和展示结果的UI组件:小明调查了一下,使用了大名鼎鼎地ELK日志分析组件。ELK是Elasticsearch、Logstash和Kibana三个组件的缩写。Elasticsearch:搜索引擎,同时也是日志的存储。Logstash:日志采集器,它接收日志输入,对日志进行一些预处理,然后输出到Elasticsearch。Kibana:UI组件,通过Elasticsearch的API查找数据并展示给用户。最后还有一个小问题是如何将日志发送到Logstash。一种方案是在日志输出的时候直接调用Logstash接口将日志发送过去。这样一来又(咦,为啥要用“又”)要修改代码……于是小明选用了另一种方案:日志仍然输出到文件,每个服务里再部署个Agent扫描日志文件然后输出给Logstash。 网关 - 权限控制,服务治理 拆分成微服务后,出现大量的服务,大量的接口,使得整个调用关系乱糟糟的。经常在开发过程中,写着写着,忽然想不起某个数据应该调用哪个服务。或者写歪了,调用了不该调用的服务,本来一个只读的功能结果修改了数据……为了应对这些情况,微服务的调用需要一个把关的东西,也就是网关。在调用者和被调用者中间加一层网关,每次调用时进行权限校验。另外,网关也可以作为一个提供服务接口文档的平台。使用网关有一个问题就是要决定在多大粒度上使用:最粗粒度的方案是整个微服务一个网关,微服务外部通过网关访问微服务,微服务内部则直接调用;最细粒度则是所有调用,不管是微服务内部调用或者来自外部的调用,都必须通过网关。折中的方案是按照业务领域将微服务分成几个区,区内直接调用,区间通过网关调用。由于整个网上超市的服务数量还不算特别多,小明采用的最粗粒度的方案: 服务注册于发现 - 动态扩容 前面的组件,都是旨在降低故障发生的可能性。然而故障总是会发生的,所以另一个需要研究的是如何降低故障产生的影响。最粗暴的(也是最常用的)故障处理策略就是冗余。一般来说,一个服务都会部署多个实例,这样一来能够分担压力提高性能,二来即使一个实例挂了其他实例还能响应。冗余的一个问题是使用几个冗余?这个问题在时间轴上并没有一个切确的答案。根据服务功能、时间段的不同,需要不同数量的实例。比如在平日里,可能4个实例已经够用;而在促销活动时,流量大增,可能需要40个实例。因此冗余数量并不是一个固定的值,而是根据需要实时调整的。一般来说新增实例的操作为:部署新实例将新实例注册到负载均衡或DNS上操作只有两步,但如果注册到负载均衡或DNS的操作为人工操作的话,那事情就不简单了。想想新增40个实例后,要手工输入40个IP的感觉……解决这个问题的方案是服务自动注册与发现。首先,需要部署一个服务发现服务,它提供所有已注册服务的地址信息的服务。DNS也算是一种服务发现服务。然后各个应用服务在启动时自动将自己注册到服务发现服务上。并且应用服务启动后会实时(定期)从服务发现服务同步各个应用服务的地址列表到本地。服务发现服务也会定期检查应用服务的健康状态,去掉不健康的实例地址。这样新增实例时只需要部署新实例,实例下线时直接关停服务即可,服务发现会自动检查服务实例的增减。 服务发现还会跟客户端负载均衡配合使用。由于应用服务已经同步服务地址列表在本地了,所以访问微服务时,可以自己决定负载策略。甚至可以在服务注册时加入一些元数据(服务版本等信息),客户端负载则根据这些元数据进行流量控制,实现A/B测试、蓝绿发布等功能。服务发现有很多组件可以选择,比如说Zookeeper 、Eureka、Consul、Etcd等。不过小明觉得自己水平不错,想炫技,于是基于Redis自己写了一个…… 熔断、服务降级、限流 熔断当一个服务因为各种原因停止响应时,调用方通常会等待一段时间,然后超时或者收到错误返回。如果调用链路比较长,可能会导致请求堆积,整条链路占用大量资源一直在等待下游响应。所以当多次访问一个服务失败时,应熔断,标记该服务已停止工作,直接返回错误。直至该服务恢复正常后再重新建立连接。 服务降级当下游服务停止工作后,如果该服务并非核心业务,则上游服务应该降级,以保证核心业务不中断。比如网上超市下单界面有一个推荐商品凑单的功能,当推荐模块挂了后,下单功能不能一起挂掉,只需要暂时关闭推荐功能即可。 限流一个服务挂掉后,上游服务或者用户一般会习惯性地重试访问。这导致一旦服务恢复正常,很可能因为瞬间网络流量过大又立刻挂掉,在棺材里重复着仰卧起坐。因此服务需要能够自我保护——限流。限流策略有很多,最简单的比如当单位时间内请求数过多时,丢弃多余的请求。另外,也可以考虑分区限流。仅拒绝来自产生大量请求的服务的请求。例如商品服务和订单服务都需要访问促销服务,商品服务由于代码问题发起了大量请求,促销服务则只限制来自商品服务的请求,来自订单服务的请求则正常响应。 测试微服务架构下,测试分为三个层次:端到端测试:覆盖整个系统,一般在用户界面机型测试。服务测试:针对服务接口进行测试。单元测试:针对代码单元进行测试。三种测试从上到下实施的容易程度递增,但是测试效果递减。端到端测试最费时费力,但是通过测试后我们对系统最有信心。单元测试最容易实施,效率也最高,但是测试后不能保证整个系统没有问题。 由于端到端测试实施难度较大,一般只对核心功能做端到端测试。一旦端到端测试失败,则需要将其分解到单元测试:则分析失败原因,然后编写单元测试来重现这个问题,这样未来我们便可以更快地捕获同样的错误。服务测试的难度在于服务会经常依赖一些其他服务。这个问题可以通过Mock Server解决: 单元测试大家都很熟悉了。我们一般会编写大量的单元测试(包括回归测试)尽量覆盖所有代码。 微服务框架 指标接口、链路跟踪注入、日志引流、服务注册发现、路由规则等组件以及熔断、限流等功能都需要在应用服务上添加一些对接代码。如果让每个应用服务自己实现是非常耗时耗力的。基于DRY的原则,小明开发了一套微服务框架,将与各个组件对接的代码和另外一些公共代码抽离到框架中,所有的应用服务都统一使用这套框架进行开发。使用微服务框架可以实现很多自定义的功能。甚至可以将程序调用堆栈信息注入到链路跟踪,实现代码级别的链路跟踪。或者输出线程池、连接池的状态信息,实时监控服务底层状态。使用统一的微服务框架有一个比较严重的问题:框架更新成本很高。每次框架升级,都需要所有应用服务配合升级。当然,一般会使用兼容方案,留出一段并行时间等待所有应用服务升级。但是如果应用服务非常多时,升级时间可能会非常漫长。并且有一些很稳定几乎不更新的应用服务,其负责人可能会拒绝升级……因此,使用统一微服务框架需要完善的版本管理方法和开发管理规范。 另一条路 - Service Mesh 另一种抽象公共代码的方法是直接将这些代码抽象到一个反向代理组件。每个服务都额外部署这个代理组件,所有出站入站的流量都通过该组件进行处理和转发。这个组件被称为Sidecar。Sidecar不会产生额外网络成本。Sidecar会和微服务节点部署在同一台主机上并且共用相同的虚拟网卡。所以sidecar和微服务节点的通信实际上都只是通过内存拷贝实现的。 Sidecar只负责网络通信。还需要有个组件来统一管理所有sidecar的配置。在Service Mesh中,负责网络通信的部分叫数据平面(data plane),负责配置管理的部分叫控制平面(control plane)。数据平面和控制平面构成了Service Mesh的基本架构。 Sevice Mesh相比于微服务框架的优点在于它不侵入代码,升级和维护更方便。它经常被诟病的则是性能问题。即使回环网络不会产生实际的网络请求,但仍然有内存拷贝的额外成本。另外有一些集中式的流量处理也会影响性能。 结束、也是开始 微服务不是架构演变的终点。往细走还有Serverless、FaaS等方向。另一方面也有人在唱合久必分分久必合,重新发现单体架构…… 最后欢迎大家一起交流,喜欢文章记得点个赞哟,感谢支持!

优秀的个人博客,低调大师

Java程序员金九银十跳槽面试,微服务架构是你必须过的坎

近几年,微服务架构迅速在整个技术社区窜红,被认为是 IT 软件架构的未来方向。一线互联网公司由于具有大量的业务体量和业务场景,比如阿里、百度、网易,很早就开始入坑微服务架构。 但说起微服务,不少人还是有这样的困惑:“作为一个开发,微服务架构是不是和我关系不大?那不都是架构师的事吗?”关于这个问题,我来谈谈自己的看法。微服务是当下最火热的后端架构之一。不管你是一个什么级别的程序员,也不论你在一个什么体量的公司,服务化都是你迟早会遇到的难题。实践微服务的过程本身也是一个升级打怪的过程,这中间你会遇到基本上所有后端架构的问题。解决了这些问题,你自然也就理解了那些高深的概念,也就成为了一名架构师,成长和能力提升都是这个过程的附属品。并且,你了解微服务架构之后,能知道领导为什么让你这么做,也更容易站在系统角度思考公司技术的进程,这对于你的大局观构建来说非常有帮助。再者,微服务这技术在面试的时候总有人提,尤其对于头部互联网企业,微服务架构更是面试考核必备,所以“进大厂必须掌握的50个微服务面试问题”等一些文章备受欢迎。今天专门分享一份微服务架构的技术路线给大家 如果下面这些微服务面试题总分是100分,看看你能答多少分呢?1.什么是 Spring Cloud?2.使用 Spring Cloud 有什么优势?3.服务注册和发现是什么意思?Spring Cloud 如何实现?4.负载平衡的意义什么?5.什么是 Hystrix?它如何实现容错?6.什么是 Hystrix 断路器?我们需要它吗?7.什么是 Netflix Feign?它的优点是什么?8.什么是 Spring Cloud Bus?我们需要它吗?9.什么是 Spring Boot?10.Spring Boot 有哪些优点?11.什么是 JavaConfig?12.如何重新加载 Spring Boot 上的更改,而无需重新启动服务器?13.Spring Boot 中的监视器是什么?14.如何在 Spring Boot 中禁用 Actuator 端点安全性?15.什么是 YAML?16.如何实现 Spring Boot 应用程序的安全性?17.如何使用 Spring Boot 实现分页和排序?18.什么是 Swagger?你用 Spring Boot 实现了它吗?19.什么是 Spring Batch?20.如何使用 Spring Boot 实现异常处理? 欢迎大家一起交流,喜欢文章记得点个赞,感谢支持!

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册