SqlServerProxy的一些资料

SqlServerProxy的一些资料

下载地址:http://files.cnblogs.com/files/lyhabc/SqlServerProxy.rar

1、特性及实现原理

SqlServerProxy 特性介绍:

#-------#--------------------------------------------------------------------------------------#
|特性 |不需要版本升级就兼容SQL Server 2000 到 SQL Server 2014的所有版本。 |
|-------|--------------------------------------------------------------------------------------|
|特性2 |开箱即用:只需简单配置一下就能开始使用。 |
|-------|--------------------------------------------------------------------------------------|
|特性3 |内置命令能查看历史、实时、单个客户端的通信量、请求数、事务数等。 |
|-------|--------------------------------------------------------------------------------------|
|特性4 |开放请求分发处理接口,可基于业务需求自己定制,默认提供一个基于正则表达式匹配的实现。 |
#-------#--------------------------------------------------------------------------------------#

SqlServerProxy 实现原理

Proxy能解析SQLServer通信采用的TDS协议内容,因而能再次封装分发客户端的请求。但是,不负责数据同步,需要采用复制等技术来数据同步。没有分布式事务,只在通信层工作,不会往数据库中添加任何东西,还开放执行请求内容记录接口,方便对执行内容进行审计。

SqlServerProxy的其它说明:

不支持客户端连接时的加密选项为True,就是连接字符串中“Encrypt=True”,必须为False。

暂不支持使用TDS 4.2协议的客户端连接,TDS 4.2作为早期与Sybase兼容的通信协议,已很少使用。

使用MARS(多活动结果集)能正常连接到proxy,也能统计通信量信息,但暂不支持请求分发,将来会实现。

将请求分发到从服务器时,使用的上下文数据库是请求会话在主服务器上的上下文数据库名,如需不同名称,需要定制"ISlaveProvider"接口,详见“实践手册”。



最新版下载地址

http://www.projky.com/downloads/3a382709-d680-476c-853d-dc3af5c625de/SqlServerProxy.zip

最新版对.NET Framework版本要求降到了.NET 4,现在支持Windows XP和Windows Server 2003了,详见《安装及3分钟快速体验.txt》。



正则测试器



2、配置手册

1、“dbServers.xml” 配置SqlServerProxy监听的端口、主服务器从服务器的连接地址信息。
<akuma>\<proxys>下配置服务监听的端口,可以是IPV4或者IPV6的地址,还可包含多个监听地址。测试时,将测试程序的连接字符串修改为监听地址及端口就ok了。
<akuma>\<master>配置主服务器的IP地址及端口。该地址可为IPV4或IPV6地址,只能包含一个元素。权重必须位于0~10之间(包括0和10)。
<akuma>\<slaves>下配置从服务器的IP地址及端口。可包含任意个<slave>元素。
<akuma>\<heartbeat>从服务器心跳检测,心跳检测执行时采用的AppName为“SqlServerProxy Heartbeat”。

该配置文件只会在启动时加载一次,修改后必须重启服务才能生效。

2、“balanceRules.xml” 配置当客户端的SQL请求或Rpc请求到来时,将依据本配置决定是否将请求分发到从服务器。
所有的规则内容都是正在表达式,不允许为空。可将事务中的查询也分发到从服务器,但这要业务需求允许才可以。
reject规则:如果匹配成功,请求就会发送到主服务器。
accept规则:如果匹配成功,将按权重将请求发送到主服务器或者从服务器。
<akuma>\<sqlbatch>匹配无参的sql查询或参数化查询生成的语句(内部是执行sp_executesql存储过程,此规则匹配存储过程参数“@statement”)。-->
<akuma>\<rpcbatch>匹配的是Rpc请求。

特别提醒1:事务是不能够在主服务器开始再到从服务器结束的。必须尽量在主服务器开始和结束。对于“begin tran ..... commit tran”开始和结束都在一起的sql语句可以分发到从服务器,但对于先在主服务器执行“begin tran”再到从服务器执行“commit tran”的请求,客户端会报错。

特别提醒2:因为是采用正则表达式进行匹配,每个请求都要应用,所以配置的正则表达式必须注重效率,以免导致请求反应速度下降。

规则示例1:

<appname>
<reject transaction="All" ignorecase="true">^Microsoft SQL Server Management Studio|^SQL Server Profiler</reject>
</appname>

意味着无论是否在事务下(transaction="All"),忽略大小写(ignorecase="true"),凡是客户端应用程序名以"Microsoft SQL Server Management Studio"或"SQL Server Profiler"开头的请求都应该发送到主服务器。

规则示例2:

<statement>
<!-- 排除改变数据、修改会话变量等-->
<reject>insert|update|delete|begin|save|commit|rollback|create|alter|drop|truncate|set|#|##|exec|execute</reject>
<accept transaction="false" ignorecase="true">\bSELECT\b</accept>
</statement>

reject项意味着无论是否在事务下(默认的),忽略大小写(默认的),凡是包含关键字“insert|update|delete|begin|save|commit|rollback|create|alter|drop|truncate|set|#|##|exec|execute”的语句请求都应该发送到主服务器。
accept项意味着不在事务下(transaction="false"),忽略大小写,且包含“SELECT”单词的语句请求可分发到从服务器。

匹配顺序[hostname] -> [clientendpoint] -> [appname] -> [loginname] -> [dbname] -> [statement]
匹配结果: 按匹配顺序,先应用reject规则,如果任何一条reject匹配成功,对应的请求将只发送到主服务器。 然后,同样按匹配顺序,再应用accept规则,如果任何一条accept匹配成功,对应的请求将发送到从服务器。 可同时并存任意条reject或accept规则。

该配置文件修改后不必重启服务,而是实时生效。

3、 “SqlServerProxy.exe.config” 配置解析接口实现类的配置文件。SqlServerProxy.exe 服务启动时会读取该文件,如果解析失败,将不能正常使用服务。
IHeartbeat 接口即心跳检测接口,只检测从服务器。
IBatchLog 接口即请求执行记录接口,只记录Sql请求和Rpc请求,接口参数将包含执行sql的语句和rpc名称参数值等信息,可以单独实现该接口来审计通过SqlServerProxy的执行记录。
IRunLog 程序运行日志接口,包含客户端连接记录等。
ISessionLog 客户端和服务器响应时发送的网络包内容。
ISlaveProvider 接口即根据执行的Sql语句和rpc请求内容,选择从服务器的接口,决定读写分离,最为核心。默认提供了一个基于正则表达式的实现,但特定业务通过该接口定制,将能获得最大性能。

该配置文件修改后必须重启服务才能生效。

4、“Akuma.Imp.config” 配置默认的IBatchLog、IRunLog、ISessionLog记录的日志目录,和记录等级。

调整目录示例:
比如:<file value="${ALLUSERSPROFILE}\SqlServerProxy\apprun.log" /> 在本测试机上就是“C:\Users\All Users\SqlServerProxy\apprun.log”文件。需要将日志文件移动到“D:”下,就可以更改为:<file value="D:\Logs\SqlServerProxy\apprun.log" />

调整记录等级能让更多或更少记录被记下来。ISessionLog 和 IBatchLog 默认实现必须为“All”或“Debug”级别才记录,默认不记录。
调整记录等级示例:
<logger name="Akuma.Imp.IBatchLogDefault.BatchLog">
<level value="WARN" />
<appender-ref ref="BatchLogFileAppender" />
</logger>
更改为要记录请求日志内容:
<logger name="Akuma.Imp.IBatchLogDefault.BatchLog">
<level value="ALL" />
<appender-ref ref="BatchLogFileAppender" />
</logger>

该配置文件修改后必须重启服务才能生效。



3、安装及3分钟快速体验

SqlServerProxy 环境要求:

.NET 4 Framework,.NET 3.5 Framework(两个同时装,现在支持Windows XP和Windows Server 2003了)。

安装:运行解压后的“InstallSvc.bat”,允许管理员权限即能成功安装,并自动启动SqlServerProxy服务。

卸载:运行解压后的“UninstallSvc.bat”,允许管理员权限即能成功卸载。

3分钟快速体验:

#-----------#-----------------#------#------------------#--------------#
| |ip地址 |端口 | 机器名 |SQLServer版本 |
|-----------|-----------------|------|------------------|--------------|
|主服务器 |192.168.201.134 |1433 |WIN-D5FC592I20C |08R2 |
|-----------|-----------------|------|------------------|--------------|
|从服务器 |192.168.201.1 |1433 | AKUMA-PC |08R2 |
#-----------#-----------------#------#------------------#--------------#
从服务器登陆名及密码 cqUser [email protected]

以上是测试环境,SqlServerProxy运行在主服务器上。

第1步:编辑“dbServers.xml”,设置测试环境的值。仅列出关键部分。
#----------------------------------------------------------------------#

<proxys>
<proxy>
<!-- 使用“0.0.0.0”更方便 -->
<property name="ipAddress">0.0.0.0</property>
<property name="port">8999</property>
<property name="backlog">1024</property>
</proxy>
</proxys>
<master>
<property name="ipAddress">192.168.201.134</property>
<property name="port">1433</property>
<property name="backlog">256</property>
<!-- 主服务器权重设置为0,方便将符合条件的请求都分发到从服务器。-->
<property name="weight">0</property>
</master>
<slaves>
<slave>
<property name="ipAddress">192.168.201.1</property>
<property name="port">1433</property>
<property name="backlog">256</property>
<!-- 必须提供一个可用的账户。-->
<property name="user">cqUser</property>
<property name="password">[email protected]</property>
<property name="weight">5</property>
</slave>
</slaves>

#----------------------------------------------------------------------#

这样配置后,SqlServerProxy运行后将在主服务器上监听 8999 端口。

第2步:编辑"balanceRules.xml", 去掉对连接程序名“Microsoft SQL Server Management Studio”的限制。仅列出关键部分。
#----------------------------------------------------------------------#

<sqlbatch>
<appname>
<!-- 去掉对连接程序名“Microsoft SQL Server Management Studio”,默认配置文件只修改这一处。 -->
<reject ignorecase="true" transaction="All">^SQL Server Profiler</reject>
</appname>
<statement>
<reject>insert|update|delete|begin|save|commit|rollback|create|alter|drop|truncate|set|#|##|exec|execute</reject>
<accept ignorecase="true">\bSELECT\b</accept>
</statement>
</sqlbatch>

#----------------------------------------------------------------------#

第3步:重启SqlServerProxy服务(在“services.msc”名称显示为“SQL Server Proxy Service”),或者先运行“UninstallSvc.bat”再运行“InstallSvc.bat”重装。

第4步:使用“Management Studio”登陆到“192.168.201.134,8999”。

执行“SELECT @@SERVERNAME;”,可以看到返回结果为“AKUMA-PC”,没有reject规则匹配成功,而accept规则匹配成功了,是在从服务器上执行的。

执行“exec(‘SELECT @@SERVERNAME‘);”,因为包含了关键字“exec”,reject规则匹配成功,在主服务器执行,返回结果为“WIN-D5FC592I20C”。

执行“SELECT @@SERVERNAME; exec(‘SELECT @@SERVERNAME‘);” 同样因为包含关键字“exec”,reject规则匹配成功,在主服务器执行,返回结果为两个“WIN-D5FC592I20C”。

通过这个小测试,就能看到,通过简单的配置,能将请求分发到从服务器上去。



4、实践手册

目录:
1、内置命令
2、正则表达式测试器
3、怎么使用单机版的Proxy
4、虚拟ip结合的技巧
5、自定义SQL语句前缀来实现分发
6、业务需要,自己定制请求分发实现

1、内置命令

内置命令是仅连接到SqlServerProxy端口执行的特定sql语句,用来查看从服务器状态和会话历史等。命令是大小写敏感的,且固定大小,不能包含多余空格等,只能单次执行 一个命令。

命令1、“SELECT vt_active;” 查看当前活动连接信息。
返回结果解析:

#------------------#---------------------------------------#----------------------------------------------------#
|列名 |示例值 |客户端属性 |
|------------------|---------------------------------------|----------------------------------------------------|
|endpoint |192.168.201.1:34298 |连接时的远程ip及端口。 |
|------------------|---------------------------------------|----------------------------------------------------|
|app_name |Microsoft SQL Server Management Studio |应用程序名。 |
|------------------|---------------------------------------|----------------------------------------------------|
|to_client |2.55MB/5.23MB |2.55MB从服务器返回数据量,5.23MB返回客户端总数据量。|
|------------------|---------------------------------------|----------------------------------------------------|
|from_client |12.26KB/25.88KB |12.26KB到从服务器的数据量,25.88客户端发送总数据量。|
|------------------|---------------------------------------|----------------------------------------------------|
|sqlbatch_count |19 |执行SQL请求数。 |
|------------------|---------------------------------------|----------------------------------------------------|
|rpcbatch_count |1 |执行Rpc请求数。 |
|------------------|---------------------------------------|----------------------------------------------------|
|transaction_count |0 |执行事务数。 |
|------------------|---------------------------------------|----------------------------------------------------|
|command_count |6 |执行内置命令数。 |
|------------------|---------------------------------------|----------------------------------------------------|
|mars |False |True,启用Mars(多活动结果集);False,没启用。 |
|------------------|---------------------------------------|----------------------------------------------------|
|last_sql |select HOST_NAME(); |最后执行SQL(只包括最前面的256个字符)。 |
|------------------|---------------------------------------|----------------------------------------------------|
|last_rpc |UpdateTask |最后执行的Rpc名称。 |
#------------------#---------------------------------------#----------------------------------------------------#

特别说明:
to_client 前半部分代表了从服务器返回客户端的数据量,后半部分代表了从服务器+主服务器返回客户的数据量,两者的比值越大,从服务器分担的负载越多。
from_client 前半部分代表了客户端到从服务器的数据量,后半部分代表了客户端到从服务器+主服务器的数据量,两者的比值越大,从服务器分担的负载越多。
transaction_count 仅统计客户通过如"sqlConn.BeginTransaction();"开始的事务数,不统计如执行SQL“begin tran”引发的事务。

命令2、“SELECT vt_realtime;” 查看当前实时汇总连接信息。
返回结果解析:

#------------------#---------------------------------------#----------------------------------------------------#
|列名 |示例值 |SqlServerProxy在时间窗口内统计值 |
|------------------|---------------------------------------|----------------------------------------------------|
|span_time |21:46:58 - 21:47:08 |实时统计数据的时间窗口,为10秒。 |
|------------------|---------------------------------------|----------------------------------------------------|
|to_client |43.25MB/85.23MB |参见命令1。 |
|------------------|---------------------------------------|----------------------------------------------------|
|from_client |88.26KB/278.88KB |参见命令1。 |
|------------------|---------------------------------------|----------------------------------------------------|
|session_count |3 |新建立了3个会话。 |
|------------------|---------------------------------------|----------------------------------------------------|
|sqlbatch_count |58 |参见命令1。 |
|------------------|---------------------------------------|----------------------------------------------------|
|rpcbatch_count |20 |参见命令1。 |
|------------------|---------------------------------------|----------------------------------------------------|
|transaction_count |30 |参见命令1。 |
|------------------|---------------------------------------|----------------------------------------------------|
|command_count |3 |参见命令1。 |
#------------------#---------------------------------------#----------------------------------------------------#

命令3、“SELECT vt_history;” 查看当前SqlServerProxy历史运行统计信息。
返回结果解析:

#------------------#---------------------------------------#----------------------------------------------------#
|列名 |示例值 |SqlServerProxy启动后的历史统计 |
|------------------|---------------------------------------|----------------------------------------------------|
|run_time |0.12:37:10 |启动服务后连续运行了0天12小时37分10秒。 |
|------------------|---------------------------------------|----------------------------------------------------|
|to_client |70.58MB/138.84MB |参见命令1。 |
|------------------|---------------------------------------|----------------------------------------------------|
|from_client |24.15MB/54.67MB |参见命令1。 |
|------------------|---------------------------------------|----------------------------------------------------|
|session_count |92 |参见命令2。 |
|------------------|---------------------------------------|----------------------------------------------------|
|sqlbatch_count |2098 |参见命令1。 |
|------------------|---------------------------------------|----------------------------------------------------|
|rpcbatch_count |1673 |参见命令1。 |
|------------------|---------------------------------------|----------------------------------------------------|
|transaction_count |3200 |参见命令1。 |
|------------------|---------------------------------------|----------------------------------------------------|
|command_count |63 |参见命令1。 |
#------------------#---------------------------------------#----------------------------------------------------#

命令4、“SELECT vt_slave;” 查看SqlServerProxy配置的从服务器是否在线(即心跳检测的结果)。
返回结果解析:

#------------------#---------------------------------------#----------------------------------------------------#
|列名 |示例值 |SqlServerProxy配置的从服务器属性 |
|------------------|---------------------------------------|----------------------------------------------------|
|endpoint |192.168.201.1:1433 |从服务器的ip及端口。 |
|------------------|---------------------------------------|----------------------------------------------------|
|status |True |True,在线;False,宕机了。 |
#------------------#---------------------------------------#----------------------------------------------------#

命令5、“SELECT vt_server;” 查看运行SqlServerProxy服务的服务器信息
返回结果解析:

#------------------#---------------------------------------#----------------------------------------------------#
|列名 |示例值 |服务器信息 |
|------------------|---------------------------------------|----------------------------------------------------|
|date |2014-10-14 22:15:06.807 |服务器时间 |
|------------------|---------------------------------------|----------------------------------------------------|
|memory |2.86GB/4.00GB |共有4Gb内存,已使用2.86Gb。 |
|------------------|---------------------------------------|----------------------------------------------------|
|run_time |1.12:25:13 |运行时间。 |
|------------------|---------------------------------------|----------------------------------------------------|
|app_memory |64.88MB |SqlServerProxy使用内存量 |
#------------------#---------------------------------------#----------------------------------------------------#

2、正则表达式测试器

用来测试输入字符串对正则表达式是否匹配,以及将表达式在转义字符和正常字符间的转换。

Expression:在“Pattern”文本框中输正则表达式,在“Input”处输测试字符串,点击“Go”,出现“Yes”表达匹配,出现“No”表达不匹配。如果匹配成功,会计算执行匹配100次所用的毫秒数。

Escaping:在“Plain”文本框中输入要转义的正则表达式,自动在“Escaping”中出现转义后的字符串。反正也然。

3、怎么使用单机版的Proxy

使用单机可以统计SqlServerProxy所执行的会话信息、及对执行请求的审计、验证TDS解析效果等。
方法是在“dbServers.xml”中去掉所有“slave”元素即可。
<akuma>
<slaves>
<!-- 此处留空。 -->
</slaves>
</akuma>

4、虚拟ip结合的技巧

添加虚拟Ip的方法参见《手工添加虚拟IP的实现方法.pdf》或博客:http://www.cnblogs.com/ProJKY/p/VirtualIPAddressImp.html。

技巧1:在运行SqlServerProxy服务的服务器上添加虚拟Ip,客户端连接字符串中的DataSource就执行该虚拟Ip,方便切换SqlServerProxy服务的服务器。

技巧2:在“dbServers.xml”使用从服务器的虚拟Ip地址,也方便切换从服务器地址。压力小了,直接删除虚拟Ip地址即可。

技巧3:因为配置文件“dbServers.xml”只加载一次,所以后续所加从服务器不能够识别,但可以添加多个虚拟Ip,将来压力大了,再将这些虚拟Ip放到从服务器上,心跳检测能快速检测出使用虚拟Ip的从服务器上线了,而将请求分发到这些新上线的虚拟Ip从服务器上。

5、自定义SQL语句前缀来实现分发

使用该方法要求能修改客户端执行SQL请求的代码,但能避免正则表达式匹配速度慢的问题。

例如在执行只读可分发到从服务器执行的SQL语句前加前缀"--SqlServerProxyReadonly",对应“balanceRules.xml”里面添加一条accept规则“<accept>^--SqlServerProxyReadonly<accept>”能加快将只读查询分发到从服务器。类似的添加前缀如“--SqlServerProxyMaster”,对应“balanceRules.xml”里面添加一条reject规则“<reject>^--SqlServerProxyMaster<reject>”能加快将不符合条件的Sql语句分发到主服务器上。

6、业务需要,自己定制请求分发实现

请求分发在SqlServerProxy中被抽象为“ISlaveProvider”接口,位于“Akuma.Contract”程序集中。

实现“ISlaveProvider”接口的要点位于接口签名中,实现接口后,再修改“SqlServerProxy.exe.config”文件即可。



command.sql

SELECT vt_active;

SELECT vt_realtime;

SELECT vt_history;

SELECT vt_slave;

SELECT vt_server;

SELECT N‘command‘ as Col


关于SqlServerProxy

本压缩包的程序将在2015.5.1日过期,过期后将不能继续使用。如需测试,请将数据库和运行Proxy服务的系统时间调到前面。

如果您觉得这些特性不够用或者Bug,请联系[email protected]。



配置程序连接代理中间件字符串

假设你的SqlServerProxy运行在192.168.2.136上,在dbServers.xml配置的代理监听如下:

<?xml version="1.0" encoding="utf-8" ?>
<!--定义主数据库和从服务器等信息。-->
<akuma>
<!-- 代理服务监听的端口信息,可以配置监听多个端口。 -->
<proxys>
<proxy>
<!-- 可为IPV6 或 IPV4 的地址。 -->
<property name="ipAddress">0.0.0.0</property>
<property name="port">8999</property>
<property name="backlog">1024</property>
</proxy>

那么根据配置,代理监听的端口号就是:8999,那么字符串中Data Source就是192.168.2.136,8999。

#-------------------------------------------------#-------------------------------------------------------------#
| 希望SqlServerProxy采用Windows认证连接主服务器 |Data Source=192.168.2.136,8999;Integrated Security = SSPI; |
| |Initial Catalog = myDataBase;Encrypt=False; |
|-------------------------------------------------|-------------------------------------------------------------|
| 希望SqlServerProxy采用SqlServer认证连接主服务器 |Data Source=192.168.2.136,8999;Initial Catalog = myDataBase; |
| |User ID = sa;Password=samplepassword;Encrypt=False; |
#-------------------------------------------------#-------------------------------------------------------------#

连接字符串里面的“Encrypt=False”可以不写,但不能为“Encrypt=True”,详情参见文档“1、特性及实现原理.txt”。



master_slave.png



手工添加虚拟IP的实现方法.pdf

f

f

f

f

f

f

f



ISlaveProvider.sample

using Akuma.Contract.Heartbeat;
using Akuma.Contract.Policy;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace CustomSlaveProvider {
    [Serializable]
    public class SlaveProvider : ISlaveProvider {
        public ApplayResult ApplyRpc(RequestRpcCollection rpcColl, SessionInfo sessionInfo, SlaveInfo[] slaves) {
            bool isSp_executesql = rpcColl.All(rpc => rpc.Name.Equals(SystemRpc.SP_EXECUTESQL, StringComparison.OrdinalIgnoreCase));
            bool accept = false;

            if (isSp_executesql) {    // 如果执行的是参数化查询
                foreach (var rpc in rpcColl) {
                    if (rpc.Parameters.Length == 0) {
                        accept = false;
                        break;
                    }

                    string statement = rpc.Parameters[0].Value as String;
                    if (String.IsNullOrEmpty(statement) == true) {
                        accept = false;
                        break;
                    }

                    RequestSql requestSql = new RequestSql(rpc.Parameters[0].Value as String, rpcColl.UseTransaction);
                    // _ruleService 是默认实现的正则表达式匹配服务
                    accept = _ruleService.AcceptSql(requestSql, sessionInfo);
                    if (accept == false) {
                        break;
                    }
                }
            } else {
                accept = _ruleService.AcceptRpc(rpcColl, sessionInfo);
            }

            if (accept == false) {
                return null;   // 返回null,将会分发到主服务器执行
            }

            // 主服务器也有权重,按权重是否该在主服务器上执行
            bool turnToMaster = SholdTurnToMaster(sessionInfo.MasterWeight, slaves);

            if (turnToMaster == true) {
                return null;
            }

            SlaveInfo currentSlave = slaves.FirstOrDefault(slave => _currentSlaveResult != null && slave.SlaveId == _currentSlaveResult.SlaveId && slave.Status == OnlineStatus.On);
            if (currentSlave != null) {    // 如果可以到从服务器执行,那么尽量返回上一次分配的从服务器,避免不必要的网络流量。
                return _currentSlaveResult;
            }

            _currentSlaveResult = GetRandomIndexByWeight(slaves);    // 根据权重,计算该分配到那个从服务器

            return _currentSlaveResult;
        }

        public ApplayResult ApplySql(RequestSql requestSql, SessionInfo sessionInfo, SlaveInfo[] slaves) {
            bool accept = _ruleService.AcceptSql(requestSql, sessionInfo);

            if (accept == false) {
                return null;
            }

            bool turnToMaster = SholdTurnToMaster(sessionInfo.MasterWeight, slaves);

            if (turnToMaster == true) {
                return null;
            }

            SlaveInfo currentSlave = slaves.FirstOrDefault(slave => _currentSlaveResult != null && slave.SlaveId == _currentSlaveResult.SlaveId && slave.Status == OnlineStatus.On);
            if (currentSlave != null) {
                return _currentSlaveResult;
            }

            _currentSlaveResult = GetRandomIndexByWeight(slaves);

            return _currentSlaveResult;
        }

        bool SholdTurnToMaster(int masterWeight, SlaveInfo[] slaves) {
            int length = masterWeight + slaves.Where(slave => slave.Status == OnlineStatus.On).Sum(slave => slave.Weight);
            int index = _random.Next(0, length);

            if (index < masterWeight && masterWeight > 0) {
                return true;
            }

            return false;
        }

        ApplayResult GetRandomIndexByWeight(SlaveInfo[] slaves) {
            SlaveInfo[] onlineSlaves = slaves.Where(slave => slave.Status == OnlineStatus.On).ToArray();

            List<SlaveInfo> list = new List<SlaveInfo>();
            foreach (var slave in onlineSlaves) {
                list.AddRange(Enumerable.Repeat(slave, slave.Weight));
            }
            if (list.Count == 0) {
                return null;
            }
            int index = _random.Next(0, list.Count);
            string slaveId = list[index].SlaveId;

            ApplayResult applayResult = new ApplayResult();
            applayResult.SlaveId = slaveId;
            return applayResult;
        }

        /// <summary>
        /// 当前会话的从服务器Id。
        /// 每个SqlConnection连接就是一个会话,会话的从服务器确定后,就尽量不要修改,避免不必要的网络通信。
        /// 如果修改了,会导致额外的网络通信。
        /// </summary>
        ApplayResult _currentSlaveResult = null;

        Random _random = new Random();
    }
}
时间: 2024-10-14 17:07:59

SqlServerProxy的一些资料的相关文章

Android 学习资料分享(2015 版)

我是如何自学Android,资料分享(2015 版) Tikitoo2015.02.11 10:21 1713 字 3932 次阅读 自己学了两三个月的Android,最近花了一周左右的时间写了个App--Diigoer(已开源),又花了一两周时间找工作,收到了两个Offer,也算是对自己学习的一种认可吧:我刚开始学习总结的--<我是如何自学Android,资料分享>,如果是初学Android 的话,不应该错过的,而今天这篇分享好这篇文章,相对于第一次写的会有所提升,所以建议先把上一篇看了,再

华为FusionCloud 云计算解决方案及相关资料下载

华为FusionCloud云计算解决方案引入水平融合.垂直融合.接入融合和数据融合四位一体的全融合,对企业与行业传统数据中心的IT基础设施的进行"融合重构", 帮助企业化繁为简,实现商业价值. FusionCloud 彻底打破原有的笨重的IT基础设施在支撑企业核心业务效率与成本方面的束缚与障碍,把企业传统数据中心改造成为一个高度简化.标准化.自动化和弹性的云数据中心,使得企业的IT支撑系统从企业的"成本中心"转型成为推动企业核心业务不断发展的引擎. 相关资料下载地址

nodejs学习资料

NodeJS基础 什么是NodeJS JS是脚本语言,脚本语言都需要一个解析器才能运行.对于写在HTML页面里的JS,浏览器充当了解析器的角色.而对于需要独立运行的JS,NodeJS就是一个解析器. 每一种解析器都是一个运行环境,不但允许JS定义各种数据结构,进行各种计算,还允许JS使用运行环境提供的内置对象和方法做一些事情.例如运行在浏览器中的JS的用途是操作DOM,浏览器就提供了document之类的内置对象.而运行在NodeJS中的JS的用途是操作磁盘文件或搭建HTTP服务器,NodeJS

linux netlink套接字学习资料

理论: http://blog.csdn.net/unbutun/article/details/3394061 进一步深入: http://edsionte.com/techblog/archives/4134 http://edsionte.com/techblog/archives/4140 http://edsionte.com/techblog/archives/4134 实践: http://bbs.chinaunix.net/thread-3766684-1-1.html 附录代码

机器学习资料

1. https://pan.baidu.com/s/1jIegLmu 密码: 87im (资料)2. https://pan.baidu.com/s/1bpAjo7d 密码: yppj(数据)

【持续更新】机械工业出版社华章科技《计算机科学丛书》原版PDF+随书资料下载

图片 中文名 英文名 版次 著 译 PDF下载 随书资料 计算机科学导论 Foundations of Computer Science 3rd Behrouz Forouzan & Firouz Mosharraf 刘艺 瞿高峰 等     Java编程思想 Thinking in Java 4th Bruce Eckel  陈昊鹏 链接: http://pan.baidu.com/s/1brGWnc 密码: 2hrr    软件工程:实践者的研究方法 Software Engineering

独家全功能USB2.0开发板,最强CY7C68013A-128核心板,超强资料不断提供更新服务

       学习USB开发再也不用买书啦,也不用花费重金去上培训班啦,IFLabs开创USB学习开发新模式,你所需要的知识.技术.范例.代码等等统统都在这里.IFLabs打造全网最丰富.最权威的USB开发平台和资料. 热卖的IFLabs精品USB2.0核心板套件再升级,全网独家推出最强.最全功能的Cypress USB 2.0 CY7C68013A-128AXC核心板开发板,全网最全配件和全网最全开发资料.只需这一次投入,即可实现USB接口开发的从入门到精通!并且有长期的全网最全开发手册更新支

公众号快速吸几万粉分享课资料

昨晚很多人表示听课的录音找不到了,所以简单的整理了一份文字版.虽然比较简单,但是核心的东西都基本在呢.因为比较晚了所以可能整理得有点乱,大家费点心看吧. 今天晚上主要分享的内容是公众号快速吸粉这块的,我今天晚上用了一天吸几万粉这个标题,但是并不代表大家在听完课操作后就一定能达到这个效果.因为这里面的因素很多,如果真的每个人都能轻松达到这个效果,有怎么神奇的话,估计我也不用做项目了.直接收8万8一堂课就够我花三代了.写这个标题只是为了吸引更多的人来听课.但是如果你肯去做,肯花时间和精力去研究或者你

数据资料的统计描述

一.集中趋势 1.算术平均数 1.1 简单的算术平均数 1.2 加权的算术平均数 均值的计算要根据分组的资料进行,要涉及到频数的考虑,即所谓的加权问题. 2.几何平均数 2.1 简单几何平均数 数据资料的统计描述