该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2005-12-08
群集如果只考虑“负载平衡”而不考虑“灾难恢复”(就是说不需要在各个节点间拷贝session的状态),我认为还是可以在session中存些信息的,就是当负载大的时候,会比较消内存。理想情况下,session中不放任何用户状态相关的东西,这样水平伸缩性会很好的。
|
|
返回顶楼 | |
发表时间:2005-12-08
robbin 写道 lingcm 写道 我现在所在的项目就有这样的问题,数据从数据库里面取出来的数据很多情况都是放在session里面的!主要原因是一般的功能都有XXXXinput.jsp , XXXXdetail.jsp , XXXXconfirm.jsp , XXXXack.jsp 因为上面的页面都有可能出错,所以很多list如果放到request里面出错后将会丢失(需要重新到数据库里面去捞)
现在项目里面的做法是,把这些可能出错回来还要显示的数据都塞到session里面。然后每个function都有一个functionID号,在每个function 的init的时候会remove掉所有以这个functionId相关的session中的值,(当然这个是在框架里面封装了,只要调用removeAllfuncationVariable()方法就可以了)。但是这样会使用户的session迅速膨胀。用户如果能按照正常流程跑还行,因为每个function结束后都会把用户带到这个这个function的init 方法去清session的,但是用户如果在中途退出我们就没有办法控制了! 另外公司里面有些其它项目就禁止使用session,所有的东西都是放到resquest里面然后每次出错什么的都是重新到数据库里面再捞一次数据。不知道各位在项目里面是怎么做的?有没有个平衡点的?有没有什么心得可以共享的 这样用法,负载一大,应用服务器就得out of memory。根据我多个项目调优和解决性能故障的经验,session里面除了放用户登陆信息之外,其他什么都不应该放。就像Tapestry那样在session中保持状态都放得太多了,做群集的时候很容易出问题。 至于你说的什么request出错,那是解决方法不对,不是request不行。 我也倾向于Stateless ,而不是stateful. 如果有状态,最好放在客户端。比如, url parameter, hidden input. 就是采用request的方法。 如果数据确实太多,不可能放在页面上,那么要考虑的是,使用通用数据缓存,而不是使用Session缓存。 通用数据缓存的好处,在于所有用户都可以共享数据,增加命中率。而且可以统一管理。而不用在Session Listener里面。(也许楼主可以考虑Session Listener控制session 数据的大小) Session里面应该放什么东西?只应该放 本用户特有的东西。除了权限相关,还有用户自定义的配置,比如layout, favour之类。这些东西放在session的好处是,当session失效的时候,这些东西自动回收。 nkoffee 写道 web应用中很难避免一些长用户类型的事务, 比如新建某个东西要经历若干个页面,类似于app中的wizard, 面对这样的问题,也很难不用session来存放数据, 原则是尽量避免这样的长事务,尽量避免往session里塞东西, 无法避免的话就要注意好管理这些数据。 多说无益,建议你看一下atleap里面的的BaseAction,参考一下它的存取session的数据并使用。 另外虽然对session数据的使用要分外小心,但是并不说明session的使用只能局限于用户登陆信息 这类多步骤的长事务(这个事务不是db transaction,而是一个完整业务的意思), 应该选择使用 持久化 来保存每一步数据,而不是session memory。这样更加友好健壮。 因为即使cluster session memory的东西,也会失效。 而持久化,用户第二天来的时候,也可以继续恢复到上次的步骤。 |
|
返回顶楼 | |
发表时间:2005-12-08
pageFlow?用session?
我更相信是你们的需求或设计有问题. |
|
返回顶楼 | |
发表时间:2005-12-08
引用 我也倾向于Stateless ,而不是stateful. 如果有状态,最好放在客户端。比如, url parameter, hidden input. 就是采用request的方法。 如果数据确实太多,不可能放在页面上,那么要考虑的是,使用通用数据缓存,而不是使用Session缓存。 通用数据缓存的好处,在于所有用户都可以共享数据,增加命中率。而且可以统一管理。而不用在Session Listener里面。(也许楼主可以考虑Session Listener控制session 数据的大小) Session里面应该放什么东西?只应该放 本用户特有的东西。除了权限相关,还有用户自定义的配置,比如layout, favour之类。这些东西放在session的好处是,当session失效的时候,这些东西自动回收。 buaawhl 你这样的做法我不能赞同!把这些信息放到客户端会带来安全问题,项目里面就碰到这样的安全问题,客户可以通过工具修改你hidden里面的值,比如你给用户选择的是性别选项,理想情况是“M”表示男 “F”表示女你用的radio button不过用户可以用工具改成不男不女,这样的数据你是放进数据库还是? 当然上面说的男女还是理想情况,如果这些数据都是放在数据库里面的,比如说国家。可能你定义了100个可能让用户选择,那你是否要在server端验证用户选择的是否是在这100种情况内?他通过工具改成第101种情况提交你怎么办? 这些可能还不是极端的还有可能是你里面的用户a和用户b权限不一样,你a的权限只能看到前面的50条 用户b只能看到后面的50条。当然你在前面的页面就已经取出了a的前50条记录,但是你怎么保证a用户提交的数据不会是第51种情况?这些情况一定要在server端再一次验证,如果这些list是放在request里面那你一定要重新到数据库里面重新根据上面的条件load一次,如果放在session中就可以直接到session中取出来这个list然后check一下用户提交的是否在以前的list中,不在就throw一个错误信息出来。 所以我感觉一个原则是能不用session的尽量不用,但是我上面的这种情况怎么办呢?用session(方便很多),用request要复杂很多! 所以上面buaawhl 的做法我认为会带来很多安全隐患,要是做安全了你还是需要每次在server端做check,这样你还是做不到Stateless 。得不偿失! |
|
返回顶楼 | |
发表时间:2005-12-08
huazii 写道 pageFlow?用session?
我更相信是你们的需求或设计有问题. 要是需求就是这样的!你怎么办?不至于和客户说你的需求有问题吧! 设计我现在也说不上话(好像是一帮印度哥们设计的),我只是用了后感觉到有这个问题,只能说以后自己做项目的时候注意这些情况。对于robbin刚才说的pageFlow很感兴趣。以前一直没有看过,不知能否完美的解决我的问题。 |
|
返回顶楼 | |
发表时间:2005-12-08
lingcm 写道 huazii 写道 pageFlow?用session?
我更相信是你们的需求或设计有问题. 要是需求就是这样的!你怎么办?不至于和客户说你的需求有问题吧! 设计我现在也说不上话(好像是一帮印度哥们设计的),我只是用了后感觉到有这个问题,只能说以后自己做项目的时候注意这些情况。对于robbin刚才说的pageFlow很感兴趣。以前一直没有看过,不知能否完美的解决我的问题。 其实robbin已经说了,如果的确是属于pageFlow的范畴,而且这样的case很多,就要用pageFlow的思想来做,这也是为什么还有 spring webflow这个项目的原因,当然你也可以去参考一下别的webflow http://opensource2.atlassian.com/confluence/spring/display/WEBFLOW/Home 如果这样的case不多,而且web框架是用struts的,我在前面已经说了,建议你去看一下atleap的做法,我想你会有收获的 |
|
返回顶楼 | |
发表时间:2005-12-08
lingcm 写道 引用 我也倾向于Stateless ,而不是stateful. 如果有状态,最好放在客户端。比如, url parameter, hidden input. 就是采用request的方法。 如果数据确实太多,不可能放在页面上,那么要考虑的是,使用通用数据缓存,而不是使用Session缓存。 通用数据缓存的好处,在于所有用户都可以共享数据,增加命中率。而且可以统一管理。而不用在Session Listener里面。(也许楼主可以考虑Session Listener控制session 数据的大小) Session里面应该放什么东西?只应该放 本用户特有的东西。除了权限相关,还有用户自定义的配置,比如layout, favour之类。这些东西放在session的好处是,当session失效的时候,这些东西自动回收。 buaawhl 你这样的做法我不能赞同!把这些信息放到客户端会带来安全问题,项目里面就碰到这样的安全问题,客户可以通过工具修改你hidden里面的值,比如你给用户选择的是性别选项,理想情况是“M”表示男 “F”表示女你用的radio button不过用户可以用工具改成不男不女,这样的数据你是放进数据库还是? 当然上面说的男女还是理想情况,如果这些数据都是放在数据库里面的,比如说国家。可能你定义了100个可能让用户选择,那你是否要在server端验证用户选择的是否是在这100种情况内?他通过工具改成第101种情况提交你怎么办? 这些可能还不是极端的还有可能是你里面的用户a和用户b权限不一样,你a的权限只能看到前面的50条 用户b只能看到后面的50条。当然你在前面的页面就已经取出了a的前50条记录,但是你怎么保证a用户提交的数据不会是第51种情况?这些情况一定要在server端再一次验证,如果这些list是放在request里面那你一定要重新到数据库里面重新根据上面的条件load一次,如果放在session中就可以直接到session中取出来这个list然后check一下用户提交的是否在以前的list中,不在就throw一个错误信息出来。 所以我感觉一个原则是能不用session的尽量不用,但是我上面的这种情况怎么办呢?用session(方便很多),用request要复杂很多! 所以上面buaawhl 的做法我认为会带来很多安全隐患,要是做安全了你还是需要每次在server端做check,这样你还是做不到Stateless 。得不偿失! 奇怪,信息不放在客户端,你就不需要在server端进行数据检查了? 根本不需要什么客户端,随便一个http client就可以仿造数据包攻击你的server。还提什么安全性? 另外,如果是保密的数据,谁让你放到 客户端了? 我说的是,在页面放置State信息。啥叫State信息?就是标志你现在的步骤step id等。PageFlow, Continuation也是采用这样的手法。 至于说这个state信息量的大小,看你的id的长度。如果这个state信息也需要保密,encoding一下就行了。甚至可以自定义encoding。 后面的数据查询例子,也比较奇怪。本来我建议的是使用 通用数据缓存。 从你的表述来看,你的这个 用户权限条件,应该是作为SQL的一个条件?如果是这样,那么, 缓存中的 Key 就是SQL。对应的结果,本来就是该用户的结果,别的用户怎么可能看到? 如果这个 用户权限条件 是在数据库选取结果后,进行过滤。那么通用缓存这种方式,不是更好?两个用户都选了同样的1000条数据,然后根据权限条件过滤,A看到了其中500个,B看到了其中600个。缓存中的这1000条数据,命中率不是很高? 总之,感觉你随便说的这几个例子,和这些话,似乎没有经过严肃思考,就脱口而出,图个爽。哪怕给出类似的具体一点的例子(不需要暴露真实程序),从page到db, db到page,也有点针对性。 另外,大家提出的所谓的Page Flow,Web Flow, Continuation 更是一种Session State 的 重量级误用。这些server side flow的实现,无一例外,都需要在 server side session 中维护状态,一个小状态机。 什么时候,需要用它们?企业内部网,用户量少,交互步骤复杂的情况。那还不如用Ajax。 与其使用这种专业重量级的session based framework,还不如 楼主 描述的这种自订制的 session 使用方案。至少更加可控制一些。 所有的这种Session state 使用,都有一个著名的 back button 问题。 通用数据缓存的做法,能够避免这个问题。做到每一次request 都是上下文无关的,而又不影响效率。 我建议避免 session,也是为了与HTTP Server的stateless设计初衷保持高度一致。Apache HTTPD就不直接支持Session。但是,session 在某些情况下,却又不能少。 至于Session Replication in Cluster。 这是我的建议。如果不希望Session里面的数据,被复制到其他server node,那么可以简单的 不支持 serializable,或者把不需要复制的属性,声明为transient,这样就不会被传送。 其他node获取这个数据的时候,要进行null check,会发现对应的数据项是null, 然后就可以针对这个进行处理,从数据库中同步之类,建立本地local cache. 另,to nkoffee, 这种情况下,atleap 是咋做的?能否提点一二? |
|
返回顶楼 | |
发表时间:2005-12-08
引用 这样用法,负载一大,应用服务器就得out of memory。根据我多个项目调优和解决性能故障的经验,session里面除了放用户登陆信息之外,其他什么都不应该放。就像Tapestry那样在session中保持状态都放得太多了,做群集的时候很容易出问题。 robbin说的我基本是赞同的. 不单单做群集,就是一个单机也是有问题. 但有的时候用一下session也是无妨. 比如: 分页查询. 我根据用户的查询条件最多只会找出30~50条记录, 又要分页(25条/页),此时我就把它放在session里,这样算下来,一个用户在session里的记录最多有700~800条,服务器的负载还是可以的. 所以,我觉得不是用不用, 而是怎么用,怎么控制. |
|
返回顶楼 | |
发表时间:2005-12-08
buaawhl 写道 放入到session里面,会有back button的问题。因为已经假设了一个步骤顺序,需要一个确定的上下文。 我前面一直都是直接放到session里面做的!不太清楚buaawhl指的back button 问题指的是什么? |
|
返回顶楼 | |
发表时间:2005-12-08
lingcm 写道 buaawhl 写道 放入到session里面,会有back button的问题。因为已经假设了一个步骤顺序,需要一个确定的上下文。 我前面一直都是直接放到session里面做的!不太清楚buaawhl指的back button 问题指的是什么? for back button 浏览器上的回退按钮。。 Spring Web Flow 的 http://opensource2.atlassian.com/confluence/spring/display/WEBFLOW/Is+Spring+Web+Flow+Right+for+You%3F 引用 Avoid the Browser Buttons As explained above, Spring web flow is targetted at situations where you have controlled navigation and a real flow. This is completely different from a web site supporting free navigation. This being said, it is often acceptable, especially for intranet applications, to inform the user he / she cannot use the browser buttons and should stick to the controls (links, buttons, ...) offered by the application itself. It's hard to technically disable the back button, so most of the time the web application will just run in a popup window with no browser buttons being displayed. In an intranet setting, it could also be possible to roll out a specialized browser that really prevents use of the back button. Tapestry 的 http://www.theserverside.com/news/thread.tss?thread_id=32925 引用 Tapestry, Seaside, and Cocoon... ...having been doing this for years. Tapestry maintains state and page flow is easy; you have to disable the back button yourself. Cocoon and Seaside are continuations-based systems where this kind of scripted flow is fundamental from day one. --- 除了Back Button,还可以举个明显的比较极端的例子,来说明session state的不可靠。当然实际上,几乎没有人这么使用。 1. 你打开browser A, 访问 init page 查询, 这个时候session 里面存放了50条记录。 2. 你从Browser A new 一个新的browser B, 这个时候, browser A 和 browser B 共享一个session。 3. 你在 browser B的init page 用不同的条件查询,这个时候,session里面替换上了 30条记录。 4. 你回到browser A,继续Check,这时候,使用的是那30条记录。 --------------- 如果使用通用数据缓存,就不会有这个问题。因为不同的查询,具有不同的Query Key,不会冲突。多少个 共享session 的 browser都不会冲突。 |
|
返回顶楼 | |