精华内容
下载资源
问答
  • Android5.1网络切换策略分析

    千次阅读 2015-10-14 18:55:25
    最近在在5.1移植了...WIFI和ETHERNET居然可以同时存在,为了解决这个问题,就不得不重新认识5.1的网络切换策略了。在android4.4上,想实现以太网为优先级最高(意思是以太网打开了,WIFI就无法打开),方法很简单,

    最近在在5.1移植了以太网过来,移植的过程并没有什么大问题,修改了框架上的代以及添加了Settings代码,以太网调试就基本完工了,后面只是修改下布局即可。但是网络切换策略就有所变化了,就不得不重新认识5.1的网络切换策略了。
    在android4.4上,想实现以太网为优先级最高(意思是以太网打开了,WIFI就无法打开),方法很简单,只需要在default.xml和ConnectivityServicet修改就好了。但在5.1系统上就做了新的调整,具体改动的原因不明,他是依靠网络评分的大小来确定谁的优先级高,废话不多说,以以太网为例子,进行追踪。

    1、frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetServiceImpl

      public EthernetServiceImpl(Context context) {
            mContext = context;
            Log.i(TAG, "Creating EthernetConfigStore");
            mEthernetConfigStore = new EthernetConfigStore();
            mIpConfiguration = mEthernetConfigStore.readIpAndProxyConfigurations();
    
            Log.i(TAG, "Read stored IP configuration: " + mIpConfiguration);
    
            mTracker = new EthernetNetworkFactory(mListeners); //创建本地的网络工厂
         mTracker.setContext(context); //add by peng
       }
    

    2、frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetNetworkFactory

     EthernetNetworkFactory(RemoteCallbackList<IEthernetServiceListener> listeners) {
            mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, "");
            mLinkProperties = new LinkProperties();
            initNetworkCapabilities(); //初始化网络参数,比如,上下行速度、传输类型等
            mListeners = listeners;
        }
        //我们看看这个类的start函数
         public synchronized void start(Context context, Handler target) {
            // The services we use.
            IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
            mNMService = INetworkManagementService.Stub.asInterface(b);
            mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE); //获取服务
    
            // Interface match regex.
            mIfaceMatch = context.getResources().getString(
                    com.android.internal.R.string.config_ethernet_iface_regex);
    
            // Create and register our NetworkFactory.
            mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, target.getLooper());
            mFactory.setCapabilityFilter(mNetworkCapabilities); //设置网络参数
            **mFactory.setScoreFilter(-1);** // 这个就是设置网络评分,但是这为-1,因为这是初始化,等有网卡接入,讲评分拉高就行,后面会讲述
            mFactory.register();//注册
            //再来看看当网卡接入的时候做了什么
    
     private void updateInterfaceState(String iface, boolean up) {
            if (!mIface.equals(iface)) {
                return;
            }
            Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down"));
    
            synchronized(this) {
                mLinkUp = up;
                mNetworkInfo.setIsAvailable(up);
                if (!up) {
                    // Tell the agent we're disconnected. It will call disconnect().
                    mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
                    sendEthernetStateChangedBroadcast(EthernetManager.ETHER_STATE_DISCONNECTED); //add by peng
                }
                updateAgent();//这个是更新数据的,来看看。
                // set our score lower than any network could go
                // so we get dropped.  TODO - just unregister the factory
                // when link goes down.
                //这里就是当发现网卡up的话就设置评分  否则将评分设置成-1.
                mFactory.setScoreFilter(up ? NETWORK_SCORE : -1); //NETWORK_SCORE 就是自己定义的分数,我这里假设定义70
            }
        }
        //看看这个updateAgent();
     public void updateAgent() {
            synchronized (EthernetNetworkFactory.this) {
                if (mNetworkAgent == null) return;
                if (DBG) {
                    Log.i(TAG, "Updating mNetworkAgent with: " +
                          mNetworkCapabilities + ", " +
                          mNetworkInfo + ", " +
                          mLinkProperties);
                }
                mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 
                mNetworkAgent.sendNetworkInfo(mNetworkInfo);
                mNetworkAgent.sendLinkProperties(mLinkProperties);
                // never set the network score below 0.
                mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0);//这个就是重点了,看看里面做了什么
            }
        }

    3、在深入去看看sendNetworkScore(score)到底做了写什么。

     public void sendNetworkScore(int score) {
            if (score < 0) {
                throw new IllegalArgumentException("Score must be >= 0");
            }
            queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score)); //很明显是发送了一个消息 以及带上了评分发送出去了
        }

    4、全局搜索了下,发现这个消息在ConnectivityService处理了。

                    case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: {
                        NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
                        if (nai == null) {
                            loge("EVENT_NETWORK_SCORE_CHANGED from unknown NetworkAgent");
                            break;
                        }
                        Integer score = (Integer) msg.obj;
                        if (score != null) updateNetworkScore(nai, score.intValue());
                        break;
                    }
    
            private void updateNetworkScore(NetworkAgentInfo nai, int score) {  //更新网络评分
            if (DBG) log("updateNetworkScore for " + nai.name() + " to " + score);
            if (score < 0) {
                loge("updateNetworkScore for " + nai.name() + " got a negative score (" + score +
                        ").  Bumping score to min of 0");
                score = 0;
            }
    
            final int oldScore = nai.getCurrentScore(); //获取当前网络评分,比如我之前连接的是WIFI,现在要连接以太网,看看这个函数。
            nai.setCurrentScore(score);
    
            rematchAllNetworksAndRequests(nai, oldScore);
    
            sendUpdatedScoreToFactories(nai);
        }
    

    4、getCurrentScore();

      private int getCurrentScore(boolean pretendValidated) {
            int score = currentScore;
    
            ///M: Support for EPDG testing @{
            if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_EPDG)) {
            Log.d(TAG,"[peng add]  Support for EPDG testing,this score --->"+score);
                return score;
            }
            ///@}
            //add by peng  , set ethernet priority highest.
         if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) { //这个就是解决WIFI和以太网网络评分的,先跳过。后面在来分析。
            Log.d(TAG,"[peng add]  Support for TRANSPORT_ETHERNET ,this score --->"+score);
                return score;
            }
            if (!everValidated && !pretendValidated){ 
            score -= UNVALIDATED_SCORE_PENALTY;
            Log.d(TAG,"[peng add]  everValidated and pretendValidated is false,this score --->"+score);
            }
            if (score < 0) score = 0;
    
            if (networkMisc.explicitlySelected){    
            score = EXPLICITLY_SELECTED_NETWORK_SCORE;  //从log看 WIFI的默认评分是60,随着信号等级加强评分会增加,同时也会减,具体看WIFI的代码吧!这里无论是以太网还是WIFI都会走这个判断,也就是WIFI和以太网的评分都走了100,那么系统又怎么选择了打开谁呢?
            Log.d(TAG,"[peng add]  networkMisc.explicitlySelected,this score full--->"+score);
                }
    
            return score;
        }

    5、网络切换,主要看ConnectivityService的rematchNetworkAndRequests方法。

                        …………
                        if (VDBG) {
                        log("currentScore = " +
                                (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +
                                ", newScore = " + newNetwork.getCurrentScore());
                    }
                    if (currentNetwork == null ||
                            currentNetwork.getCurrentScore() <= newNetwork.getCurrentScore()) { //当连接的网络评分小于或等于新的连接网络评分,那么就remove当前网络,连接新的网络。  也就可以分析出,只要是后者连的,优先级就最高。
                        if (currentNetwork != null) {
                            if (DBG) log("   accepting network in place of " + currentNetwork.name());
                            currentNetwork.networkRequests.remove(nri.request.requestId);
                            currentNetwork.networkLingered.add(nri.request);
                            affectedNetworks.add(currentNetwork);
                        } else {
                            if (DBG) log("   accepting network in place of null");
                        }
                        …………
    

    6、如何设置以太网优先级最高?
    将EthernetNetworkFactory的以太网评分增加
    private static final int NETWORK_SCORE = 110; //大于100即可,因为WIFI最大的评分是100

    在NetworkAgentInfo的getCurrentScore方法里添加以太网的评分,保证不被修改
        //add by peng  , set ethernet priority highest.
     if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
        Log.d(TAG,"[peng add]  Support for TRANSPORT_ETHERNET ,this score --->"+score);
            return score;
        }
    

    “`
    这样就可以避免WIFI和以太网同时连接了。具体问题具体分析,以上是个人观点,如果解释的不对,请多多包含。

    展开全文
  • 几种常用的操作系统调度策略

    万次阅读 2017-08-16 17:23:04
    但如果是Pi>Pj,则立即停止Pj的执行,做进程切换,使i 进程投入执行。显然,这种抢占式的优先权调度算法能更好地满足紧迫作业的要求,故而常用于要求比较严格的实时系统中,以及对性能要求较高的批处理和分时系统中...

    一、先来先服务和短作业(进程)优先调度算法

    1.先来先服务调度算法

    先来先服务(FCFS)调度算法是一种最简单的调度算法,该算法既可用于作业调度,也可用于进程调度。当在作业调度中采用该算法时,每次调度都是从后备作业队列中选择一个或多个最先进入该队列的作业,将它们调入内存,为它们分配资源、创建进程,然后放入就绪队列。在进程调度中采用FCFS算法时,则每次调度是从就绪队列中选择一个最先进入该队列的进程,为之分配处理机,使之投入运行。该进程一直运行到完成或发生某事件而阻塞后才放弃处理机。

    2.短作业(进程)优先调度算法

    短作业(进程)优先调度算法SJ(P)F,是指对短作业或短进程优先调度的算法。它们可以分别用于作业调度和进程调度。短作业优先(SJF)的调度算法是从后备队列中选择一个或若干个估计运行时间最短的作业,将它们调入内存运行。而短进程优先(SPF)调度算法则是从就绪队列中选出一个估计运行时间最短的进程,将处理机分配给它,使它立即执行并一直执行到完成,或发生某事件而被阻塞放弃处理机时再重新调度。

    二、高优先权优先调度算法

    1.优先权调度算法的类型

    为了照顾紧迫型作业,使之在进入系统后便获得优先处理,引入了最高优先权优先(FPF)调度算法。此算法常被用于批处理系统中,作为作业调度算法,也作为多种操作系统中的进程调度算法,还可用于实时系统中。当把该算法用于作业调度时,系统将从后备队列中选择若干个优先权最高的作业装入内存。当用于进程调度时,该算法是把处理机分配给就绪队列中优先权最高的进程,这时,又可进一步把该算法分成如下两种。

    1) 非抢占式优先权算法

    在这种方式下,系统一旦把处理机分配给就绪队列中优先权最高的进程后,该进程便一直执行下去,直至完成;或因发生某事件使该进程放弃处理机时,系统方可再将处理机重新分配给另一优先权最高的进程。这种调度算法主要用于批处理系统中;也可用于某些对实时性要求不严的实时系统中。

    2) 抢占式优先权调度算法

    在这种方式下,系统同样是把处理机分配给优先权最高的进程,使之执行。但在其执行期间,只要又出现了另一个其优先权更高的进程,进程调度程序就立即停止当前进程(原优先权最高的进程)的执行,重新将处理机分配给新到的优先权最高的进程。因此,在采用这种调度算法时,是每当系统中出现一个新的就绪进程i 时,就将其优先权Pi与正在执行的进程j 的优先权Pj进行比较。如果Pi≤Pj,原进程Pj便继续执行;但如果是Pi>Pj,则立即停止Pj的执行,做进程切换,使i 进程投入执行。显然,这种抢占式的优先权调度算法能更好地满足紧迫作业的要求,故而常用于要求比较严格的实时系统中,以及对性能要求较高的批处理和分时系统中。

    2.高响应比优先调度算法

    在批处理系统中,短作业优先算法是一种比较好的算法,其主要的不足之处是长作业的运行得不到保证。如果我们能为每个作业引入前面所述的动态优先权,并使作业的优先级随着等待时间的增加而以速率a 提高,则长作业在等待一定的时间后,必然有机会分配到处理机。该优先权的变化规律可描述为:
    操作系统
    由于等待时间与服务时间之和就是系统对该作业的响应时间,故该优先权又相当于响应比RP。据此,又可表示为:
    操作系统
    由上式可以看出:

    (1) 如果作业的等待时间相同,则要求服务的时间愈短,其优先权愈高,因而该算法有利于短作业。

    (2) 当要求服务的时间相同时,作业的优先权决定于其等待时间,等待时间愈长,其优先权愈高,因而它实现的是先来先服务。

    (3) 对于长作业,作业的优先级可以随等待时间的增加而提高,当其等待时间足够长时,其优先级便可升到很高,从而也可获得处理机。简言之,该算法既照顾了短作业,又考虑了作业到达的先后次序,不会使长作业长期得不到服务。因此,该算法实现了一种较好的折衷。当然,在利用该算法时,每要进行调度之前,都须先做响应比的计算,这会增加系统开销。

    三、基于时间片的轮转调度算法

    1.时间片轮转法

    1) 基本原理

    在早期的时间片轮转法中,系统将所有的就绪进程按先来先服务的原则排成一个队列,每次调度时,把CPU 分配给队首进程,并令其执行一个时间片。时间片的大小从几ms 到几百ms。当执行的时间片用完时,由一个计时器发出时钟中断请求,调度程序便据此信号来停止该进程的执行,并将它送往就绪队列的末尾;然后,再把处理机分配给就绪队列中新的队首进程,同时也让它执行一个时间片。这样就可以保证就绪队列中的所有进程在一给定的时间内均能获得一时间片的处理机执行时间。换言之,系统能在给定的时间内响应所有用户的请求。

    2.多级反馈队列调度算法

    前面介绍的各种用作进程调度的算法都有一定的局限性。如短进程优先的调度算法,仅照顾了短进程而忽略了长进程,而且如果并未指明进程的长度,则短进程优先和基于进程长度的抢占式调度算法都将无法使用。而多级反馈队列调度算法则不必事先知道各种进程所需的执行时间,而且还可以满足各种类型进程的需要,因而它是目前被公认的一种较好的进程调度算法。在采用多级反馈队列调度算法的系统中,调度算法的实施过程如下所述。

    (1) 应设置多个就绪队列,并为各个队列赋予不同的优先级。第一个队列的优先级最高,第二个队列次之,其余各队列的优先权逐个降低。该算法赋予各个队列中进程执行时间片的大小也各不相同,在优先权愈高的队列中,为每个进程所规定的执行时间片就愈小。例如,第二个队列的时间片要比第一个队列的时间片长一倍,……,第i+1个队列的时间片要比第i个队列的时间片长一倍。

    (2) 当一个新进程进入内存后,首先将它放入第一队列的末尾,按FCFS原则排队等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚未完成,调度程序便将该进程转入第二队列的末尾,再同样地按FCFS原则等待调度执行;如果它在第二队列中运行一个时间片后仍未完成,再依次将它放入第三队列,……,如此下去,当一个长作业(进程)从第一队列依次降到第n队列后,在第n 队列便采取按时间片轮转的方式运行。

    (3) 仅当第一队列空闲时,调度程序才调度第二队列中的进程运行;仅当第1~(i-1)队列均空时,才会调度第i队列中的进程运行。如果处理机正在第i队列中为某进程服务时,又有新进程进入优先权较高的队列(第1~(i-1)中的任何一个队列),则此时新进程将抢占正在运行进程的处理机,即由调度程序把正在运行的进程放回到第i队列的末尾,把处理机分配给新到的高优先权进程。

     

    本文出自:http://www.wypblog.com/archives/251

    展开全文
  • 主备切换策略

    千次阅读 2018-01-18 16:37:59
    (4)将keepalived注册到系统服务中 cp /usr/ local /keepalived/ sbin /keepalived /u sr /sbin/ cp /usr/ local /keepalived/ etc /sysconfig/ keepalived /etc/ sysconfig / cp /usr/ local /keepalived/ etc...

    master:10.6.2.148

    backup: 10.6.2.132

    vip:10.6.2.135 (虚拟ip)

    在NodeA和NodeB分别部署tomcat并启动,然后安装keepalived监控tomcat,通过vip:10.6.2.135可以访问到tomcat,这时候访问的其实是NodeA上的tomcat,如果关闭NodeA上面的tomcat,这时候NodeB会自动帮助接管,这样的服务依旧可以运行。

    下面来安装keepalived。

    (1)下载keepalived的压缩包,需要服务器联网(也可直接yum安装,不过机房目前不支持yum服务)

    wget http://www.keepalived.org/software/keepalived-1.2.15.tar.gz

    这里写图片描述

    (2)解压keepalived源码包

    tar zxf keepalived-1.2.15.tar.gz

    这里写图片描述

    (3)进行编译和安装

    cd keepalived-1.2.15
    ./configure --prefix=/usr/local/keepalived
    make
    make install

    (4)将keepalived注册到系统服务中

    cp /usr/local/keepalived/sbin/keepalived /usr/sbin/
    cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
    cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/

    这里写图片描述

    (5)启动和停止keepalived

    service keepalived start

    这里写图片描述

    service keepalived stop

    这里写图片描述

    此时说明keepalived编译安装没有问题。

    (6)设置为开机自启动

    chkconfig keepalived on

    接下来配置keepalived

    1.配置主服务器

    (1)在/etc下创建keepalived文件夹

    mkdir /etc/keepalived

    (2)在keepalived文件夹下vi配置文件

    这里写图片描述

    vi /etc/keepalived/keepalived.conf

    配置文件如下:

    (3)在keepalived文件夹下新建tomcat_check.sh,用来监测tomcat是否运行,shell脚本如下:

    这里写图片描述

    如果tomcat停止运行,keepalived将能够检测到这个异常并将主服务器停止。

    2.配置备用服务器

    (1)在/etc下创建keepalived文件夹

    mkdir /etc/keepalived

    (2)在keepalived文件夹下vi配置文件

    这里写图片描述

    vi /etc/keepalived/keepalived.conf

    配置文件如下:

    (3)在keepalived文件夹下新建check_telnet.sh,用来监测主服务器的tomcat是否运行,shell脚本如下:

    这里写图片描述

    接下来配置PSN的文件同步,利用NFS和rpcbind服务,将主备服务器的存储都放到存储服务器。

    这里写图片描述

    1.服务端(存储服务器)配置

    (1)启动rpc服务

    /etc/init.d/rpcbind start

    (2)启动NFS服务

    /etc/init.d/nfs start

    注:必须先启动rpc服务,然后再启动NFS服务

    (3)开机自启动

    chkconfig nfs on
    chkconfig rpcbind on
    tail -2 /etc/rc.local

    (4)NFS服务端配置文件的配置

    NFS默认配置文件路径是:/etc/exports,配置文件的格式是:NFS共享目录

    NFS客户端地址(参数,参数2),例如,/data 10.6.3.130/24(rw,sync)

    创建/data目录,并且属主和属组都为:root,其中root是安装nfs服务时默认的用户

    mkdir /data –p
    chownR nfsnobody:nftnobody /data
    ls –ld /data
    /etc/init.d/nfs reload
    showamount –e 10.6.3.131

    这里写图片描述

    2.客户端配置

    (1)启动rpc服务,加入开机自启动

    /etc/init.d/rpcbind start
    chkconfig rpcbind on

    (2)ping通服务器端ip地址

    ping 10.6.3.131

    (3)telnet服务端的111端口

    telnet 10.6.3.131 111

    这里写图片描述

    (4)showmount服务端

    showmount –e 10.6.3.131

    这里写图片描述

    (5)挂载,文件共享

    mount –t nfs 10.6.3.131:/data /home/Videos/Test

    (6)查看是否挂载成功

    df –h

    这里写图片描述

    展开全文
  • (21)主备一致性与主备切换策略

    千次阅读 2019-05-15 11:09:58
    如图 所示就是基本的主备切换流程,是一个M-S结构(master-slave) 在状态 1 中,客户端的读写都直接访问节点 A ,而节点 B 是 A 的备库,只是将 A 的更新都同步过来,到本地执行。这样可以保持节点 B 和 A 的...

    MySQL 主备的基本原理

    如图 所示就是基本的主备切换流程,是一个M-S结构(master-slave)

    在状态 1 中,客户端的读写都直接访问节点 A ,而节点 B 是 A 的备库,只是将 A 的更新都同步过来,到本地执行。这样可以保持节点 B 和 A 的数据是相同的。

    当需要切换的时候,就切成状态 2 。这时候客户端读写访问的都是节点 B ,而节点 A 是 B 的备库。

    在状态 1 中,虽然节点 B 没有被直接访问,但是我依然建议你把节点 B (也就是备库)设置成只读( readonly )模式。这样做,有以下几个考虑:
    1.  有时候一些运营类的查询语句会被放到备库上去查,设置为只读可以防止误操作
    2.  防止切换逻辑有 bug ,比如切换过程中出现双写,造成主备不一致;
    3.  可以用 readonly 状态,来判断节点的角色。

    把备库设置成只读,不影响跟主库的同步更新

    因为 readonly 设置对超级 (super) 权限用户是无效的,而用于同步更新的线程,就拥有超级权限。

    看 节点 A A 到 B B 这条线的内部流程是什么样的

    备库 B 跟主库 A 之间维持了一个长连接。主库 A 内部有一个线程,专门用于服务备库 B 的这个长连接。一个事务日志同步的完整过程是这样的:
    1.  在备库 B 上通过 change master 命令,设置主库 A 的 IP 、端口、用户名、密码,以及要从哪个位置开始请求 binlog ,这个位置包含文件名和日志偏移量。
    2.  在备库 B 上执行 start slave 命令,这时候备库会启动两个线程,就是图中的 io_thread 和sql_thread 其中 io_thread 负责与主库建立连接。
    3.  主库 A 校验完用户名、密码后,开始按照备库 B 传过来的位置,从本地读取 binlog ,发给 B 。
    4.  备库 B 拿到 binlog 后,写到本地文件,称为中转日志( relay log )。
    5. sql_thread 读取中转日志,解析出日志里的命令,并执行。

    循环复制问题

    上面的原理中我们使用的M-S结构,但实际生产上使用比较多的是双 M 结构,如下图的主备切换流程:

    点 A 和 B之间总是互为主备关系。这样在切换的时候就不用再修改主备关系。

    但是,双 M 结构还有一个问题需要解决。业务逻辑在节点 A 上更新了一条语句,然后再把生成的 binlog  发给节点 B ,节点 B 执行完这条更新语句后也会生成 binlog 。

    那么,如果节点 A 同时是节点 B 的备库,相当于又把节点 B 新生成的 binlog 拿过来执行了一次,然后节点 A 和 B 间,会不断地循环执行这个更新语句,也就是循环复制了。

    MySQL 在 binlog 中记录了这个命令第一次执行时所在实例的 serverid 。因此,我们可以用下面的逻辑,来解决两个节点间的循环复制的问题:
    1.  规定两个库的 server id 必须不同,如果相同,则它们之间不能设定为主备关系;
    2.  一个备库接到 binlog 并在重放的过程中,生成与原 binlog 的 server id 相同的新的 binlog
    3.  每个库在收到从自己的主库发过来的日志后,先判断 server id ,如果跟自己的相同,表示这个日志是自己生成的,就直接丢弃这个日志。

    按照这个逻辑,如果我们设置了双 M 结构,日志的执行流就会变成这样:
    1.  从节点 A 更新的事务, binlog 里面记的都是 A 的 server id
    2.  传到节点 B 执行一次以后,节点 B 生成的 binlog  的 server id 也是 A 的 server id ;
    3.  再传回给节点 A , A 判断到这个 server id 与自己的相同,就不会再处理这个日志。所以,死循环在这里就断掉了。

    双 M 结构会出现循环复制的情况:

    一种场景是,在一个主库更新事务后,用命令 set global server_id=x 强制修改了 server_id 。等日志再传回来的时候,发现 server_id 跟自己的 server_id 不同,就只能执行了。

    另一种场景是,有三个节点的时候:

    trx1 是在节点 B 执行的,因此 binlog 上的server_id 就是 B , binlog 传给节点 A ,然后 A 和 A’ 搭建了双 M 结构,就会出现循环复制。

     

    主备延迟

    与数据同步有关的时间点主要包括以下三个:
    1.  主库 A 执行完成一个事务,写入 binlog ,我们把这个时刻记为 T1;
    2.  之后传给备库 B ,我们把备库 B 接收完这个 binlog 的时刻记为 T2;
    3.  备库 B 执行完成这个事务,我们把这个时刻记为 T3 。

    所谓主备延迟,就是同一个事务,在备库执行完成的时间和主库执行完成的时间之间的差值,也就是 T3-T1 。

    在网络正常的时候,日志从主库传给备库所需的时间是很短的,即 T2-T1 的值是非常小的。也就是说,网络正常情况下,主备延迟的主要来源是备库接收完 binlog 和执行完这个事务之间的时间差。

    在备库上执行 show slave status 命令,它的返回结果里面会显示seconds_behind_master ,用于表示当前备库延迟了多少秒,就是T3-T1的值。

    所以说,主备延迟最直接的表现是,备库消费中转日志( relay log )的速度,比主库生产 binlog的速度要慢

    主备延迟的来源

    首先,有些部署条件下,备库所在机器的性能要比主库所在的机器性能差。

    第二种常见的可能了,即备库的压力大。主库既然提供了写能力,那么备库可以提供一些读能力。由于主库直接影响业务,大家使用起来会比较克制,反而忽视了备库的压力控制。结果就是,备库上的查询耗费了大量的 CPU 资源,影响了同步速度

    这种情况,我们一般可以这么处理
    1.  一主多从。除了备库外,可以多接几个从库,让这些从库来分担读的压力。这是最常用的
    2.  通过 binlog 输出到外部系统,比如 Hadoop 这类系统,让外部系统提供统计类查询的能力。

    这里需要说明一下,从库和备库在概念上其实差不多。为了方便描述,我把会在 HA 主备切换过程中被选成新主库的,称为备库,其他的称为从库。

    这就是第三种可能了,即大事务。因为主库上必须等事务执行完成才会写入 binlog ,再传给备库。所以,如果一个主库上的语句执行 10 分钟,那这个事务很可能就会导致从库延迟 10 分钟。

    一个典型的大事务场景,就是一次性地用 delete 语句删除太多数据

    由于主备延迟的存在,所以在主备切换的时候,就相应的有不同的策略。

    主备切换策略-可靠性优先

    在双M结构下,切换流程由专门的 HA 系统来完成的,图中的SBM即为 seconds_behind_master 参数的简写。

    1.  判断备库 B 现在的 seconds_behind_master ,如果小于某个值(比如 5 秒)继续下一步,否则持续重试这一步
    2.  把主库 A 改成只读状态,即把 readonly 设置为 true ;
    3.  判断备库 B 的 seconds_behind_master 的值,直到这个值变成 0 为止
    4.  把备库 B 改成可读写状态,也就是把 readonly  设置为 false ;
    5.  把业务请求切到备库 B 。

    这个切换流程中是有不可用时间的。因为在步骤 2 之后,主库 A 和备库 B 都处于readonly 状态,也就是说这时系统处于不可写状态,直到步骤 5 完成后才能恢复。同时,步骤3可能要耗费好几秒时间,这也就是为什么步骤1要先判断,确保 seconds_behind_master 的值足够小

    主备切换策略-可用性优先策略

    在可靠性优先策略中存在系统的不可用时间,你也可以选择可用性优先的策略,来把这个不可用时间几乎降为 0 。

    如果我强行把步骤 4 、 5 调整到最开始执行,也就是说不等主备数据同步,直接把连接切到备库B ,并且让备库 B 可以读写,那么系统几乎就没有不可用时间了。代价就是:可能出现数据不一致情况

    举可用性优先流程产生数据不一致的例子,假设有一个表 t :

    CREATE TABLE `t` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    `c` int(11) unsigned DEFAULT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB;
    insert into t(c) values(1),(2),(3);

    主库和备库上都是 3 行数据,接下来,业务人员要继续在表 t 上执行两条插入语句的命令

    nsert into t(c) values(4);
    insert into t(c) values(5);

    假设,现在主库上其他的数据表有大量的更新,导致主备延迟达到 5 秒,在插入一条 c=4 的语句后,发起了主备切换

    下图为可用性策略,且 binlog_format=mixed 时的切换流程和数据结果

    现在,我们一起分析下这个切换流程:
    1.  步骤 2 中,主库 A 执行完 insert 语句,插入了一行数据( 4,4 ),之后使用可用性策略开始进行主备切换。不等主备数据同步,直接把连接切到备库B ,并且让备库 B 可以读写
    2.  步骤 3 中,主备切换完成。由于主备之间有 5 秒的延迟,也就是说备库B执行完中转日志的事务后与主库执行完该事务差了5秒,

    所以在这5秒内,备库 B 还没来得及应用 “ 插入 c=4” 这个中转日志,就开始接收客户端 “ 插入 c=5” 的命令。
    3.  步骤 4 中,备库 B 插入了一行数据( 4,5 ),并且把这个 binlog 发给主库 A 。
    4.  步骤 5 中,备库 B 终于执行 “ 插入 c=4” 这个中转日志,插入了一行数据( 5,4 )。而直接在备库 B 执行的 “ 插入 c=5” 这个语句,传到主库 A ,就插入了一行新数据( 5,5 )。

    最后的结果就是,主库 A 和备库 B 上出现了两行不一致的数据。

    还是用 可用性优先策略,但设置 binlog_format=row 后:

    因为 row 格式在记录 binlog 的时候,会记录新插入的行的所有字段值,所以最后只会有一行不一致。而且,两边的主备同步的应用线程会报错 duplicate key error 并停止。也就是说,这种情况下,备库 B 的 (5,4) 和主库 A 的 (5,5) 这两行数据,都不会被对方执行。

    使用 row 格式的 binlog 时,数据不一致的问题更容易被发现。大多数情况下,我都建议你使用可靠性优先策略。毕竟对数据服务来说的话,数据的可靠性一般还是要优于可用性的

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    展开全文
  • 时间系统、进程的调度与切换

    千次阅读 多人点赞 2013-09-16 19:13:24
    一、时间系统 大部分PC 机中有两个时钟源,他们分别叫做RTC 和OS(操作系统)时钟。RTC(Real Time Clock,实时时钟)也叫做CMOS 时钟,它是PC 主机板上的一块芯片(或者叫做时钟电路),它靠电池供电,即使系统...
  • 分布式系统降级策略(一)

    千次阅读 2018-07-13 09:57:39
    在开发高并发系统时,有很多方法来保护系统,如:缓存、降级、限流等。下面将介绍一下降级的策略。当系统访问量增多,服务响应时间长或者非核心服务影响了核心服务的性能时。这是如果需要保证核心服务的可用性,就...
  • 操作系统的调度策略

    千次阅读 2016-05-18 12:05:31
    调度程序:挑选就绪进程的内核函数: 调度策略(依据什么原则挑选进程/线程? ) 调度时机(什么时候进行调度?)调度时机 在进程/线程的生命周期中的什么时候进行调度?... 进程从等待切换到就绪调度策略: 确
  • Windows Server 2008配置系统安全策略

    千次阅读 2020-02-24 10:47:17
    下面学习Windows Server 2008配置系统安全策略 在工作组中的计算机本地安全策略有 用户策略,密码策略,密码过期默认42天 服务账户设置成永不过期,帐户锁定策略,本地策略,审核策略,计算机记录哪些安全事件 ...
  • 几种常见的操作系统调度策略

    千次阅读 2018-07-08 21:41:50
    但如果是Pi>Pj,则立即停止Pj的执行,做进程切换,使i 进程投入执行。显然,这种抢占式的优先权调度算法能更好地满足紧迫作业的要求,故而常用于要求比较严格的实时系统中,以及对性能要求较高的批处理和分时系统中...
  • 【分布式系统】唯一ID生成策略总结

    千次阅读 多人点赞 2021-01-30 11:55:27
    全局唯一id特点:常见全局唯一id生成策略    1、数据库自增长序列或字段生成id 全局唯一id介绍     系统唯一id是我们在设计阶段常常遇到的问题。在复杂的分布式系统中,几乎都需要对大量的数据...
  • 需要把旧的推荐服务逐步切换到新的推荐服务上,需要灰度切换,流量比例和灰度策略可以控制。   二. 方案 当前数据请求流程是:外部请求—&gt;易车nginx ---&gt;后端服务 ; 经过跟运维沟通发现,目前...
  • 本文从设计模式中的策略模式入手,主讲了飞机大战中英雄飞机切换不同的子弹。这里分为三种子弹。第一种:每次发一个子弹,垂直发射;第二种:每次发两个子弹,两个都是垂直发射:第三种;每次发三个子弹,两边的子弹有...
  • 算法的封装与切换——策略模式(三)

    万次阅读 多人点赞 2012-08-01 16:56:27
    24.3 完整解决方案 为了实现打折算法的复用,并能够灵活地向系统中增加新的打折方式,Sunny软件公司开发人员使用策略模式对电影院打折方案进行重构,重构后基本结构如图24-2所示: 在图24-2中,MovieTicket充当...
  • 操作系统进程调度,优先级反转,调度策略,linux进程调度策略
  • 算法的封装与切换——策略模式(二)

    万次阅读 多人点赞 2012-08-01 16:44:31
    24.2 策略模式概述 在策略模式中,我们可以定义一些独立的类来封装不同的算法,每一个类封装一种具体的算法,在这里,每一个封装算法的类我们都可以称之为一种策略(Strategy),为了保证这些策略在使用时具有一致性...
  • 今天用win7安装xna时,出现了“系统管理员设置了系统策略,禁止进行此安装“,网上有很多介绍方法,其中一项是: 删除 HKEY_CLASSES_ROOT\Installer\Products\4080110900063D11C8EF10054038389C 注册表项目,但是我...
  • 算法的封装与切换——策略模式(四)

    万次阅读 多人点赞 2012-08-01 17:08:48
    24.4 策略模式的两个典型应用 策略模式实用性强、扩展性好,在软件开发中得以广泛使用,是使用频率较高的设计模式之一。下面将介绍策略模式的两个典型应用实例,一个来源于Java SE,一个来源于微软公司推出的演示...
  • 数据迁移:在新旧系统切换

    千次阅读 2014-01-22 22:13:11
    在新旧系统切换过程中,必然要面临一个数据迁移的问题。  数据迁移的概念  原有的旧系统从启用到被新系统取代,在其使用期间往往积累了大量珍贵的历史数据,其中许多历史数据都是新系统顺利启用所必须的。另外...
  • 操作系统中的进程调度策略有哪几种

    万次阅读 多人点赞 2018-09-22 09:00:39
    批处理系统常用调度算法: ①、先来先服务: FCFS ②、最短作业优先 ③、最短剩余时间优先 ④、响应比最高者优先 分时系统调度算法: ①、轮转调度 ②、优先级调度 ③、多级队列调度 ④、彩票...
  • 本文禁止转载,如有需求,请联系作者。 什么是屏幕刷新率,什么是应用显示帧率。 如何修改LCD的刷新率。 Android的显示刷新率切换策略
  • 法的复用性差,如果在另一个系统(如商场销售管理系统)中需要重用某些打折算法,只能通过对源代码进行复制粘贴来重用,无法单独重用其中的某个或某些算法(重用较为麻烦)。  如何解决这三个问题?导致产生这些...
  • Linux的IO系统常用系统调用及分析

    千次阅读 2012-12-22 14:23:51
    在这里我对Linux的磁盘IO的常用系统调用进行深入一些的分析,希望在大家在磁盘IO产生瓶颈的时候,能够帮助做优化,同时我也是对之前的一篇博文作总结。转载此文请标明出处:...
  • 1、Linux系统刚装完,切换不到root权限,这是因为没有创立密码的原因。 输入命令:sudo passwd,按照提示,设定unix密码。 这个密码就是你切换到root权限时的密码。这个密码 和 你开机登录时的密码是没有关系的,...
  • 算法的封装与切换——策略模式(一)

    万次阅读 多人点赞 2012-08-01 16:14:36
    软件公司为某电影院开发了一套影院售票系统,在该系统中需要为不同类型的用户提供不同的电影票打折方式,具体打折方案如下:  (1) 学生凭学生证可享受票价 8 折优惠;  (2) 年龄在 10 周岁及以下的儿童可享受每...
  • 本篇文章是对推荐系统的学习总结,首先从推荐请求处理的整个流程中抽象出系统的几个核心方面:内容特征、用户画像、召回、排序、重排,其中包含了常见的召回和重排策略。最后从产品角度出发,对推荐策略的选择的一些...
  • 我们常常会听说,某个互联网应用的服务器端系统多么牛逼,比如QQ、微信、淘宝。那么,一个互联网应用的服务器端系统,到底牛逼在什么地方?为什么海量的用户访问,会让一个服务器端系统变得更复杂?本文就是想从最...
  • 音频输出的方式有很多种,外放即扬声器(Speaker)、听筒(Telephone Receiver)、有线耳机(WiredHeadset)、蓝牙音箱(Bluetooth A2DP)等,电话免提、插拔耳机、连接断开蓝牙设备等操作系统都会自动切换Audio音频...
  • java线程池与五种常用线程池策略使用与解析

    万次阅读 多人点赞 2016-07-09 18:23:46
    java线程池与四种常用线程池策略使用与解析 一.线程池 关于为什么要使用线程池久不赘述了,首先看一下java中作为线程池Executor底层实现类的ThredPoolExecutor的构造函数 public ThreadPoolExecutor(int ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 191,083
精华内容 76,433
关键字:

常用的系统切换策略