首页 新闻 会员 周边 捐助

客户端并发请求webservice (纠结了好久,求抱大腿 ~.~ )

0
悬赏园豆:100 [已解决问题] 解决于 2010-11-17 12:10

  在客户端频繁并发的调用webservice时,高峰期导致访问webservice失败,重启IIS就可以了。

很简单的一个架构:C/S客户端--->webservice--->数据库

webservice程序:  一个提供数据库增删改的类--IDatabase

         web服务类

public class Service : System.Web.Services.WebService

{

       private IDbConnection dbcon;
       private IDatabase dbbase;

        /// 更新数据库
        public void updata(string updataCommandText)
        {
            IDbConnection con;
            //使用全局的IDbConnection
            con = dbcon;
            //新建一个IDbConnection
            con = dbbase.GetDbConnection("ConnectionString");
            dbbase.UpdataDb(updataCommandText, con);

        }

}

几个疑问的地方 想请教下各位,先谢过!!!

1.在数据库查询时,是共用一个全局数据库连接,还是 每次新建一个IDbConnection?? 如果每次新建一个连接,在web访问比较频繁的话,连接过多的话会造成服务器资源耗尽, 可是会这样吗,网上有人多是推荐去新建一个连接,但这样并不会造成连接过多的情况,可是多没说出其缘由,,,,待解答

2,看论坛里有人的博客说:webservice是基于多线程的,那么在更新数据库函数updata中新建线程来执行访问操作是不是多余的?

3,在客户端调用webservice的,是每次调用新建一个webservice连接,还是公用一个全局的webservice连接???  --我现在使用的是每次新建一个webservice连接,因为对于客户端这种构造一个webservice的开销是微不足道(当然这不是最好的处理)

 

 

问题补充: 另外public sealed class SqlConnection : DbConnection, ICloneable 继承了ICloneable,可找不到深拷贝的方法?
PJW726的主页 PJW726 | 初学一级 | 园豆:10
提问于:2010-11-13 18:47
< >
分享
最佳答案
0

UpdataDb完后需要把 DbConnection 及时关掉。

不知道你的 UpdataDb的一般耗时是多少,请使用 BeginExecute 来让出请求线程,Service也请写成服务端异步的。

如果这样,数据库连接仍然不够用,请考虑使用MSMQ,将多条Update语句组合到一起,批量向数据库提交更新请求。

收获园豆:30
Launcher | 高人七级 |园豆:45050 | 2010-11-14 11:55
每个连接多有及时close。 不是很耗时,只是调用很频繁。 所以没考虑用异步 因为请求必须即时响应,所以不能保存请求再批量处理
PJW726 | 园豆:10 (初学一级) | 2010-11-14 21:24
@PJW726:void updata,是无需返回值的,我不知道啥叫"即时"?从你的updata方法中,我也没看到DbConnection.Close()代码.即使你不采用批量处理,你也可以使用异步Service来空出托管线程,以提高并发数.webservice使用托管线程池来处理http请求,每核心默认250个线程.你应该综合的监视并发请求数和数据库活动连接数,以确定你的应用程序的瓶颈.你必须确认你的Service是每请求一个实例,还是多个请求共用一个实例.DbConnection不应该成为Service的成员变量,而应该是方法的局部变量.
Launcher | 园豆:45050 (高人七级) | 2010-11-15 09:28
即时指发送请求后必须短时间内回复。 我使用了using(new DbConnection()) 中间也未有耗时操作。只是调用web服务次数比较频繁。 --监视并发请求数和数据库活动连接数。 请求数我不知道如何监视,但是数据库连接我看下了,因为在连接参数中用了连接应用池, 高峰的时候有 40个连接
xiven | 园豆:49 (初学一级) | 2010-11-15 16:53
@xiven:使用 PerfMon.exe 来监视你的服务使用资源的情况.具体有哪些计数器,可以自己搜下,类似Request/Sec之类的;如果你的数据库连接高峰期是40个活动连接,那么你的性能瓶颈应该在Service的实现端.这说明你的Service阻塞了大部分的请求,并没有提交给数据库.这可能是由于带宽不足,服务执行时间过长,请求线程池过小所致.
Launcher | 园豆:45050 (高人七级) | 2010-11-19 09:31
其他回答(4)
0

建议新建连接,共享一个连接的话,并发时会有问题.

如果新建连接的话,连接过多顶多也就是数据库连接池耗尽而已.

收获园豆:10
I,Robot | 园豆:9783 (大侠五级) | 2010-11-13 20:58
我上面的访问失败,重启IIS 就可以了, 应该就是新建连接过多造成。多个客户端点会频繁的并发调用。。 连接池耗尽。
支持(0) 反对(0) PJW726 | 园豆:10 (初学一级) | 2010-11-13 23:43
数据库连接打开后及时关掉就行了,除非你的数据库操作耗时很长.否则一般情况下都不太可能出现连接池耗尽.
支持(0) 反对(0) I,Robot | 园豆:9783 (大侠五级) | 2010-11-14 09:35
0

1)如果Connection不会用于多线程,建议每一个Request 一个新连接。当End_Request就关闭。

2)我觉得Server在任何情况下都不使用。如果需要异步的话,应该由客户端用多线程调用WebService就可以。

3)没有所谓。

收获园豆:30
沉默的糕点 | 园豆:1786 (小虾三级) | 2010-11-13 23:03
你说的2中,是这个意思吗? 在web服务中不要使用多线程? 我问webservice是否基于多线程的,其实是指--比如有多个客户端同时调用通一个webservice,webservice会自动新建多线程处理响应。。
支持(0) 反对(0) PJW726 | 园豆:10 (初学一级) | 2010-11-13 23:48
多线程由IIS控制(Application Pool),这个无需要担心,只要设定正确就可以了。
支持(0) 反对(0) 沉默的糕点 | 园豆:1786 (小虾三级) | 2010-11-14 21:49
0

1、数据库有最大连接数限制,并发量过大达到上限就会报错,而且频繁的创建关闭连接也要很大代价,还是使用数据库连接池吧,可以在连接字符串中设置,也可以自己写一个。不过你说的情况应该是高峰期时候webservice的并发访问请求超出IIS所能承受的最大并发连接数,导致请求阻塞引起的吧。

2.觉得没有必要

3.webservice生成的代理类不是线程安全的吧,如果使用一个全局实例,存在多线程或异步调用的话,返回值处理应该会有问题

收获园豆:20
wgz | 园豆:1254 (小虾三级) | 2010-11-14 02:28
高峰期时候webservice的并发访问请求超出IIS所能承受的最大并发连接数,导致请求阻塞引起的吧。 每次多新建一个连接,但是使用数据库连接池,情况好点了,还是还是会有IIS 卡死... 怎么控制webservice的并发访问请求,有没类似 数据库连接池的方法?
支持(0) 反对(0) PJW726 | 园豆:10 (初学一级) | 2010-11-14 21:21
0

谢谢大家的回复,问题还未解决,我还是加点分吧,希望大家再帮看下

 

IIS还是很站内存,后面给web服务设置独立应用程序池,设置CPU占用50%自动回收,服务端在高峰期不再很卡,但是web调用失败,

还是附上测试写的代码吧,

webservice代码

    [WebMethod]
    public DataSet Selectdata(string selectCommandText)
    {
        DataSet Set = new DataSet();
        string sErr = "";
        if (!SelectDs(selectCommandText, Set, ref sErr)) return null;
        return Set;
    }
    [WebMethod]
    public void updatedata(string updataCommandText)
    {
        string sErr = "";
         UpDataDB(false, updataCommandText, "", ref sErr);
     }

    public IDbDataAdapter DbDat;
    public IDbTransaction DbTran;
    public Boolean SelectDs(string selectCommandText, DataSet dbSet, ref string sErr)
    {
        sErr = "";
        try
        {
            using (IDbConnection conn = DbConsole.DbCon(ConnectionString))
            {
                DbDat.SelectCommand.CommandText = selectCommandText;
                DbDat.SelectCommand.Connection = conn;
                dbSet.Clear();
                conn.Open();
                DbDat.Fill(dbSet);
            }
        }
        catch (SqlException sqlex)
        {
            sErr = sqlex.ToString();
            return false;
        }
        return true;
    }
    public Boolean UpDataDB(Boolean IsStarTran, string updataCommandText, string splitStr, ref string sErr)
    {
        try
        {
            if (String.IsNullOrEmpty(splitStr)) splitStr = "DBSplitStr";          //默认分隔符
            string[] sql = Regex.Split(updataCommandText, splitStr, RegexOptions.IgnoreCase);
            using (IDbConnection conn = DbConsole.DbCon(ConnectionString))
            {
                //绑定数据库连接和事务对象
                IDbCommand dbCom = DbDat.UpdateCommand;
                dbCom.Connection = conn;
                conn.Open();
                if (IsStarTran)
                {
                    DbTran = conn.BeginTransaction();
                    dbCom.Transaction = DbTran;
                }
                foreach (string sqlStr in sql)
                {
                    dbCom.CommandText = sqlStr;
                    dbCom.ExecuteNonQuery();
                }
                if (IsStarTran) DbTran.Commit();
            }
        }
        catch (SqlException sqlEx)
        {
            if (IsStarTran) DbTran.Rollback();
            sErr = sqlEx.ToString();
            return false;
        }
        catch (Exception Ex)
        {
            sErr += Ex.ToString();
            return false;
        }
        return true;
    }

客户端,用多个时钟new线程 不停调用web服务:
            timer3.Interval = 1000;
            timer3.Tick += new EventHandler((o, ev) => { new Thread(InsertAndUpdate).Start(); });
            timer3.Enabled = true;
        private void InsertAndUpdate()
        {
            try
            {
                localhost.Service server = new localhost.Service();
                server.Url = sUrl;
                server.updatedata("insert into Test(id,username,logintime,other,other1) values('00','22',getdate(),'" + Environment.MachineName + "','66')");
                server.updatedata("update Test set id='01' where id='00'");
                server.Selectdata("select *  from Test ");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

表Test(id,username,logintime,other,other1)  为测试用的一个表

收获园豆:10
xiven | 园豆:49 (初学一级) | 2010-11-15 17:03
上面的客户端(3个1000周期的时钟不停调用web)测试运行一段时间后,检查数据库连接数为54 个。 后面客户端每次调用webservice函数多是失败,跟踪未见报错。。 虽然执行server.updatedata("insert into Test(id,username,logintime,other,other1) values('00','22',getdate(),'" + Environment.MachineName + "','66')"); 可是数据库未见增加记录。。。刚开始运行一段时间webservice调用和数据库操作多是正常的。
支持(0) 反对(0) PJW726 | 园豆:10 (初学一级) | 2010-11-15 17:26
1.在XP,还是2003上测试的?XP下最大连接数为10, http://www.yimiju.com/articles/381.html这个连接可以修改最大并发连接数,要不放服务器上试试。 2.如果使用的是orale数据库的话,可以修改下oracle 的最大连接数http://hi.baidu.com/chenhj_brenda/blog/item/e810be2524ed2d39c895599e.html sqlserver应该也有的,找找看。 3.服务端的错误你catch后有进行日志记录吗? 4.可以在事件查看器中看看有没有错误提示
支持(0) 反对(0) wgz | 园豆:1254 (小虾三级) | 2010-11-15 20:29
2003系统, 数据库SQL, catch(consele。write()) w未见错误输出 事件查看器 不知
支持(0) 反对(0) PJW726 | 园豆:10 (初学一级) | 2010-11-15 22:49
[WebMethod] public void updatedata(string updataCommandText) { string sErr = ""; UpDataDB(false, updataCommandText, "", ref sErr); } 这段代码获取错误后,你没有进行后续的处理了,调试的时候先把catch去掉吧,要不就把sErr写到日志中。事件查看器在:我的电脑右键-》管理-》系统工具-》事件查看器-》应用程序。sqlserver也有设置命令的吧,查查看
支持(0) 反对(0) wgz | 园豆:1254 (小虾三级) | 2010-11-17 11:33
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册