|
该帖已经被评为精华帖
|
|
|---|---|
| 作者 | 正文 |
|
时间: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 写道 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 是咋做的?能否提点一二? 不好意思buaawhl,我刚才没有完全理解你的意思。没有理解你刚才说的状态放到client端是什么意思。就错误的理解成你把用户选择后的信息再送到client,用hidden来存放,等到最后一步confirm的时候再一次提交。再次道歉!其实我得问题就是如果不用session多页面之间数据共享的问题,可能也就是上面robbin说说的用web flow来解决比较好。 还有我上面说的用户权限的问题不是buaawhl兄理解的这样,我在数据库里面取了100条记录里面的前50条记录给用户a,当然用户a只能看到这前50条记录没有问题。 我的意思是如果这个取记录是在init的时候取出来的,然后用户取了其中的一个(当然client端可以作弊)。client端提交数据的时候可能提交的这条数据并不在我先前给他选择的50条内。应为init和这次的check不在同一个请求里面也就是不在同一个request里面所以这样的数据我是在init的时候取好后直接放到session里面供下次check的时候使用,还是在check的时候再到数据库里面按照当时init时候的条件再到数据库里面把那50条记录load一次,然后再check用户提交的数据在不在我刚才给他的50条里面!(觉得buaawhl说的缓存sql语句本质和我后面说的情况应该一样,再到数据库里面load一次,不过把sql语句放到client端感觉不好,再考虑加密就更复杂了) 其实我主要想说的是用session的话可以很简单的解决这样的check问题,如果不用session就要增加负责程度,不知道这样的复杂到底值不值得。 |
|
| 返回顶楼 | |
|
时间:2005-12-08
lingcm 写道 不好意思buaawhl,我刚才没有完全理解你的意思。没有理解你刚才说的状态放到client端是什么意思。就错误的理解成你把用户选择后的信息再送到client,用hidden来存放,等到最后一步confirm的时候再一次提交。再次道歉!其实我得问题就是如果不用session多页面之间数据共享的问题,可能也就是上面robbin说说的用web flow来解决比较好。 还有我上面说的用户权限的问题不是buaawhl兄理解的这样,我在数据库里面取了100条记录里面的前50条记录给用户a,当然用户a只能看到这前50条记录没有问题。 我的意思是如果这个取记录是在init的时候取出来的,然后用户取了其中的一个(当然client端可以作弊)。client端提交数据的时候可能提交的这条数据并不在我先前给他选择的50条内。应为init和这次的check不在同一个请求里面也就是不在同一个request里面所以这样的数据我是在init的时候取好后直接放到session里面供下次check的时候使用,还是在check的时候再到数据库里面按照当时init时候的条件再到数据库里面把那50条记录load一次,然后再check用户提交的数据在不在我刚才给他的50条里面!(觉得buaawhl说的缓存sql语句本质和我后面说的情况应该一样,再到数据库里面load一次,不过把sql语句放到client端感觉不好,再考虑加密就更复杂了) 其实我主要想说的是用session的话可以很简单的解决这样的check问题,如果不用session就要增加负责程度,不知道这样的复杂到底值不值得。 我前面说了,使用Web Flow,和你描述的这种Session 使用方法没有本质区别。Web Flow也是替你把状态数据保存在session里面,而且它很难分辨该放什么,不放什么,也许一股脑全都放进去了。你自己来控制,可能更好一些。更清晰,更有效。 1. init的时候取好后直接放到session里面供下次check的时候使用 这个时候,你可以选择把选出来的数据,放入到 session 里面,还是放入到 通用数据缓存里面。 放入到session里面,会有back button的问题。因为已经假设了一个步骤顺序,需要一个确定的上下文。 放入到通用数据缓存,没有这个问题。要考虑到用什么作为 cache key。这里的cache key 应该是这个 Query Key (SQL, parameter, 分段信息等) 2. 在check的时候再到数据库里面按照当时init时候的条件再到数据库里面把那50条记录load一次,然后再check用户提交的数据在不在我刚才给他的50条里面 如果这个时候配置了 通用数据缓存,这个query 发到数据库之前,是直接从缓存中把结果取出来。 而且这种做法更加透明。business layer不需要显式的操作cache。这是在DAO层配置处理的。 而你使用session的时候,business layer 或者action layer 至少需要显式的操作session。侵入性较强。 使用Web Flow 的主要好处就是,解除了 显式操作session代码的侵入。代价就是潜在的heavy load session state. |
|
| 返回顶楼 | |








