为什么“分布式”要加引号?

  与其他公司提高并发性能的场景可能不太一样,我们的系统之前是多个模块共用一个tomcat来运行的(All in One),模块有很多,光安装包就几十个。当某个模块或某几个模块出问题的时候,整个tomcat就挂了,请求时间长、内存占用高、垃圾回收频繁、错误日志不停的刷....现场工程解决问题的办法是,重启tomcat(小问题重启浏览器,大问题重启tomcat,万能的重启^_^)!!当然,这个对用户的使用体验很差,用户甚至提出要弃用我们公司系统的说法了,领导压力大啊...

  因本项目历史久远、技术落后、规模庞大、交接频率高,想系统的发现及解决问题是件很困难的事。重新开发一套系统也是不可能的事(这套系统积累了太多的心血在上面了,无论从人力、时间成本来说都花费太大,下不了狠心)。于是,分布式部署的方案被提上了工作日程,目的是将各模块隔离开来,出问题的时候互不影响。但是,一套不是面向分布式的设计的系统,要想实现分布式部署,就像是将一大团的乱麻分成一团团小的乱麻(哈哈,这比喻我觉得挺恰当的,分开来后还是乱麻^_^),谈何容易啊!

  艰巨而又头疼的任务分给了我们组。经过几轮讨论后,列出了几个关键的问题:

  1、  静态变量共享问题。单独部署的情况下,各业务注册的数据,如字典数据、关键词类型等,存放在全局的静态变量中的;分布的情况下,各业务只能获取到自己模块注册的数据,获取不到全量的数据。

  2、  定时任务重复执行问题。分布式的情况下,会有多个界面框架模块共存。界面框架中的定时任务执行次数和执行频率都会变高。其实从机器中的定时任务是不需要的。

  3、  文件上传与读取问题。All in One的情况下,界面框架提供统一的上传组件,文件上传到一个固定目录下,各业务可以通过绝对路径获取到文件,直接操作文件流。分布式的情况下,业务上传的文件会上传至主框架上,当从节点通过绝对路径去访问时,肯定是获取不到文件的。

  4、  session共享问题。All in One的情况下,各业务拿到的是同一个session;分布式的情况下,各业务的sessionID不通,session也不是同一个session,一个机器上修改了session的数据,其他机器要实时感知到数据的变化。

  5、  请求分发问题。各业务的请求,应该被正确的分发给各业务机器处理,各业务机器处理请求时不需要登录,登录统一由主框架负责处理。

  6、  安装时重复刷菜单的问题。All in One的情况下,安装或升级某个包时,会将对应的菜单刷到菜单表中。分布式的情况下,各从机器升级界面框架包时,也会刷界面框架的菜单,很可能导致菜单表的数据出问题。

  7、  单例问题。不确定具体的影响范围。

  8、  多线程执行顺序问题。不确定具体的影响范围。

  9、  事务。不确定具体的影响范围。

  10、 各机器对时。不确定具体的影响范围。

  大概确定了思路如下:

  1、 各模块单独部署在各自的tomcat里,各模块安装需依赖界面框架模块。

  2、 通过nginx做代理,保证对用户的入口唯一。按各模块url请求规则,分配到各自的tomcat上处理请求。平台公共的请求由一个tomcat单独处理。

  3、 tomcat通过共享session,与nginx呼应,确保用户会话在多个tomcat共享。

  4、 引入Spring-session模块,将session存储到redis服务器上。

  5、 将静态变量通过redis的发布/通知机制,修改代码,实现静态变量的同步。

  6、 增加nginx配置服务,用于管理各业务的请求转发规则,并定义各机器的角色。主节点只能有一台,负责处理公共请求、执行界面定时任务、刷界面框架的菜单;从节点的界面框架负责支撑业务功能。

  7、 增加文件服务器,将上传的文件存储到文件服务器上。

  8、 其他问题暂不确定具体的影响范围。

未完待续,后面整理迁移过程中遇到的坑!

坑1:Spring session 提交问题

  因要对session共享,使用的spring session本以为万事大吉,结果问题来了。看下代码:

  UserBean user = (UserBean )session.getAttribute("currentLoginUser");  System.out.println(user.getName());
  user.setName("张三");

  单机的情况下,没毛病吧,我就想改下session里的用户信息。如果你这么放心的把sesson交给spring,那就等着测试部提问题吧。如果不退出或关闭浏览器的话,你会发现修改的用户信息,你刷新后,竟然没有生效!!!于是就想,spring-session是怎么保证session存储到redis上的呢?不卖关子了,redis通过hash类型存储session中的数据,session内的数据有变化时,会将修改的数据更新到redis上,为了提高效率,spring在filterchain结束的时候提交一次session数据到redis,而不是每次修改session数据都去提交一次。那spring怎么知道session的哪些数据变了呢?跟了下源码发下,只有在主动调用session的setAttribute和removeAttribute方法时,才会将修改的数据放到this.delta中,最后提交数据时,就是把这里的数据更新到redis的。所以为什么修改的user数据没有生效呢?因为没再次调用setAttribute方法,spring感知不到对象属性的变化!!坑爹啊~~自己修改了spring的提交逻辑,与旧的session进行了equals对比,把有变化的数据放入this.delta中,解决问题了?并没有!!最终发现UserBean重写了equals和Hash方法,只要用户ID相同,就返回true,我只想说,你大爷的!!

坑2:与其他系统融合的问题

  暂给我们的系统取名A系统,现有个B系统也要用B系统的一些数据,于是取了个名字叫“A与B系统的融合”。所谓A与B的融合,其实就是实现B系统的免登陆,并获取A系统的一些内存数据。于是,两个不同的系统,session就共享了...

   于是,当你在使用A系统的时候,很多莫名其妙的反序列的问题就出来了。为什么会报反序列化的错误?因为session里面有B系统的对象,但A系统根本就没有B系统的jar包。实现免登陆,可以走单点登录吧?想获取A系统的数据,可以让A系统提供接口吧?为什么要共享session?我也不知道了。

 

  

All in One到”分布式“迁移过程中的坑的更多相关文章

  1. 转载自lanceyan: 一致性hash和solr千万级数据分布式搜索引擎中的应用

    一致性hash和solr千万级数据分布式搜索引擎中的应用 互联网创业中大部分人都是草根创业,这个时候没有强劲的服务器,也没有钱去买很昂贵的海量数据库.在这样严峻的条件下,一批又一批的创业者从创业中获得 ...

  2. 分布式数据库中的Paxos 算法

    分布式数据库中的Paxos 算法 http://baike.baidu.com/link?url=ChmfvtXRZQl7X1VmRU6ypsmZ4b4MbQX1pelw_VenRLnFpq7rMvY ...

  3. 分布式服务框架 Zookeeper -- 管理分布式环境中的数据

    转自:http://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/index.html Zookeeper 分布式服务框架是 Apa ...

  4. ZooKeeper学习第五期--ZooKeeper管理分布式环境中的数据

    引言 本节本来是要介绍ZooKeeper的实现原理,但是ZooKeeper的原理比较复杂,它涉及到了paxos算法.Zab协议.通信协议等相关知识,理解起来比较抽象所以还需要借助一些应用场景,来帮我们 ...

  5. J2EE分布式事务中的提交、回滚方法调用异常。

    这个是昨天上班的时候,写一个后台程序的调试程序时碰到的问题,和项目经理纠结了一天,最后搞定了.于是今天上班正好闲着,花了几乎一天的时间去网上找各种相关的资料.目前了解的内容如此: 根据使用的weblo ...

  6. 分布式服务框架 Zookeeper -- 管理分布式环境中的数据(转载)

    本文转载自:http://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/ Zookeeper 分布式服务框架是 Apache Had ...

  7. 分布式服务框架 Zookeeper -- 管理分布式环境中的数据--转载

    原文:http://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/ Zookeeper 分布式服务框架是 Apache Hadoop ...

  8. 在分布式数据库中CAP原理CAP+BASE

    本篇博文的内容均来源于网络,本人只是整理,仅供学习! 一.关系型数据库 关系型数据库遵循ACID规则 事务在英文中是transaction,和现实世界中的交易很类似,它有如下四个特性: 1.A (At ...

  9. SQLServer2PostgreSQL迁移过程中的几个问题

    1.PostgreSQL 跨平台迁移工具Migration Toolkit的使用指南:http://www.enterprisedb.com/docs/en/8.4/mtkguide/Table%20 ...

随机推荐

  1. 7.Mongodb复制(副本集)

    1.复制 什么是复制 复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性,并可以保证数据的安全性 复制还允许从硬件故障和服务中断中恢复数据 为什么要复制 数据备份 数据灾难恢复 ...

  2. MySQL源码中的String

    适用于离开作用域就销毁的字符串.

  3. request.getparameter() 获取中文出现乱码 问题

    http请求是以ISO-8859-1的编码来传送url的 如果页面的content-type为utf-8,那么在发送请求时,会将字符转成utf-8后进行传送 如: 中 的UTF-8编码为:E4 B8 ...

  4. 「日常训练」Single-use Stones (CFR476D2D)

    题意(Codeforces 965D) $w$表示河的宽度,$l$表示青蛙所能跳的最远的距离,第二行的$w-1$个元素表示离河岸为$i$的地方有$a[i]$个石头,一个石头被踩两次,问最多有多少只青蛙 ...

  5. hdu5863 cjj's string game

    矩阵快速幂 #include<bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; const int MOD = ...

  6. 异常处理中try,else,finally含有return的情况解析

    直接看代码,拿到你的py下运行测试一下就 明白了. 例一: def f(): try: print() finally: print() print(f()) # 若注释掉finally内的retur ...

  7. 监控memcache服务

    监控memcache服务是否正常,模拟用户(web客户端)检测. 使用nc命令加上set/get来模拟检测,以及监控响应时间及命中率. #!/bin/bash #################### ...

  8. mongolass 中报 ($.content: "say Hi ~") ✖ (type: String)

    第二次报这个错了, 一直以为MongoDB的模型用的type 是 String, 一直报错, 找不到原因. // 留言模型1 exports.Comment = mongolass.model('Co ...

  9. DP入门(3)——多阶段决策问题

    多阶段决策问题,简单地说,每做一次决策就可以得到解的一部分,当所有决策做完之后,完整的解就“浮出水面”了.在回溯法中,每次决策对应于给一个结点产生新的子树,而解的生成过程对应一棵解答树,结点的层数就是 ...

  10. Elasticsearch 监控和部署

    Elasticsearch: ! [ https://elasticsearch.cn/book/elasticsearch_definitive_guide_2.x/_cluster_health. ...