请教板桥大哥及各位高手:J2EE项目的大数量查询及WebLogic的负载平衡问题

J2EE项目的大数量查询及WebLogic的负载平衡问题

在J道潜水很久了,很喜欢这里的研究氛围。由于最近刚刚接手了一个J2EE项目(我们公司第一次应用),在技术上不是很把握,所以今天注册了一个ID,向各位请教一下,恳请帮助、批评、指正。

项目背景:某市户籍管理系统;
技术方案:J2EE;WebLogic 7+Oracle 8.17;客户端采用Web

主要问题:
1、大数据量并发操作(主要针对查询)问题。由于数据库记录为百万级,而且并发客户端为200(600*33%)左右,所以这将是影响系统性能的瓶颈。
2、WebLogic的负载平衡问题。

拟定解决方案:

针对问题1:
A、建立一个ServerFacade(Session Bean),它为多个对象提供统一获取EJB Home和获取对象的接口;
B、降低事物级别为最低;
C、对于查询操作,不采用Entity Bean,而是采用Seesion Bean+DAO的模式;
D、采用模式2的JDBC驱动,对于WebLogic 7采用JDriver与Oracle客户端连接;
E、JSP和servlet尽量和EJB部署在同一台应用服务器中,尽量少用或不用HTTP Session;
F、在WebLogic服务器设置方面,不是很熟悉,但我想这一定与性能的提升息息相关,比如:高速缓存技术、域(field)分组、并发策略以及紧密关联缓存(eager relationship caching)等,还请大家指导。

针对问题2:
我完全没有负载平衡应用的经验,只是知道WebLogic可以实现,但是怎么实现请大家帮忙;另外,应用负载平衡,对于程序的开发阶段有什么要求?我的意思是:这是不是系统开发后期部署阶段的问题?

第一次发言,加之本人水平有限,不知道问题说清楚没有,还恳请大家,尤其是板桥大哥多帮忙。

这个问题很有高度,我本人对weblogic不是很熟,请其它兄弟帮忙解答,本人也能从中得到提高 谢谢

谢谢板桥大哥这么快就进行了回复。

对于这两个问题,我的当务之急是解决大数据量的性能问题,由于自己没有这方面的开发经验而项目又很紧,所以我把自己能想到的都列举出来了,请大家帮忙判断一下。对于第二个问题,我只是有所担心对开发阶段是否有影响(估计没有),真正到具体实施时,我想自己搞不定的话可以请BEA的工程师帮忙解决。

UP一下

刚才在开发中遇到一个问题,希望大家注意:

我们的程序中用到了java.sql.Connection中的public PreparedStatement prepareStatement(String s, int i, int j)方法,但是运行后系统报错不支持。查了一下WebLogic 7的文档,发现:Jdriver不完全支持JDBC 2.0规范,包括――

Class or Interface
Unsupported Methods

java.sql.Blob
public long position(Blob blob, long l)

public long position(byte abyte0[], long l)

java.sql.CallableStatement
public Array getArray(int i)

public Date getDate(int i, Calendar calendar)

public Object getObject(int i, Map map)

public Ref getRef(int i)

public Time getTime(int i, Calendar calendar)

public Timestamp getTimestamp(int i, Calendar calendar)

public void registerOutParameter(int i, int j, String s)

java.sql.Clob
public long position(String s, long l)

public long position(java.sql.Clob clob, long l)

java.sql.Connection
public java.sql.Statement createStatement(int i, int j)

public Map getTypeMap()

public CallableStatement prepareCall(String s, int i, int j)

public PreparedStatement prepareStatement(String s, int i, int j)

public void setTypeMap(Map map)

java.sql.DatabaseMetaData
public Connection getConnection()

public ResultSet getUDTs(String s, String s1, String s2, int ai[])

public boolean supportsBatchUpdates()

java.sql.PreparedStatement
public void addBatch()

public ResultSetMetaData getMetaData()

public void setArray(int i, Array array)

public void setNull(int i, int j, String s)

public void setRef(int i, Ref ref)

java.sql.ResultSet
public boolean absolute(int i)

public void afterLast()

public void beforeFirst()

public void cancelRowUpdates()

public void deleteRow()

public boolean first()

public Array getArray(int i)

public Array getArray(String s)

public int getConcurrency()

public int getFetchDirection()

public int getFetchSize()

public Object getObject(int i, Map map)

public Object getObject(String s, Map map)

public Ref getRef(int i)

public Ref getRef(String s)

public int getRow()

public Statement getStatement()

public int getType()

public void insertRow()

java.sql.ResultSet
(continued)
public boolean isAfterLast()

public boolean isBeforeFirst()

public boolean isFirst()

public boolean isLast()

public boolean last()

public void moveToCurrentRow()

public void moveToInsertRow()

public boolean previous()

public void refreshRow()

public boolean relative(int i)

public boolean rowDeleted()

public boolean rowInserted()

public boolean rowUpdated()

public void setFetchDirection(int i)

public void setFetchSize(int i)

public void updateAsciiStream(int i, InputStream inputstream, int j)

public void updateAsciiStream(String s, InputStream inputstream, int i)

public void updateBigDecimal(int i, BigDecimal bigdecimal)

public void updateBigDecimal(String s, BigDecimal bigdecimal)

public void updateBinaryStream(int i, InputStream inputstream, int j)

public void updateBinaryStream(String s, InputStream inputstream, int i)

public void updateBoolean(int i, boolean flag)

public void updateBoolean(String s, boolean flag)

public void updateByte(int i, byte byte0)

public void updateByte(String s, byte byte0)

public void updateBytes(int i, byte abyte0[])

public void updateBytes(String s, byte abyte0[])

java.sql.ResultSet
(continued)
public void updateCharacterStream(int i, Reader reader, int j)

public void updateCharacterStream(String s, Reader reader, int i)

public void updateDate(int i, Date date)

public void updateDate(String s, Date date)

public void updateDouble(int i, double d)

public void updateDouble(String s, double d)

public void updateFloat(int i, float f)

public void updateFloat(String s, float f)

public void updateInt(int i, int j)

public void updateInt(String s, int i)

public void updateLong(int i, long l)

public void updateLong(String s, long l)

public void updateNull(int i)

public void updateNull(String s)

public void updateObject(int i, Object obj)

public void updateObject(int i, Object obj, int j)

public void updateObject(String s, Object obj)

public void updateObject(String s, Object obj, int i)

public void updateRow()

public void updateShort(int i, short word0)

public void updateShort(String s, short word0)

public void updateString(int i, String s)

public void updateString(String s, String s1)

public void updateTime(int i, Time time)

public void updateTime(String s, Time time)

public void updateTimestamp(int i, Timestamp timestamp)

public void updateTimestamp(String s, Timestamp timestamp)

java.sql.ResultSetMetaData
public String getColumnClassName(int i)

看来这是执行效率和编程效率的矛盾,想要更高的执行效率就要牺牲编程的灵活性……唉,本来以为通过JDriver+Oracle客户端(OCI方式)会取得比Oracle Thin Driver更好的效果,但是现在看来似乎又要放弃了(因为我们自己的一套基类无法使用),郁闷啊!!大家有什么好的替代方法吗?

在一篇文章看到,提升EJB性能的方法之一

“用"transient"关键字声明不必要的数据变量,替代以前的"public"、"private"等,避免不必要的数据变量占用网络资源。

示例:

public class DemoCMP implements EntityBean {
transient EntityContext entCtx;
transient InitialContext initCtx;
public String id;
public String description;

}

不知道作用如何,是否可行?

transient 是针对 Serializable 来说的。
因为在网络上传输对象要将对象 串化.
如果将对象不需要保存的数据申明为 transient,那么串化系统就会丢掉对象中的这些属性。这样对象的 size 就会小一些,相对占用的网络资源就会小。

希望能帮到你

Interesting project, though I think for only 200 concurrent users and primary activities on query( not update), I don't perf tuning will be too complicated.

If my understanding is correct, your primary tuning focus should be on database, not app server. if you can affort a large SGA in oracle, do it.
Of course, you should consider using prepared statements, assume the variation of sql syntax are limited.

I think you should try oracle thin driver, it has been working very well for me to support thousands of concurrent users and prepared statements.

If you can limited the return record size for each query, then you have less thing to concern, if you can't force users to give narrow criteria, then you need some control to do incremental fetching.

Too much dynamic allocation/deallocation will be your enemy, for sure no EJB here, you just want to see the data, not triggering rules.

Before you go for clustering, try to identity whether your system is cpu bound, DB bound or memory bound.

Just my two cents.

Good luck

BTW, clustering setup is straight forward in WL7, if you just need load balancing. If you need fail-over, and you have to use stateful design, then you have more work to do. It would be challange to even most BEA support engineer. Do it earlier.

Jevang老兄终于出手了,Jevang是weblogic方面的专家,曾经从事过weblogic server的开发。

我们的程序中用到了java.sql.Connection中的public PreparedStatement prepareStatement(String s, int i, int j)方法,但是运行后系统报错不支持。查了一下WebLogic 7的文档,发现:Jdriver不完全支持JDBC 2.0规范,包括――


不是吧,你 用的是什么驱动呀,weblogic自己的驱动是第四类型的驱动,呵呵

首先感谢Jevang的回复!你的建议很好,在一个项目没有大面积的铺开之前,有你这样的高人指导一下,提前预判未知的技术风险,对我这样的J2EE新手很有帮助。

正如你说的,我们首先进行的工作就是进行数据库的调优。但是现在我们在数据库的设计方面有一个问题还在犹豫不绝。我们的系统提供户籍信息的输入功能,主要针对一个人员表,由于信息的输入将集中在一段时间,比如一个月,输入几百万条信息,这段期间将不会进行大量的查询操作。我们首先想把人员表拆分成根据区或街道划分的子表,但是由于系统中将有很多组合条件和动态查询,多表操作将会很麻烦。现在的方案是建一些临时表,等数据采集基本结束后一起倒到一个人员表中。……不知是否可行?

另外,你提到了应用oracle thin driver。通过我们这几天做得测试来看确实oracle thin driver相对快一些。但是也发现一个现象,采用OCI方式第一次连接比较慢,但是随后的连接就很快(不过还是没有oracle thin driver快)。这是不是说明OCI的潜力很大??我们只测验50万条数据的查询和分页,还有待观察。另外,为什么我看的很多资料上都说OCI的方式比较快呢?

关于集群,今天与BEA的工程师通过电话聊了这个问题,按照他的说法,在开发阶段可以不考虑这方面的问题,万一有问题,改动的地方也很少。当然,我们主要需要的是load balancing 。

总之,谢谢你中肯的建议!还有什么好的建议请谈一谈小弟洗耳恭听。

richardluopeng ,我之所以说JDRIVER不支持JDBC 2,一是我们确实碰到了这种情况,二是BEA的文档就是怎么说的。大体的意思是:WEBLOGIC完全支持JDBC 2规范,但是JDBC不完全支持。

In theory thin client is a java impl of OCI, in oracle tech doc, they claim 10% faster. You can ignore initial connect time as for sure you will use some kind of connection pooling.

In one of the tax project I involved in the past, they have millions of tax record, I think they always stored it using a single table. If inserting just a one time action?If that's the case, one trade off can be made is use less indexes during heavy data inserting phase; then you can apply indexes back to speed up different queries.

assume you need enter 5 million records in 20 days, 8hr a day, then a given minute rate is >500 record/min. Not a big deal assume you don't have to lock too many other reference resources during a single transaction.

在开发阶段需要考虑Cluster的问题,实际就是需要考虑架构的问题,因为你使用的是J2EE,目前J2EE在cluster方面没有统一的标准,因此各个产品支持可能不一样,主要就是围绕JNDI的cluster的方法不同。当然这些原理你不必了解,但是需要知道你在应用中使用的一些技术可能不适合Cluster场合,本身就是矛盾的。

比如 Singleton模式在CLuster下就要避免,如果你的系统的关键部分使用了Singleton,那么一旦移植到CLuster下,你得修改你的系统关键部分,那是一件可怕的事情。

还有http seession对于cluster也是不利,会降低性能,那么你的系统就要尽量使用无状态的bean。

你可以找些这方面资料参考一下。