??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲理论在线观看,亚洲欧洲日产国产综合网,中文有码亚洲制服av片http://www.tkk7.com/jelver/category/31068.html“一直很多h说我是天才,但我却相信这个世界没有天才。如果没有卓的努力和娴熟的球性,你永q不会踢出精彩的球。我从来不会低估努力的重要性,而这正是我对自己的要求。? ----------------------------------------------------------------------------|纳_奥(Ronaldinho)-------- “不要叫我神童!我不是神童!我所获得的一切成,都是我用汗水和刻苦训l换来的Q?--------------------------丁俊辉(中国斯诺克公开赛冠军)--- zh-cnFri, 16 May 2008 04:49:32 GMTFri, 16 May 2008 04:49:32 GMT60用Java实现断点l传(HTTP)http://www.tkk7.com/jelver/articles/200827.html冰河快狼冰河快狼Fri, 16 May 2008 03:12:00 GMThttp://www.tkk7.com/jelver/articles/200827.htmlhttp://www.tkk7.com/jelver/comments/200827.htmlhttp://www.tkk7.com/jelver/articles/200827.html#Feedback0http://www.tkk7.com/jelver/comments/commentRss/200827.htmlhttp://www.tkk7.com/jelver/services/trackbacks/200827.html本文介绍了一U利?Java 来实现断点箋传的Ҏ?/blockquote>

断点l传的原?/span> 原文http://www.ibm.com/developerworks/cn/java/joy-down/index.html

其实断点l传的原理很单,是在Http的请求上和一般的下蝲有所不同而已?
打个比方Q浏览器h服务器上的一个文Ӟ所发出的请求如下:
假设服务器域名ؓwwww.sjtu.edu.cnQ文件名为down.zip?
GET /down.zip HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-
excel, application/msword, application/vnd.ms-powerpoint, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
Connection: Keep-Alive

服务器收到请求后Q按要求Lh的文Ӟ提取文g的信息,然后q回l浏览器Q返回信息如下:

200
Content-Length=106786028
Accept-Ranges=bytes
Date=Mon, 30 Apr 2001 12:56:11 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT

所谓断点箋传,也就是要从文件已l下载的地方开始l下载。所以在客户端浏览器传给 Web服务器的时候要多加一条信?-从哪里开始?
下面是用自己~的一?览?来传递请求信息给Web服务器,要求?000070字节开始?
GET /down.zip HTTP/1.0
User-Agent: NetFox
RANGE: bytes=2000070-
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

仔细看一下就会发现多了一行RANGE: bytes=2000070-
q一行的意思就是告诉服务器down.zipq个文g?000070字节开始传Q前面的字节不用传了?
服务器收到这个请求以后,q回的信息如下:
206
Content-Length=106786028
Content-Range=bytes 2000070-106786027/106786028
Date=Mon, 30 Apr 2001 12:55:20 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT

和前面服务器q回的信息比较一下,׃发现增加了一行:
Content-Range=bytes 2000070-106786027/106786028
q回的代码也改ؓ206了,而不再是200了?

知道了以上原理,可以进行断点箋传的~程了?





回页?/strong>


Java实现断点l传的关键几?/span>

  1. (1)用什么方法实现提交RANGE: bytes=2000070-?
    当然用最原始的Socket是肯定能完成的,不过那样太费事了Q其实Java的net包中提供了这U功能。代码如下:

    URL url = new URL("http://www.sjtu.edu.cn/down.zip");
    HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();

    //讄User-Agent
    httpConnection.setRequestProperty("User-Agent","NetFox");
    //讄断点l传的开始位|?
    httpConnection.setRequestProperty("RANGE","bytes=2000070");
    //获得输入?
    InputStream input = httpConnection.getInputStream();

    从输入流中取出的字节就是down.zip文g?000070开始的字节。大家看Q其实断点箋传用Java实现hq是很简单的吧。接下来要做的事是怎么保存获得的流到文件中M?

  2. 保存文g采用的方法?
    我采用的是IO包中的RandAccessFilecR?
    操作相当单,假设?000070处开始保存文Ӟ代码如下Q?
    RandomAccess oSavedFile = new RandomAccessFile("down.zip","rw");
    long nPos = 2000070;
    //定位文g指针到nPos位置
    oSavedFile.seek(nPos);
    byte[] b = new byte[1024];
    int nRead;
    //从输入流中读入字节流Q然后写到文件中
    while((nRead=input.read(b,0,1024)) > 0)
    {
    oSavedFile.write(b,0,nRead);
    }

怎么P也很单吧。接下来要做的就是整合成一个完整的E序了。包括一pd的线E控制等{?





回页?/strong>


断点l传内核的实?/span>

主要用了6个类Q包括一个测试类?
SiteFileFetch.java负责整个文g的抓取,控制内部U程(FileSplitterFetchc??
FileSplitterFetch.java负责部分文g的抓取?
FileAccess.java负责文g的存储?
SiteInfoBean.java要抓取的文g的信息,如文件保存的目录Q名字,抓取文g的URL{?
Utility.java工具c,放一些简单的Ҏ?
TestMethod.java试cR?

下面是源E序Q?/p>
/*
            **SiteFileFetch.java
            */
            package NetFox;
            import java.io.*;
            import java.net.*;
            public class SiteFileFetch extends Thread {
            SiteInfoBean siteInfoBean = null; //文g信息Bean
            long[] nStartPos; //开始位|?
            long[] nEndPos; //l束位置
            FileSplitterFetch[] fileSplitterFetch; //子线E对?
            long nFileLength; //文g长度
            boolean bFirst = true; //是否W一ơ取文g
            boolean bStop = false; //停止标志
            File tmpFile; //文g下蝲的时信?
            DataOutputStream output; //输出到文件的输出?
            public SiteFileFetch(SiteInfoBean bean) throws IOException
            {
            siteInfoBean = bean;
            //tmpFile = File.createTempFile ("zhong","1111",new File(bean.getSFilePath()));
            tmpFile = new File(bean.getSFilePath()+File.separator + bean.getSFileName()+".info");
            if(tmpFile.exists ())
            {
            bFirst = false;
            read_nPos();
            }
            else
            {
            nStartPos = new long[bean.getNSplitter()];
            nEndPos = new long[bean.getNSplitter()];
            }
            }
            public void run()
            {
            //获得文g长度
            //分割文g
            //实例FileSplitterFetch
            //启动FileSplitterFetchU程
            //{待子线E返?
            try{
            if(bFirst)
            {
            nFileLength = getFileSize();
            if(nFileLength == -1)
            {
            System.err.println("File Length is not known!");
            }
            else if(nFileLength == -2)
            {
            System.err.println("File is not access!");
            }
            else
            {
            for(int i=0;i<nStartPos.length;i++)
            {
            nStartPos[i] = (long)(i*(nFileLength/nStartPos.length));
            }
            for(int i=0;i<nEndPos.length-1;i++)
            {
            nEndPos[i] = nStartPos[i+1];
            }
            nEndPos[nEndPos.length-1] = nFileLength;
            }
            }
            //启动子线E?
            fileSplitterFetch = new FileSplitterFetch[nStartPos.length];
            for(int i=0;i<nStartPos.length;i++)
            {
            fileSplitterFetch[i] = new FileSplitterFetch(siteInfoBean.getSSiteURL(),
            siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(),
            nStartPos[i],nEndPos[i],i);
            Utility.log("Thread " + i + " , nStartPos = " + nStartPos[i] + ", nEndPos = " + nEndPos[i]);
            fileSplitterFetch[i].start();
            }
            // fileSplitterFetch[nPos.length-1] = new FileSplitterFetch(siteInfoBean.getSSiteURL(),
            siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(),nPos[nPos.length-1],nFileLength,nPos.length-1);
            // Utility.log("Thread " + (nPos.length-1) + " , nStartPos = " + nPos[nPos.length-1] + ",
            nEndPos = " + nFileLength);
            // fileSplitterFetch[nPos.length-1].start();
            //{待子线E结?
            //int count = 0;
            //是否l束while循环
            boolean breakWhile = false;
            while(!bStop)
            {
            write_nPos();
            Utility.sleep(500);
            breakWhile = true;
            for(int i=0;i<nStartPos.length;i++)
            {
            if(!fileSplitterFetch[i].bDownOver)
            {
            breakWhile = false;
            break;
            }
            }
            if(breakWhile)
            break;
            //count++;
            //if(count>4)
            // siteStop();
            }
            System.err.println("文g下蝲l束Q?);
            }
            catch(Exception e){e.printStackTrace ();}
            }
            //获得文g长度
            public long getFileSize()
            {
            int nFileLength = -1;
            try{
            URL url = new URL(siteInfoBean.getSSiteURL());
            HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection ();
            httpConnection.setRequestProperty("User-Agent","NetFox");
            int responseCode=httpConnection.getResponseCode();
            if(responseCode>=400)
            {
            processErrorCode(responseCode);
            return -2; //-2 represent access is error
            }
            String sHeader;
            for(int i=1;;i++)
            {
            //DataInputStream in = new DataInputStream(httpConnection.getInputStream ());
            //Utility.log(in.readLine());
            sHeader=httpConnection.getHeaderFieldKey(i);
            if(sHeader!=null)
            {
            if(sHeader.equals("Content-Length"))
            {
            nFileLength = Integer.parseInt(httpConnection.getHeaderField(sHeader));
            break;
            }
            }
            else
            break;
            }
            }
            catch(IOException e){e.printStackTrace ();}
            catch(Exception e){e.printStackTrace ();}
            Utility.log(nFileLength);
            return nFileLength;
            }
            //保存下蝲信息Q文件指针位|)
            private void write_nPos()
            {
            try{
            output = new DataOutputStream(new FileOutputStream(tmpFile));
            output.writeInt(nStartPos.length);
            for(int i=0;i<nStartPos.length;i++)
            {
            // output.writeLong(nPos[i]);
            output.writeLong(fileSplitterFetch[i].nStartPos);
            output.writeLong(fileSplitterFetch[i].nEndPos);
            }
            output.close();
            }
            catch(IOException e){e.printStackTrace ();}
            catch(Exception e){e.printStackTrace ();}
            }
            //d保存的下载信息(文g指针位置Q?
            private void read_nPos()
            {
            try{
            DataInputStream input = new DataInputStream(new FileInputStream(tmpFile));
            int nCount = input.readInt();
            nStartPos = new long[nCount];
            nEndPos = new long[nCount];
            for(int i=0;i<nStartPos.length;i++)
            {
            nStartPos[i] = input.readLong();
            nEndPos[i] = input.readLong();
            }
            input.close();
            }
            catch(IOException e){e.printStackTrace ();}
            catch(Exception e){e.printStackTrace ();}
            }
            private void processErrorCode(int nErrorCode)
            {
            System.err.println("Error Code : " + nErrorCode);
            }
            //停止文g下蝲
            public void siteStop()
            {
            bStop = true;
            for(int i=0;i<nStartPos.length;i++)
            fileSplitterFetch[i].splitterStop();
            }
            }
            /*
            **FileSplitterFetch.java
            */
            package NetFox;
            import java.io.*;
            import java.net.*;
            public class FileSplitterFetch extends Thread {
            String sURL; //File URL
            long nStartPos; //File Snippet Start Position
            long nEndPos; //File Snippet End Position
            int nThreadID; //Thread's ID
            boolean bDownOver = false; //Downing is over
            boolean bStop = false; //Stop identical
            FileAccessI fileAccessI = null; //File Access interface
            public FileSplitterFetch(String sURL,String sName,long nStart,long nEnd,int id) throws IOException
            {
            this.sURL = sURL;
            this.nStartPos = nStart;
            this.nEndPos = nEnd;
            nThreadID = id;
            fileAccessI = new FileAccessI(sName,nStartPos);
            }
            public void run()
            {
            while(nStartPos < nEndPos && !bStop)
            {
            try{
            URL url = new URL(sURL);
            HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection ();
            httpConnection.setRequestProperty("User-Agent","NetFox");
            String sProperty = "bytes="+nStartPos+"-";
            httpConnection.setRequestProperty("RANGE",sProperty);
            Utility.log(sProperty);
            InputStream input = httpConnection.getInputStream();
            //logResponseHead(httpConnection);
            byte[] b = new byte[1024];
            int nRead;
            while((nRead=input.read(b,0,1024)) > 0 && nStartPos < nEndPos && !bStop)
            {
            nStartPos += fileAccessI.write(b,0,nRead);
            //if(nThreadID == 1)
            // Utility.log("nStartPos = " + nStartPos + ", nEndPos = " + nEndPos);
            }
            Utility.log("Thread " + nThreadID + " is over!");
            bDownOver = true;
            //nPos = fileAccessI.write (b,0,nRead);
            }
            catch(Exception e){e.printStackTrace ();}
            }
            }
            //打印回应的头信息
            public void logResponseHead(HttpURLConnection con)
            {
            for(int i=1;;i++)
            {
            String header=con.getHeaderFieldKey(i);
            if(header!=null)
            //responseHeaders.put(header,httpConnection.getHeaderField(header));
            Utility.log(header+" : "+con.getHeaderField(header));
            else
            break;
            }
            }
            public void splitterStop()
            {
            bStop = true;
            }
            }
            /*
            **FileAccess.java
            */
            package NetFox;
            import java.io.*;
            public class FileAccessI implements Serializable{
            RandomAccessFile oSavedFile;
            long nPos;
            public FileAccessI() throws IOException
            {
            this("",0);
            }
            public FileAccessI(String sName,long nPos) throws IOException
            {
            oSavedFile = new RandomAccessFile(sName,"rw");
            this.nPos = nPos;
            oSavedFile.seek(nPos);
            }
            public synchronized int write(byte[] b,int nStart,int nLen)
            {
            int n = -1;
            try{
            oSavedFile.write(b,nStart,nLen);
            n = nLen;
            }
            catch(IOException e)
            {
            e.printStackTrace ();
            }
            return n;
            }
            }
            /*
            **SiteInfoBean.java
            */
            package NetFox;
            public class SiteInfoBean {
            private String sSiteURL; //Site's URL
            private String sFilePath; //Saved File's Path
            private String sFileName; //Saved File's Name
            private int nSplitter; //Count of Splited Downloading File
            public SiteInfoBean()
            {
            //default value of nSplitter is 5
            this("","","",5);
            }
            public SiteInfoBean(String sURL,String sPath,String sName,int nSpiltter)
            {
            sSiteURL= sURL;
            sFilePath = sPath;
            sFileName = sName;
            this.nSplitter = nSpiltter;
            }
            public String getSSiteURL()
            {
            return sSiteURL;
            }
            public void setSSiteURL(String value)
            {
            sSiteURL = value;
            }
            public String getSFilePath()
            {
            return sFilePath;
            }
            public void setSFilePath(String value)
            {
            sFilePath = value;
            }
            public String getSFileName()
            {
            return sFileName;
            }
            public void setSFileName(String value)
            {
            sFileName = value;
            }
            public int getNSplitter()
            {
            return nSplitter;
            }
            public void setNSplitter(int nCount)
            {
            nSplitter = nCount;
            }
            }
            /*
            **Utility.java
            */
            package NetFox;
            public class Utility {
            public Utility()
            {
            }
            public static void sleep(int nSecond)
            {
            try{
            Thread.sleep(nSecond);
            }
            catch(Exception e)
            {
            e.printStackTrace ();
            }
            }
            public static void log(String sMsg)
            {
            System.err.println(sMsg);
            }
            public static void log(int sMsg)
            {
            System.err.println(sMsg);
            }
            }
            /*
            **TestMethod.java
            */
            package NetFox;
            public class TestMethod {
            public TestMethod()
            { ///xx/weblogic60b2_win.exe
            try{
            SiteInfoBean bean = new SiteInfoBean("http://localhost/xx/weblogic60b2_win.exe","L:\\temp","weblogic60b2_win.exe",5);
            //SiteInfoBean bean = new SiteInfoBean("http://localhost:8080/down.zip","L:\\temp","weblogic60b2_win.exe",5);
            SiteFileFetch fileFetch = new SiteFileFetch(bean);
            fileFetch.start();
            }
            catch(Exception e){e.printStackTrace ();}
            }
            public static void main(String[] args)
            {
            new TestMethod();
            }
            }
            


冰河快狼 2008-05-16 11:12 发表评论
]]>
从LiveJournal后台发展看大规模|站性能优化Ҏhttp://www.tkk7.com/jelver/articles/196656.html冰河快狼冰河快狼Sun, 27 Apr 2008 14:15:00 GMThttp://www.tkk7.com/jelver/articles/196656.htmlhttp://www.tkk7.com/jelver/comments/196656.htmlhttp://www.tkk7.com/jelver/articles/196656.html#Feedback0http://www.tkk7.com/jelver/comments/commentRss/196656.htmlhttp://www.tkk7.com/jelver/services/trackbacks/196656.html一、LiveJournal发展历程 LiveJournal?9q始于校园中的项目,几个人出于爱好做了这样一个应用,以实C下功能:
  • 博客Q论?
  • C会性网l,扑ֈ朋友
  • 聚合Q把朋友的文章聚合在一?/li>
LiveJournal采用了大量的开源YӞ甚至它本w也是一个开源Y件?

在上U后QLiveJournal实现了非常快速的增长Q?/p>

  • 2004q?月䆾Q?80万注册用戗?
  • 2005q?月䆾Q?80万注册用戗?
  • 2005q?月䆾Q?90万注册用戗?
  • 辑ֈ了每U钟上千ơ的面h及处理?
  • 使用了大量MySQL服务器?
  • 使用了大量通用lg?/li>

二、LiveJournal架构现状概况

livejournal_backend.png

三、从LiveJournal发展中学?/h2>

 

LiveJournal?台服务器发展?00台服务器Q这其中l历了无数的伤痛Q但同时也摸索出了解册些问题的ҎQ通过对LiveJournal的学习,可以让我们避免LJ曄犯过的错误,q且从一开始就对系l进行良好的设计Q以避免后期的痛苦?/p>

下面我们一步一步看LJ发展的脚步?/p>

1、一台服务器

一台别人捐助的服务器,LJ最初就跑在上面Q就像Google开始时候用的破服务器一P值得我们敬。这个阶D,LJ的h以惊人的速度熟悉的Unix的操作管理,服务器性能出现q问题,不过q好Q可以通过一些小修小改应付过厅R在q个阶段里LJ把CGI升CFastCGI?/p>

最l问题出CQ网站越来越慢,已经无法通过优过化来解决的地步,需要更多的服务器,q时LJ开始提供付Ҏ务,可能是想通过q些钱来购买新的服务器,以解军_时的困境?br /> 毫无疑问Q当时LJ存在巨大的单炚w题,所有的东西都在那台服务器的铁皮盒子里装着?/p>

LJ-backend-7.png

2、两台服务器

用付Ҏ务赚来的钱LJC两台服务器:一台叫做Kenny的Dell 6U机器用于提供Web服务Q一台叫做Cartman的Dell 6U服务器用于提供数据库服务?/p>

LJ-backend-8.png

LJ有了更大的磁盘,更多的计资源。但同时|络l构q是非常单,每台机器两块|卡QCartman通过内网为Kenny提供MySQL数据库服务?br />
暂时解决了负载的问题Q新的问题又出现了:

  • 原来的一个单点变成了两个单点?
  • 没有冷备份或热备份?
  • |站速度慢的问题又开始出CQ没办法Q增长太快了?
  • Web服务器上CPU辑ֈ上限Q需要更多的Web服务器?/li>

3、四台服务器

又买了两収ͼKyle和StanQ这ơ都?U的,都用于提供Web服务。目前LJ一共有3台Web服务器和一台数据库服务器。这旉要在3台Web服务器上q行负蝲均横?/p>

LJ-backend-9.png

LJ把Kenny用于外部的网养I使用mod_backhandq行负蝲均横?/p>

然后问题又出CQ?/p>

  • 单点故障。数据库和用于做|关的Web服务器都是单点,一旦Q何一台机器出现问题将D所有服务不可用。虽然用于做|关的Web服务器可以通过保持心蟩同步q速切换,但还是无法解x据库的单点,LJ当时也没做这个?
  • |站又变慢了Q这ơ是因ؓIO和数据库的问题,问题是怎么往应用里面d数据库呢Q?/li>

4、五台服务器

又买了一台数据库服务器。在两台数据库服务器上用了数据库同?Mysql支持的Master-Slave模式)Q写操作全部针对L据库Q通过BinlogQ主服务器上的写操作可以q速同步到从服务器上)Q读操作在两个数据库上同时进?也算是负载均横的一U吧)?/p>

LJ-backend-10.png

实现同步时要注意几个事项Q?/p>

  • L作数据库选择法处理Q要选一个当前负载轻一点的数据库?
  • 在从数据库服务器上只能进行读操作
  • 准备好应对同步过E中的gq,处理不好可能会导致数据库同步的中断。只需要对写操作进行判断即可,L作不存在同步问题?/li>

5、更多服务器

有钱了,当然要多C服务器。部|后快了没多久,又开始慢了。这ơ有更多的Web服务器,更多的数据库服务器,存在 IO与CPU争用。于是采用了BIG-IP作ؓ负蝲均衡解决Ҏ?/p>

LJ-backend-11.png

6、现在我们在哪里Q?/h2>

LJ-backend-1.png

现在服务器基本上够了Q但性能q是有问题,原因出在架构上?/p>

数据库的架构是最大的问题。由于增加的数据库都是以Slave模式d到应用内Q这样唯一的好处就是将L作分布到了多台机器,但这样带来的后果是写操作被大量分发Q每台机器都要执行,服务器越多,费p大,随着写操作的增加Q用于服务读操作的资源越来越?/p>

LJ-backend-2.png

׃台分布到两台

LJ-backend-3.png

最l效?/p>

现在我们发现Q我们ƈ不需要把q些数据在如此多的服务器上都保留一份。服务器上已l做了RAIDQ数据库也进行了备䆾Q这么多的备份完全是对资源的费Q属于冗余极端过度。那Z么不把数据分布存储呢Q?/p>

问题发现了,开始考虑如何解决。现在要做的是把不同用L数据分布C同的服务器上q行存储Q以实现数据的分布式存储Q让每台机器只ؓ相对固定的用h务,以实现^行的架构和良好的可扩展性?/p>

Z实现用户分组Q我们需要ؓ每一个用户分配一个组标记Q用于标记此用户的数据存攑֜哪一l数据库服务器中。每l数据库׃个master及几个slavel成Qƈ且slave的数量在2-3収ͼ以实现系l资源的最合理分配Q既保证数据L作分布,又避免数据过度冗余以及同步操作对pȝ资源的过度消耗?/p>

LJ-backend-4.png

׃収ͼ一l)中心服务器提供用户分l控制。所有用L分组信息都存储在q台机器上,所有针对用L操作需要先查询q台机器得到用户的组P然后再到相应的数据库l中获取数据?/p>

q样的用h构与目前LJ的架构已l很相像了?/p>

在具体的实现旉要注意几个问题:

  • 在数据库l内不要使用自增IDQ以便于以后在数据库l之间迁UȝP以实现更合理的I/OQ磁盘空间及负蝲分布?
  • useridQpostid存储在全局服务器上Q可以用自增,数据库组中的相应值必M全局服务器上的gؓ准。全局服务器上使用事务型数据库InnoDB?
  • 在数据库l之间迁Uȝh要万分小心,当迁UL用户不能有写操作?/li>

7、现在我们在哪里

LJ-backend-5.png

问题Q?/p>

  • 一个全局L务器Q挂掉的话所有用h册及写操作就挂掉?
  • 每个数据库组一个主服务器,挂掉的话q组用户的写操作挂掉?
  • 数据库组从服务器挂掉的话会导致其它服务器负蝲q大?/li>

对于Master-Slave模式的单炚w题,LJ采取了Master-Master模式来解冟뀂所谓Master-Master实际上是人工实现的,q不是由MySQL直接提供的,实际上也是两台机器同时是MasterQ也同时是SlaveQ互相同步?/p>

Master-Master实现旉要注意:

  • 一个Master出错后恢复同步,最好由服务器自动完成?
  • 数字分配Q由于同时在两台机器上写Q有些ID可能会冲H?/li>

解决ҎQ?br />

  • 奇偶数分配IDQ一台机器上写奇敎ͼ一台机器上写偶?
  • 通过全局服务器进行分?LJ采用的做??/li>

 

Master-Master模式q有一U用法,q种Ҏ与前一U相比,仍然保持两台机器的同步,但只有一台机器提供服务(d写)Q在每天晚上的时候进行轮换,或者出现问题的时候进行切换?/p>

8、现在我们在哪里

LJ-backend-6.png

现在插播一条广告,MyISAM VS InnoDB?/p>

使用InnoDBQ?/p>

  • 支持事务
  • 需要做更多的配|,不过值得Q可以更安全的存储数据,以及得到更快的速度?/li>

使用MyISAMQ?/p>

  • 记录日志QLJ用它来记|络讉K日志Q?
  • 存储只读静态数据,_快?
  • q发性很差,无法同时d数据Q添加数据可以)
  • MySQL非正常关闭或L时会D索引错误Q需要用myisamchk修复Q而且当访问量大时出现非常频繁?/li>

9、缓?/h2>

d我写q?a >一文章介lmemcachedQ它是由LJ的团队开发的一Ƅ存工P以key-value的方式将数据存储到分布的内存中。LJ~存的数据:

  • 12台独立服务器Q不是捐赠的Q?
  • 28个实?
  • 30GBd?
  • 90-93%的命中率Q用qsquid的h可能知道Qsquid内存加磁盘的命中率大概在70-80%Q?/li>

如何建立~存{略Q?/p>

想缓存所有的东西Q那是不可能的,我们只需要缓存已l或者可能导致系l瓶颈的地方Q最大程度的提交pȝq行效率。通过对MySQL的日志的分析我们可以扑ֈ~存的对象?/p>

~存的缺点?

  • 没有完美的事物,~存也有~点Q?
  • 增大开发量Q需要针对缓存处理编写特D的代码?
  • 理隑ֺ增加Q需要更多h参与pȝl护?
  • 当然大内存也需要钱?/li>

10、Web讉K负蝲均衡

在数据包U别使用BIG-IPQ但BIG-IPq不知道我们内部的处理机Ӟ无法判断由哪台服务器对这些请求进行处理。反向代理ƈ不能很好的vC用,不是已经够快了,是达不到我们想要的效果?/p>

所以,LJ又开发了Perlbal。特点:

  • 快,,可管理的http web 服务?代理
  • 可以在内部进行{?
  • 使用Perl开?
  • 单线E,异步Q基于事Ӟ使用epoll , kqueue
  • 支持Console理与httpq程理Q支持动态配|加?
  • 多种模式Qweb服务器,反向代理Q插?
  • 支持插gQGIF/PNG互换Q?/li>

11、MogileFS

LJ使用开源的MogileFS作ؓ分布式文件存储系l。MogileFS使用非常单,它的主要设计思想是:

  • 文g属于c(cL最的复制单位Q?
  • 跟踪文g存储位置
  • 在不同主Z存储
  • 使用MySQL集群l一存储分布信息
  • 大容易廉L?/li>

到目前ؓ止就q么多了Q更多文档可以在http://www.danga.com/words/扑ֈ?a >Danga.com?a >LiveJournal.com的同学们拿这个文档参加了两次MySQL ConQ两ơOS ConQ以及众多的其它会议Q无U的把他们的l验分n出来Q值得我们学习。在web2.0时代快速开发得到大家越来越多的重视Q但良好的设计仍是每一个应用的基础Q希望web2.0们在成长为Top500|站的\上,不要因ؓ架构ȝ了网站的发展?/p>

参考资料:http://www.danga.com/words/2005_oscon/oscon-2005.pdf

感谢向静推荐了这文档给我?/p>



冰河快狼 2008-04-27 22:15 发表评论
]]>电媄服务器流媒体关键技?/title><link>http://www.tkk7.com/jelver/articles/196409.html</link><dc:creator>冰河快狼</dc:creator><author>冰河快狼</author><pubDate>Sun, 27 Apr 2008 02:31:00 GMT</pubDate><guid>http://www.tkk7.com/jelver/articles/196409.html</guid><wfw:comment>http://www.tkk7.com/jelver/comments/196409.html</wfw:comment><comments>http://www.tkk7.com/jelver/articles/196409.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/jelver/comments/commentRss/196409.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/jelver/services/trackbacks/196409.html</trackback:ping><description><![CDATA[<strong>引言</strong> <br /> <br /> q年来,随着计算机技术、压~技术以及网l技术的发展Q网l中的流媒体业务也得C飞速的发展和应用。所谓流媒体是指在 Internet/Intranet中用流式传输技术的q箋时基媒体。本文中着重介l视频流。目前在Internet上传输视频还有许多困难,其根本原因在于Internet的无q接每包转发机制主要是ؓH发性的数据传输而设计的Q不适用于对q箋媒体的传输。ؓ了在Internet上有效地、高质量C输视频流Q还需要多U技术的支持Q例如基于视频的压羃~码技术、应用层QoS技术、连l媒体分布服务、流服务器、媒体同步技术和相关协议{?<br /> <br /> 其中Q原始视/音频l过?音频压羃法的预压羃存储在存储设备中。响应客戯求时Q流服务器从存储讑֤中获得视/音频数据Q应用层QoS控制模块Ҏ|络状态和QoS要求来改变视/音频比特。然后通过传输协议把压~过的比Ҏ打包q且发送到|上。由于拥塞数据包可能出现丢包或者过度时延。ؓ了提高视 /音频的传输质量,|络中配|了q箋媒体分布式服务。对于成功传输的数据包,它们首先通过传输层,然后在进行视/音频解码前经q应用层处理。ؓ了获得在播放中的视频和音频的同步Q还需要媒体同步机制。从上图中可以看出,q六个部分有着紧密的联p而且都是媒体结构的l成部分?br /> <br /> <strong>2 媒体中的关键技?br /> <br /> </strong><br /> <br /> 2.1 视频压羃及编?<br /> <br /> 目前|络是异构性的Q缺乏QoS质量控制Qƈ且带宽也在很大范围内变化。传l的不可扩展性视频编码的目标是将视频压羃成适合一个或者几个固定码率的码流Q是面向存储的,因此不适合|络传输。ؓ了适应|络带宽的变化,面向传输的可扩展性编码的思想应运而生。可扩展性编码[2]是多媒体数据压羃~码成多个流Q其中一个可以独立解码,产生_糙质量的视频序列,它适应最低的|络带宽Q称为基本层码流Q其他的码流可以按层为单位在M地点截断Q称为增强层Q用来覆盖网l带宽变化的动态范_它们不可以单独解码,而只能与基本层和它以前的增强层联合在一赯码,用来提高观看效果。因此,可扩展性码具有一定的|络带宽适应能力?<br /> <br /> 可扩展性编码主要分为时域可扩展性编码、空域可扩展性编码和质量可扩展性编码。可以选择在时间、空间和信噪比(SNRQ中的一个或者几个方面实现扩展。考虑到编码效率和复杂性两斚wQMPEGl织采纳了精l可扩展性编码(FGSQ和渐进的精l可扩展性编码(PFGSQ[3]。精l可扩展性视频编码采用位q面QbitplaneQ编码,它的基本层用基于分块运动补偿和DCT变换的编码方式达到网l传输的最低要求,增强层用位q面~码技术对DCTD差q行~码来覆盖网l带宽的变化范围Q它每一帧的增强层码可以在M地点截断Q解码器重徏的视频质量和收到q解码的比特数成正比Q它可以实现q箋的增强层速率控制。FGS虽然h很好的可扩展性,但是效率太低QPFGS在保留了FGS所h的网l带宽自适应和错误恢复能力的同时Q还有效地提高了~码效率。但是可扩展性编码的效率较非可扩展性编码而言Q还有一定差距。ؓ了进一步压~FGS和PFGS的基本层码流Q有专家提出一U称为精l的I域可扩展性(Fine-Granularity Spatially Scalable,FGSSQ的视频~码法Q低分辨率和高分L率的增强层码都可以在Q何地Ҏ断,h极强的网l带宽适应能力和错误恢复功能,同时保持了空域可扩展性编码的多分辨率Ҏ,它可以满x有不同网l带宽和不同分L率接收设备的许多用户的需求,性能得到了更大的提高?<br /> <br /> l合多种视频~码技术来适应|络上的QoS波动是今后可扩展性视频编码的发展方向。比如,可扩展性视频编码可以适应|络带宽的变化;错误Ҏ编码可以适应丢包QDCVCQDelay Cognizant Video CodingQ可以适应|络时g。这三种技术的l合可以更好地提供一U应对网lQoS波动的解x案?br /> <br /> 2.2 应用层QoS控制技术由于目前的Internet只提供Best-effort的服务,所以需要通过应用层的机制来实现QoS的控制。QoS控制技术主要集中在对网l带宽的变化q行响应和处理分l丢q技术上Q主要可以分Zc:拥塞控制技术和差错控制技术?<br /> <br /> 拥塞控制的目的是采用某种机制应对和避免网l阻塞,降低时g和丢包率。常用的拥塞控制机制有速率控制和速率整Ş。对于视频流Q拥塞控制的主要Ҏ是速率控制。速率控制机制试图使一个视频连接的需求与整个q接链\的可用带宽相匚wQ这样可以同时ɾ|络拥塞和包丢失率达到最。速率控制机制主要包括Z源端的、基于目的的以及混合速率控制。在Z源端的控制机制中Q视频源端收集反馈信息,q行控制计算q取相应的控制动作。这U方法在因特|中被率先采?但是在异构网l中的运行情况ƈ不是很好。基于目的端的控制机制则主要Ҏ所接收的视频流的状况向上层反映相应的统计信息,实时调整~冲及播攑ֆ容,q力图节奏均匀Q这U机制用较。؜合性速率控制的方法兼有前二者的特点Q即目的端增加减通道Q而源端同时根据反馈调整各个通道的速率。؜合速率控制Ҏ的一个例子是目标集分l的Ҏ?<br /> <br /> 拥塞控制只能减少数据包的丢失Q但是网l中不可避免的会存在数据包丢失,而且到达时gq大的分l也会被认ؓ没有用而被丢弃Q从而降低了视频质量。要改善视频质量需要一定的差错控制机制。差错控制机制包括: <br /> <br /> Q?Q前向纠错(FECQ:FEC是通过在传输的码流中加入用于纠错的冗余信息Q在遇到包丢q情况Ӟ利用冗余信息恢复丢失的信息。它的不x增加了编码时延和传输带宽?<br /> <br /> Q?Qgq约束的重传。通常的播放有时间限Ӟ因此Q仅有当重传的时间小于正常的播放旉Ӟ重传才是有h值的?<br /> <br /> Q?Q错误弹性编码(Error-Resilient EncodingQ:在编码中通过适当的控制得发生数据的丢失后能够最大限度的减少对质量的影响。在Internet环境下,最典型的方法是多描q编码(MDCQ。MDC把原始的视频序列压羃成多位流Q每个流对应一U描qͼ都可以提供可接受的视觉质量。多个描q结合v来提供更好的质量。该Ҏ的优Ҏ实现了对数据丢失的鲁性和增强的质量。其~点是相比单描述~码QSDCQ,它在压羃的效率上受到影响。而且׃在多描述之间必须加入一定的相关性信息,q进一步降低了压羃的效率?<br /> <br /> Q?Q错误的取消QconcealmentQ:错误的取消是指当错误已经发生后,接受端通过一定的Ҏ量削弱对h的视觉媄响。主要的Ҏ是时间和I间的插|InterpolationQ。近q来的研I还包括最大^滑恢复,q动补偿旉预测{?br /> <br /> 2.3 q箋媒体分布服务 <br /> <br /> q箋媒体分布服务Qcontinuous media distribution servicesQ的目的是在Internet 力服务的基上提供QoS和高效的?视频传输Q包括网l过滤(Network FilteringQ、应用层l播QApplication-Level MulticastQ、内容复ӞContent ReplicationQ等Q下面分别进行详l介l?br /> <br /> |络qoQ网l过滤是拥塞控制的一U,不仅可以提高视频质量Q还可以提高带宽利用率。不同于发送端的速率整ŞQ网l过滤是在流服务器和客户端之间的传输路径上通过虚拟信道q入qo器,该过滤器Ҏ|络的拥塞状态实现速率的整形。网l过滤通常采用的是丢qo器(frame-dropping filterQ,其基本方法是客户端根据网l丢包率向过滤器发送请求来增减丢速率Q以调节媒体的带宽。这U速率整Ş可以在拥塞点q行Q这样可以提高速率控制的效率和拥塞控制的响应时间?br /> <br /> 应用层组播:IP层的l播存在诸如可扩展性、网l管理和寚w层应用的支持Q例如差错控Ӟ量控制和拥塞控Ӟ{屏障。应用层l播机制打破了IPl播的一些障,其目的在于构建网l上的组播服务,可以以更灉|的方式实现组播控制。它允许独立?CSPs和ASPs{徏立它们的Internetl播|络Q这些组播网l可以互q成为更大的媒体l播|络。媒体组播网l可以利用内容分布网l的互连Q通过在不同种cȝ服务提供者(比如ISPs、CSPs和ASPs{)之间的应用层的对{关pL构徏。媒体组播网l中每个hl播能力的节点称为媒体桥QMediaBridgeQ,它做为应用层的\由。每个媒体桥和一个或多个盔R的媒体桥通过明确的配|互q,q个互连建立了应用层重叠拓扑。媒体桥在媒体组播网l中用分布式应用层组播\q法来定一条优化的虚拟l播路径。如果网l不通或者过度拥挤,媒体l播|络会自动的Ҏ应用层\p则来重新定路径。ƈ且,只有当下游客L需要某媒体内容Ӟ媒体桥才会传输它。这q保了不管客户端的数目而只有一个媒体流Q从而节U了|络带宽?br /> <br /> 内容复制Q内?媒体复制是提高媒体传输系l可扩展性的一w要技术。内容复制具有以下优点: <br /> <br /> Q?Q降低网l连接的带宽消耗?<br /> <br /> Q?Q减L服务器负荗?<br /> <br /> Q?Q羃短客L时g?<br /> <br /> Q?Q提高有效性。它主要有两UŞ式:cachingQ缓存)和mirroringQ镜像)。镜像是把原始媒体内Ҏ贝到|络上其他分散的备䆾服务器中。用户可以从最q的备䆾服务器上获得媒体数据。缓存则是从原服务器中获得媒体文Ӟ然后传输l客LQ同时在本地做备份。如果缓存中已经存在客户端需要的数据Q缓存就会把本地拯传给用户而不是从传送原服务器中的媒体数据?br /> <br /> 2.4 服务器视频服务器在媒体服务中L非常重要的作用。当视频服务器响应客L视频请求以后,它从存储pȝd一部分视频数据到对应于q个视频的特定~存中,再把~存的内定w过|络接口发送给相应客户Q保证视频流的连l输出。目前存在三U类型的视频服务器结构[4]Q?<br /> <br /> Q?Q通用LҎ。采用计机L作ؓ视频服务器。它的主要功能是存储、选择、传送数据。缺Ҏpȝ成本高而且不利于发挥主机功能?<br /> <br /> Q?Q紧耦合多处理机。把一些可以大量完成某指o或者专门功能的g单元l合成的专用pȝU联hQ就构成了紧耦合多处理机实现的视频服务器。这U服务器费用低、性能高、功能强Q但是扩展性较差?<br /> <br /> Q?Q调谐视频服务器。这U服务器L上有一个独特微码的嵌入式仿真器控制。通过在主板中插入更多的服务通\Q可以方便地q行扩展?br /> <br /> 对于服务器Q如何更有效支持VCR交互控制功能Q如何设计磁盘阵列上多媒体对象高效可靠的存储和检索;如何设计更好的可伸羃多媒体服务器Q如何设计兼有奇偶和镜像Ҏ的定w存储pȝ是目前研I的重点?br /> <br /> 2.5 媒体同步 <br /> <br /> 所谓媒体同步是指保持一个数据流或者不同媒体流之间的时间关pR通常有三U类型的同步控制Q流内(intra-streamQ同步、流_inter- streamQ同步和对象_inter-objectQ同步。由于网l时ӞD媒体在传输q程中失d步关p,媒体同步机制可以保客户端正地恢复媒体的同步。媒体同步机制实际上是在媒体内或者媒体间说明其时间关pR说明时间关pȝҎ有:Z间隔的方法、基于u的方法、基于控制流的方法和Z事g的方法。对于连l媒体,应用最为广泛的说明Ҏ是基于u的说明或旉戟뀂时间戳法是在每个媒体的数据单元中加进l一的时间戳或时间码Q具有相同时间戳的信息单元将同时予以表现。在发送时Q将各个媒体都按旉序分成单元Q在同一个时间u上,l每个单元都打上一个时间戳Q处于同一时标的各个媒体单元具有相同的旉戟뀂在各个媒体到达l端后,让具有相同时间戳的媒体单元同时进行表玎ͼq样得C媒体之间同步的效果。对与终端系l而言Q同步机制包括阻止(preventiveQ机制和U正QcorrectiveQ机制。前者是主要通过减小延迟和抖动来减少同步错误Q后者主要是在发生同步错误之后恢复同步。考虑到Internet传输的gq随机性,同步错误是不可避免的。因此,在接受方的错误补偿是必须的?<br /> <br /> 另外Q同步多媒体集成语言SMILQSynchronized Multimedia Integration LanguageQ是?W(World Wide Web Consortium)l织规定的多媒体操纵语言。可以实现多个流和文本信息在播放时的旉同步控制和空间位|布|。通过SMILq可以实C定的用户交互功能?br /> <br /> 2.6 媒体相兛_?br /> <br /> 2.6.1 实时传输协议QRTPQ与实时传输控制协议QRTCPQ?<br /> <br /> RTP(Real-time Transport Protocol)和RTCPQReal-time Control ProtocolQ都是基于IP的应用层协议。RTP为实旉/视频数据提供端到端的传送服务,包括有效载荷cd标识、序列标受时间标{֒源标识,可以提供旉信息和实现流同步。由于TCP中重传机制会引v时gQ通常RTPq行于UDP之上Q但是也可以在TCP或者ATM{协议之上运行。RTP本nq不提供可靠的传送机Ӟ也不提供量控制或者拥塞控Ӟ而是通过与RTCP配合使用Q传输效率最佟뀂RTCP用来监视服务质量和在会议q程中交换信息。它提供QoS反馈、参与者标识、控制包~放、媒体间同步{服务。RTCP包中包含已发数据包的数量、丢失数据包数量{统计资料。服务器可以Ҏq些信息动态的改变传输速率甚至有效载荷cd?br /> <br /> 2.6.2 实时协议(RTSPQRTSPQReal-time Streaming ProtocolQ是由RealNetworks和Netscape共同提出的一个应用层协议。它可以在媒体服务器和客L之间建立和控制连l的?视频媒体,协同更低层协议RTP、RSVP{一h提供ZInternet的整套流式服务。RTSP提供了一U可扩展框架Q得可控的、点播的实时数据的传送成为可能。它提供用于音频和视频流?#8220;VCR模式”q程控制功能Q例如暂停、快q、快退和定位。支持单播和l播。RTSPq提供选择发送通道的方法(如UDP、组播UDP和TCPQ和ZRTP的发送机制。RTSP像是媒体服务器和客户端之间的“|络q程控制”Q它提供多种服务Q如从媒体服务器上检索媒体、邀请媒体服务器q入会议、添加媒体到现成节目。RTSP在语法和操作上类gHTTPQ因此许多HTTP的扩展机刉可以UL于RTSP上。在 RTSP中,每个节目和媒体流由RTSP URL定Q全部节目和媒体Ҏ都在节目描q文件中l予了描qͼ包括~码、语a、RTSP URLs、目的地址、端口号以及其他参数。但是,不同于HTTP的无状态和非对UͼRTSP是有状态的、对U的协议。RTSP的服务器保持会话状态以q接 RTSP的hQƈ且服务器和客L都可以发求?br /> <br /> 2.6.3 资源预留协议QRSVPQ资源预留协议[5]QResource Reserve ProtocolQ是q行于传输层的一个网l控制协议。RSVP允许数据的接受方请求特D的端到端QoS。RSVP是非路由协议Q它同\由器协同工作Q在传输路径的\由器上预留必要的带宽Q减网l的时g和抖动。RSVP的流E是单一的,q不区分发送方和接受方Q且支持单播和组播,适应于可变成员个数和路由。RSVP领域的发展非常迅速,但是目前它的应用只限于在试的小Intranet|络上?br /> <br /> <strong>3 l论</strong>技术的q步和用L需求促q了媒体应用的q速发展。在q程教育、数字图书馆、电子商务、视频点播、交互电视、远E医疗、网l音/视频、实时多媒体会议{方面,媒体技术都起到很重要的作用。本文对|络中流媒体业务的关键技术和相关协议做了研究Qƈ探讨了未来流媒体技术发展的方向。我们相信,随着媒体应用的不断普及Q宽带流媒体技术及其应用必然会在未来的|络中发挥更重要的作用,q在一定程度上改变Z使用|络的方式? <img src ="http://www.tkk7.com/jelver/aggbug/196409.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/jelver/" target="_blank">冰河快狼</a> 2008-04-27 10:31 <a href="http://www.tkk7.com/jelver/articles/196409.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一U高效流媒体电媄服务器的设计(?http://www.tkk7.com/jelver/articles/196400.html冰河快狼冰河快狼Sun, 27 Apr 2008 01:53:00 GMThttp://www.tkk7.com/jelver/articles/196400.htmlhttp://www.tkk7.com/jelver/comments/196400.htmlhttp://www.tkk7.com/jelver/articles/196400.html#Feedback0http://www.tkk7.com/jelver/comments/commentRss/196400.htmlhttp://www.tkk7.com/jelver/services/trackbacks/196400.html1 引言

     随着|络技术的发展Q主q网与宽带网接入技术的日臻成熟Q网l视频的传输成ؓ Internet应用的一个亮炏Vؓ了提高视频数据在|上的传输效率,q实现视频的实时播放Q流媒体技术的研究与应用得C很大发展。其中,媒体服务器技术在媒体的应用中发挥了关键的作用?br />
     传统的网l传输数据的Ҏ是文件下载:用户需要准备大量的盘I间Qƈ花大量的旉{待下蝲l束。但是,当数据变成v量的视频数据Ӟ在数据处理量大,数据吞吐量高Q视频播攑֮时性,客户q接h数目大,q接旉长等一些情况下Q传l的服务器技术已l无法高效的满要求。面对这L技术要求,本文?CPU调度Q资源控制内存分配,IQOȝ理q三个方面出发,l合的给Z一U高效的服务器设计方法,从而有效的提高了视频流式传输时的效率。该Ҏ也具有很强的可扩展性,当服务器的CPU数目增加Ӟ服务器的性能能得到成倍的增长?br /> 2 媒体服务器的设?/strong>

2Q? 媒体服务器的功?br />
媒体在播放前不是完全下载整个文Ӟ而是把开始部分内容存入内存,数据是随时传送随时播放?br />
媒体服务器提供的流式传输方式有两种Q顺序流式传输和实时式传输两种方式。顺序流式传输是序下蝲Q在下蝲文g的同时用户可观看在线媒体。实时流式传输与序式传输不同Q实时流式传输L实时传送,特别适合现场事g。实时流式传输必d配连接带宽,q意味着囑փ质量会因|络速度降低而变差?br />
在流式传输时Q流媒体数据h实时性,{时性等基本特点Q流服务期和客户l端要保证各U媒体间的同步关p,因此Q流媒体传输?#8220;最大g?#8221;Q?#8220;延时抖动”{QoS参数都有严格要求?br />
2Q? 媒体服务器协议栈的设计

在TCPQIP参考模型中Q传输层通信协议TCP和UDP都不能满x媒体传输的QoS要求。由于TCP协议采用滑动H口控制机制Q数据传送随着控H口动态的启动和关闭,难以满媒体实时和{时的传送要求。UDP协议的无q接特点能够提高传输速率Q虽然可以在某种E度上满x媒体的实时性要求,但是׃其本w的不可靠性,也无法满x媒体传输的需要?br />
针对传输层协议的矛盾Qؓ了实现流媒体在IP上的实时传送播放,设计媒体服务器旉要在传输层协议(TCPQUDPQ和应用层之间增加一个通信控制层。在增加的通信控制层,采用相应的实时传输协议,主要有:数据部分的实时传输协议RTPQRealQtime Transport ProtocolQ,用于控制部分的实时传输控制协议RTCPQRealQtime Transport? 媒体服务协议栈Streaming ProtocolQ。RTP协议主要是用来传送实时的媒体信息,数据报主要包括多媒体数据Q以及所携带负蝲的时间戳Q顺序号{。RTCP协议的数据报主要包括了接收者收到某个多媒体的服务质量信息Q用于对服务器端的反馈?br />
媒体服务器的协议栈如图1所C?



当服务器收到RTSPhQ它首先产生RTSPh对象。服务器通过RTSP协议的应{信息将h的内容以会话(streaming sessionQ的形式描述Q内容包括数据流包含多少个流、媒体类型、和~解码格式。一个流会话׃个或多个数据组成,如视频流和音频流{。实际的数据通过RTP协议传递到客户端。RTP在一对一或一对多的传输情况下工作Q其目的是提供时间信息和实现同步。RTP本nq不能ؓ序传送数据包提供可靠的传送机Ӟ它依靠RTCP一h供流量控制和拥塞控制服务。在RTP会话期间Q各q接者监视下层网l的性能Qƈ相关信息放入RTCP包,周期性地传?RTCP包来通知发送方。发送方也可以用RTCP包提供每ơ的会话信息Q包中含有已发送的数据包的数量、丢q数据包的数量{统计资料。因此服务器可以利用q些信息动态地改变传输速率Q甚x变有效蝲L型。RTP和RTCP配合使用Q因有效的反馈和最的开销使传输效率最佛_?br />
媒体服务器的功能框囑֦?所C?/p>



2Q? 高效媒体服务器的设?br />
通过媒体服务器的协议栈的设计,可以明确媒体服务器是在传输层协议(TCPQUDPQ上解释RTPQRTCPQRTSP协议的,所有的客户q接h都是以TCP的端口获得的Q流媒体数据也都是打成RTP包,通过UDP端口发出ȝQ因此,对于TCPQUDP端口事g的调度以及如何把大量的流媒体数据从磁盘空间传递到|络上成为制U流媒体服务器性能的主要因素?br />
媒体服务器面对一个单一的客P完成的过E如下:

1Q在客户端发出RTSPq接h后,服务器通过对TCP端口的监听,dh?br />
2Q解析请求内容,调入相应的流媒体文g?br />
3QŞ成RTP包,分发数据包Q获得RTCP包?br />
4Q数据包发送完毕,关闭q接?br />
上述q程如果采用传统的服务器设计Ҏ实现Q一般的办法是用一个线E不断的d用户的连接请求,然后这些请求分z其它的工作线E,q些工作U程则分别@环往复的完成以下的工作:

1Q解析请求内宏V?br />
2Q发送RTP包,发送接收RTCP?br />
3Q判断数据发送完毕,关闭q接。服务器的结构如?所C?/p>



操作pȝ在对媒体服务器的功能实C采用以应用进E(U程Qؓ中心的系l资源管理方式。操作系l采用虚拟内存方式,应用E序的虚拟内存空间映到物理内存Q物理内存与CPU之间有Cache。当媒体数据从盘上到|络上进行传递时Q要在不同的pȝI间中进行多ơ传递拷贝,如图4所C?/p>



?昄了磁盘数据到|络接口的传递\径:首先Q数据对象从盘拯到内存中Q然后,数据在内存中׃每个工作U程的空间不同,q行I间拯Q即从核心空间拷贝到q程I间Q接着Q数据再从进E空间拷贝到核心I间Q最后数据再拯到网l上。由于流媒体数据要经qRTP的打包处理,因此Q数据在拯到网l上之前Q还要拷贝到CacheQ再从Cache中拷贝到CPU寄存器,q行打包处理?br />
从图3可以看出Q随着工作U程数n的增大,pȝ在各U程之间的切换开销急剧增加Q从操作pȝ的角度来看,׃每个U程都涉及对盘视频数据的读取,各自独立的线E越多,对硬盘读写的数据量就大Q数据在不同I间的拷贝增加,操作pȝ不断的q行面切换Q服务器的性能随着客户q接数的增多Q效率将急剧下降?br />
Z改善上述设计的缺点,需重新设计服务器的服务E序l构。根据服务器在流媒体传输中所要完成的功能Q可以看出,<服务器在客户有连接请求时Q解析连接请求和关闭q接h是很短的q程服务器的大部分时间都用于l每个客户发送RTP数据包。发送RTP数据包包括服务器把相应的媒体文件调入内存,打包发送,以及获得RTCP包的反馈。因此,可以设计一个单独的处理U程Q专门用于给客户发送RTP的数据流包?br />
改进的流媒体服务器设计如?所C,完成主要的功能通过两个U程来实现?br />
事gU程负责客戯接,以及客户发的RTCP包的到来。事件线E通过对TCP端口的检,在有q接h时徏立可l护客户信息的RTSP会话Q在每一个客LRTSP会话的存zL内,事gU程不断的把向客户发送RTP包这一d攑օ处理U程的队列,直到RTSP会话l止Q事件线E再把关闭连接的d攑օ队列?br />
事gU程把对不同客户的服务(发送RTP数据包)以Q务的形式攑օ队列后,处理U程对对列中的Q务依ơ进行处理,也就是说Q处理线E根据客L不同Q不断的把相应的媒体文件Ş成RTP包,依次发出Q直到视频服务的l止?br />
可以看的出来Q处理线E虽然对所有的客户提供服务Q但是执行的d始终是发送RTP数据包Q同Ӟ该线E所讉K的媒体文件被调入内存后,可以被同一U程的其它Q务重复调用,q样的设计,不但减少了随着客户数增加而造成的系l频J切换的资源损失Q也减少了访问硬盘数据的ơ数Q羃短了讉K旉Q也发挥了指令局部性效率提高的优点。设? 改进后的处理程计中Q解析客Lq接h也放入处理线E的队列中,在处理线E中q行处理Q虽然解析连接的d不同于大部分发送RTP包的dQ但是该d消耗时间少Q所以对对系l性能的媄响ƈ不大?



采用?的设计方法,服务器还可以Ҏ客户端反馈的RTCP包得知客L的网l状况,采取一定的{略针对不同的客Ll质量进行RTP包发送Q务的调度Q对于带宽质量好的客P事gU程可以多放一些RTP包到队列中;对于׃|络质量造成的即超时的客户q接Q服务器也可以通过d调度的方式进行特D处理,最大限度的提供不同质量的客戯接服务?br />
上述的设计是在硬件具有一个CPU的情况下Q当pȝgh的CPU个数为nӞnQ?Q事实上做ؓ媒体服务器的硬仉求,一个CPU是远q不能满系l需求的Q,E序采用n个处理线E来分担事gU程调度的Q务,利用pȝ的可扩展性来提高性能?br />
2Q? 性能分析

新设计的Ҏ充分发挥了指令局部性和数据局部性的优点。处理线E在处理队列dӞ׃队列中每一个操作所作的事都一P如不停的发RTP 包)Q因此每个操作的指o序列都是完全相同的;而且Q当客户在连接后要求获得热点节目的媒体文件时Q指令操作的数据也将非常相近Q都在一个范围很的区域内。这Pl过几次操作后,当指令被加蝲到Cache中,数据加蝲到内存中后,׃再需要从盘中去调,极大提高了程序的性能?br />
新设计的Ҏ可以实现媒体数据在内存中连l存放,快速存取以及Cache预取Q资源管理方式从以应用线Eؓ中心的资源管理与分配转变Z数据Z心的资源理与分配?br />
衡量媒体服务器的性能可以Ҏ服务CPU的负载情冉|衡量。CPU的用情况主要和q接的客h目,客户端的操作如读取,快进Q搜索等相关。对于一?2kbps的文仉Q改q的服务器设计方案与传统的服务器设计Ҏ的性能优劣比较曲线Q如?所C?br />
?体现了随着CPU数的增加Q传l设计方案的性能变化不大Q改q的设计Ҏ在多个CPU的系l里Q充分利用了CPU所带的Cache的强大功能,CPU的M负蝲明显下降Q可以获得性能的极大提高?/p>



3 l束?br />
本文从系l可扩展斚w提出了实现高效的媒体服务器的解x案。除了系l可扩展斚wQ设计一个完善的高效媒体服务器Q还需要在实时的服务器操作pȝQ系l资源管理(CPU理Q内存管理,盘资源理Q,文g理Q服务器盘调度斚wq行高效的设计,q需要我们进一步研I和设计?/p>

冰河快狼 2008-04-27 09:53 发表评论
]]>
վ֩ģ壺 һ3Ƶ| 999ƵƷѲŹۿ| ޾Ʒ| 91ѸƷ| ձߵӰ| ľƷAVƬ| ƷѾþþþþþ| ޹˾þþƷ| ޾Ʒ| ˳ѵӰ| Ʒһþ| ޾ƷƷ˿| ӽ18վ| jizzձ| ˳վ߲| ɫͼۺ| 97Ƶ| ҹɫ˽ӰԺվӰ| av뾫Ʒվ| ѨƬ߹ۿ| þþƷһ| ɫۼۺ| ˳ۺ | ɱƬav| Ƶ| 99|| þþƷҹɫav| ڵֻˬƵ| þþþѿaԿ| պƷרӰ| Ƶһ| avרavý| õƵ| 99ѹۿƵ| ëƬڵ| gayƬgvվ| һƵۿ| ޳xxxxxӰ| ߹ۿ| ˳Ƶ| Ұ¾þø|