Django community: Community blog posts RSS
This page, updated regularly, aggregates Community blog posts from the Django community.
-
Starting with django-allauth
There are a lot of ways to do authentication in django. You can do social authentication and/or django.contrib.auth authentication. Generally they are separate, but with django-allauth you can combine them both into one package. It even gives you a great jumping off place with plenty of other features. In this video learn how to start using django-allauth.Watch Now... -
Review Django Essentials
[Django Essentials](http://www.packtpub.com/web-development/getting-started-django). Note it appears the name of this book has been changed from "Getting started with Django". I'll be clear from the outset: I have some pretty strong issues about the first part of this book, and I'm going to be quite specific with the things that I think are wrong with it. Having said that, the later chapters are far better than the earlier ones. I am not sure, however, that it's any more accessible than the [official documentation](http://docs.djangoproject.org). There's probably a market for a more thorough tutorial than the one on the Django website, however, I'm not sure this book, as it stands, is that tutorial. How could this book be better? I think it gets bogged down providing detail in areas that are just not that important at that point in time. I also think it misses a good overview of the product that is being built: indeed it's never clear, even after completing the book, exactly what the product is supposed to do. In my opinion, the code examples are hard to read. This is a combination of the styling of the source code, and the layout. That bold, blue is quite jarring in comparison … -
Don't touch autocommit in Django
Great Sentry We have a sentry service running on our server. It’s built on the Django framework and helps us to monitor the logging messages. It works just like a charm. Disk out of usage However, after three months the service went online, suddenly our IT monitor system alerts that the disk is running out due to mysql, and the mysql is for sentry. 60G /var/lib/mysql/ibdata1 The ibdata1 continuously grows without purge. It contains huge MVCC data like UNDO_LOG, We have to dump/load the whole databases and set innodb_file_per_table to replace the big ibdata1 file. find the exception The dump is very slow, so I take a look at the data. I suprisely find the table sentry_message have 500M rows! most of them is like this - MySQLdb.connections in defaulterrorhandler DatabaseError: (1305, 'SAVEPOINT s47569297779632_x1 does not exist') episode And it’s for an invisible project - Sentry (Internal). What, invisible? Yes, because the our setup didn’t create a default superuser. Thanks mwaterfall, I use the following command to fix it. sentry --config=~/etc/sentry/sentry.conf.py repair --owner=mwaterfall show queries So back to the topic, where is the exception coming from? I open general log for mysql, and see the following 140806 11:01:32 2 Connect … -
Dance my puppets
In many traditional multiplayer text engines for MUD/MUSH/MU*, the player connects to the game with an account name that also becomes their character's in-game name. When they log into the game they immediately "become" that character. If they want to play with another character, they need to create a new account.A single-login system is easy to implement but many code bases try to expand with some sort of "account system" where a single login "account" will allow you to manage one or more game characters. Matthew “Chaos” Sheahan beautifully argues for the benefits of an account system in the April issue of Imaginary Realities; you can read his article here.Evennia and account systemsFirst a brief show of how Evennia handles this. We use the following separation:Session(s) <-> Player <-> Objects/Characters(s)The Session object represents individual client connections to Evennia. The Player is our "account" object. It holds the password hash and your login name but has no in-game existence. Finally we have Objects, the most common being a subclass of Object we call Character. Objects exist in the game. They are "puppeted" by Sessions via the Player account. From this separation an account system follows naturally. Evennia also offers fully flexible … -
OSCON 2014 & REST API Client Best Practices
Mark Lavin, Caktus Technical Director and author of the forthcoming Django LightWeight was recently at OSCON 2014 in Portland where he gave a talk on improving the relationship between server and client for REST APIs. OSCON, with over 3000 attendees, is one of the largest open source conferences around. I sat down with him to ask him about his time there. Welcome back! This was your second year speaking at OSCON. How did you enjoy it this year? I enjoyed it. There’s a variety of topics at OSCON. It’s cool to see what people do with open source—there’s such a large number of companies, technologies, and approaches to solutions. There were great conversations and presentations. I especially liked Ignite OSCON where people gave really well-prepared 5 minute talks. I participated in the OSCON 5k [Mark received 5th place] too. There were a lot of people out. We went over bridges and went up and down this spiral bridge twice. That race was pretty late for me but fun [began at 9pm PST, which is 12AM EST]. Why did you choose REST API client best practices as a talk topic? It was something that came out of working on Django LightWeight. … -
Django Extensions 1.3.9
We are happy to release: Django-Extensions Version 1.3.9 This brings the usual tons of fixes and improvements Get it at: https://pypi.python.org/pypi/django-extensions/1.3.9 Changes: Feature: shell_plus, add --kernel option to start as standalone IPython kernel Feature: reset_db, Programatically determine PostGIS template Feature: sqldiff, add support for PointField and MultiPolygonField Test: renamed test app Fix: runserver_plus, --print-sql for Django 1.7 Fix: shell_plus, --print-sql for Django 1.7 Fix: show_urls, add support for functions that use functools.partial Fix: show_urls, add formatter for aligned output (will most likely become future default) Fix: shell_plus / notebook, support for Django 1.7 Docs: various fixes and improvements Cleanup: Remove work arounds for Django 0.96 and earlier -
如何利用 Powershell 同步本機磁碟與 Amazon S3 的檔案
转自: http://blog.miniasp.com/post/2014/07/21/Sync-folders-using-S3-Explorer-PowerShell-Snap-in.aspx 最近在協助客戶將 Amazon S3 上面的檔案遷移到 Windows Azure Storage,若要遷移這些存在 S3 上面的檔案,勢必要先把檔案下載回來,所以我今天打算分享一個不用錢的解決方案,讓你可以快速的同步本機與雲端上的檔案,你可以把本機磁碟中的檔案同步到 Amazon S3,也可以從 Amazon S3 同步檔案到本機磁碟中,已經同步過的檔案還會自動跳過,所以除了第一次同步外,日後每次同步檔案的速度都將非常快。 安裝 CloudBerry Explorer for Amazon S3 或 CloudBerry Explorer for Amazon S3 PRO 由於安裝了 CloudBerry Explorer for Amazon S3 之後,會連帶自動安裝 Powershell 的 CloudBerryLab.Explorer.PSSnapIn 管理單元,在這個管理單元中包含了一組可管理 Amazon S3 的 cmdlet 命令。 不過,有點要特別注意,CloudBerryLab.Explorer.PSSnapIn 僅支援 64 位元架構下,請記得要啟動 64-bit 的 Powershell 視窗,否則會無法在執行環境中加入這個 CloudBerryLab.Explorer.PSSnapIn 管理單元。我光是這點問題,卡了我好些時間,原因就在於我的電腦有安裝 Windows Azure PowerShell 套件,所以通常我如果要透過 PowerShell 管理 Windows Azure 資源的時候,都會透過這個捷徑啟動程式: 誰知道,原來這個捷徑指向的是 32-bit 的 PowerShell 環境! 請看看這個捷徑的內容,你會看到 SysWOW64 字樣,這就代表 PowerShell 是執行在 32-bit 環境下的。 如上圖目標的內容如下: C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -NoExit -ExecutionPolicy Bypass -File "C:\Program Files (x86)\Microsoft SDKs\Windows Azure\PowerShell\ServiceManagement\Azure\Services\ShortcutStartup.ps1" 我做了些小調整,把 powershell.exe 的路徑改一下而已,如下指令碼: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoExit -ExecutionPolicy Bypass -File "C:\Program Files (x86)\Microsoft SDKs\Windows Azure\PowerShell\ServiceManagement\Azure\Services\ShortcutStartup.ps1" 使用 CloudBerryLab.Explorer.PSSnapIn 管理單元提供的命令 大致上的使用情境如下: 1. 加入 CloudBerryLab.Explorer.PSSnapIn 到當前的 PowerShell 執行環境中 (必要動作) Add-PSSnapin CloudBerryLab.Explorer.PSSnapIn 2. 列出所有 CloudBerryLab.Explorer.PSSnapIn 支援的命令 Get-Command | Where-Object {$_.PSSnapin.Name -eq "CloudBerryLab.Explorer.PSSnapIn"} 3. 先取得 S3 連線物件 $key = "YOUR_KEY" $secret = "YOUR_SECRET" $s3 = Get-CloudS3Connection -Key $key -Secret $secret -UseSSL 4. 設定要同步兩端檔案的來源與目的物件 設定來源物件 (假設我要從本機磁碟把某個目錄同步到 S3,可以用以下語法指定一個本機磁碟機) $src = Get-CloudFilesystemConnection | Select-CloudFolder "G:\TEMP" 設定目的物件 (假設我要從本機磁碟把某個目錄同步到 S3,可以用以下語法指定一個 Bucket 路徑) $dest = $s3 | Select-CloudFolder -path "your_bucket_name/vPath" 5. 將來源複製到目的 ( 這是直接從 $src 複製所有檔案到 $dest 喔,預設 Storage Class 為 STANDARD ) $src | Copy-CloudItem $dest -filter * 如果要指定複製上去的檔案預設的 Storage Class 為 RRS 的話,可以改用以下指令: $src | Copy-CloudItem $dest -filter * -StorageClass rrs 注意:使用 Copy-CloudItem 來複製檔案,並不會檢查檔案是否上傳過,所以僅適合用在第一次上傳或下載檔案的時候。 6. … -
如何利用 AzCopy 同步本機磁碟與 Azure Blob Storage 檔案
转自: http://blog.miniasp.com/post/2014/07/23/AzCopy-sync-local-disk-and-azure-blob-storage-files.aspx 最近在協助客戶將 Amazon S3 上面的檔案遷移到 Windows Azure Storage (Blob),在我的前一篇文章已經提到如何便利的從 Amazon S3 同步到本機磁碟,今天我將分享如何透過微軟提供的免費工具 AzCopy 幫我們快速達成上傳、下載、同步等工作,也是一套兼具方便性與效能的檔案同步工具,同步檔案時,他一樣不會傳輸那些已經同步過且無異動的檔案,讓我們一起來看看如何使用吧! 當你安裝過 Windows Azure SDK 或命令列工具支援,就可以在程式集中找到 Windows Azure Storage command line 捷徑,透過這個捷徑可以開啟一個能讓你執行 AzCopy 指令的命令提示字元視窗。 你可以利用 where azcopy 命令找到該執行檔所在實際位置,執行 azcopy /? 可以看到完整使用說明: 找到 AzCopy 執行檔之後,使用方式真的是簡單到不能再簡單,一個最基本的用法,就是直接指定來源與目的即可自動完成檔案同步工作。以下幾個使用情境與相對應的指令供各位參考: 1. 將本地資料夾所有檔案(含子目錄)全部上傳到Azure Blob Storage,而且會判斷不要同步比 Azure Blob Storage 來舊的檔案,也就是如果 Azure Blob Storage 檔案有更新過時,不會複製檔案上去。 AzCopy G:\TEMP https://YOUR_URL/CONTAINER/vPath /DestKey:KEY /S /XO /Z 上述指令,藍字部份都是你要修改的,而 /DestKey 代表的是你目的端的 Storage Account 的存取金鑰。 /S 代表複製所有指定目錄與其所有子目錄的所有檔案 /XO 代表當你從來源複製到目的時,排除那些比目的端舊的檔案 ( Exclude Older ) /Z 讓你本次的同步工作進入所謂 Restartable mode,他會記錄同步檔案的過程,並寫入一個 AzCopy.log 暫存檔案中,當你同步過程發生網路問題,下次執行相同的指令會自動在上次執行到一半的地方開始同步檔案! 2. 將 Azure Blob Stroage 上面的檔案全部下載回來 以下指令跟上述指令的差別,僅把來源與目的交換,然後把 /DestKey 換成 /SourceKey 而已。 AzCopy https://YOUR_URL/CONTAINER/vPath G:\TEMP /SourceKey:KEY /S /XO /Z 3. 利用 AzCopy 在兩個不同的 Storage 儲存帳戶搬移檔案 這部分基本上還算簡單,就是你的來源與目的都是 BLOB_URL 而已,但有些額外的參數可以了解,詳細資訊可參考 AzCopy – Using Cross Account Copy Blob 這篇文章。 -
在 Raspberry Pi 上安裝 mongodb
編繹安装的話,要很久,所以找到了一個 binary zip 來安裝。解開 zip 後,要用 root 執行下面這些指令,然後,就可以用了。 adduser --firstuid 100 --ingroup nogroup --shell /etc/false --disabled-password --gecos "" --no-create-home mongodb cp -R mongodb-rpi/mongo /opt chmod +x /opt/mongo/bin/* mkdir /var/log/mongodb chown mongodb:nogroup /var/log/mongodb mkdir /var/lib/mongodb chown mongodb:nogroup /var/lib/mongodb cp mongodb-rpi/debian/init.d /etc/init.d/mongod cp mongodb-rpi/debian/mongodb.conf /etc/ ln -s /opt/mongo/bin/mongod /usr/bin/mongod chmod u+x /etc/init.d/mongod update-rc.d mongod defaults /etc/init.d/mongod start -
移动应用被苹果官方推荐的秘密
转自: http://www.williamlong.info/archives/3927.html 对于中小应用开发团队来说,技术已经不是再是瓶颈,最困难的部分是如何让大家知道自己。如果应用能被苹果官方推荐,那么就会产生巨大的收益,瞬间积累几十万用户不在话下,可以说是最具效果和性价比的推广方式。作为一个仅有一年多app开发经验的团队,我们两款产品均被苹果推荐,在业界很少见,很多朋友问我如何做到的,被问得多了,我觉得有责任和义务写一篇文章,来分享下我所知道的如何获得苹果推荐。 首先说一下我们两款产品被推荐的过程(非常平淡,慎入) 2012年在我们提交第一个产品后,收到了一封来自@apple.com的邮件,邮件的内容是苹果觉得我们的产品很有意思,想要进行推荐,需要我们提供一系列的宣传素材(主要是页首海报)和产品计划表。作为刚开始做app还在跑线下宣传的屌丝,根本不知道被推荐的意义,所以虽然认真准备并提交了,但并没有抱很大期望。没想到后来真的推荐了! 然后服务器真的爆了!我们这才明白这个推荐的价值,而且一旦被推荐后会进入一个推荐候选的名单,苹果会持续的进行推荐。在这个过程中,我们与当初联系我们的联络人一直保持着联系,update我们的进展,且对遇到的问题进行反馈,邮件发了好几个月,但一直没有见面,(要见一面非常非常难)后来,几经波折,终于见到了传说中的帅哥@apple.com.本来想好要拉拉关系,扯扯家常,后来发现对方真的是非常认真的人,见了面一直在谈工作和对我们产品的建议,解释问题。再后来到第二个产品的时候,我们也主动发我们的产品资料给他,并根据他的反馈进行了一些改进,最终获得了推荐,由于之前的经验,这次服务器没有爆。:) 苹果团队的工作人员一直非常nice,整个过程也顺利得让我们想感谢老天爷。事后我们对苹果推荐产品的标准做了一些总结,要知道帅哥联络人的表情很和蔼,内心要求可是很高的,以下就是我们总结的苹果的六个“秘密”心理: 秘密一,别想拿钱套近乎。有人听到我们的应用上榜了,第一反应是问我们花了多少钱?面对这种问题,我们只能感叹要是能花钱我们肯定也花不起这个钱,当初到处去贴小广告就是因为没有预算做更好的推广啊!后来我们才知道,苹果商店的编辑团队是真正的高富帅,根本不差土豪产品的那些钱,他们要找真正优秀的产品,所以千万别指望用钱套近乎。为了实现公平公正的原则,苹果商店创建了非常合理的组织结构。全球分为几十个商店,每个商店都有自己的编辑团队,而编辑团队类似一个黑盒子,一般是接触不到的,有点像黑衣人的感觉,苹果给了这些编辑绝对的自由可以选择自己喜欢的应用。但是我们可以通过一层关系找到这些编辑,就是之前提到的联络人,官方职位叫开发者关系,他们像是连接编辑和开发者的桥梁。 秘密二,不是最新的我不要。既然说到优秀的产品,就不得不提这优秀的第一个标准,那就是概念一定要新鲜。这个其实没什么好说的,二十一世纪最贵的就是创意,不管是商业模式还是产品本身的创意可能都能起到决定性的作用。我们第一款产品上榜的时候,市场上并没有类似的应用;这款应用上线的时候,模式已经不新鲜了,但是我们可以自信地说产品里漂亮的界面、清新的画风和大量的素材还是独一无二的。 秘密三,你能为手机用户带来什么?苹果在商店首页做推荐,千万不要幼稚地以为是发善心帮你推广产品,人家的首要任务是为了推广自己的商店,所以你的产品要能给用户带来好的体验,能够实实在在地帮苹果商店留住用户,获得好评。我每周都关注苹果商店推荐,发现工具、效率和运动类的应用每期都会获得推荐,且上榜量远远大于游戏,我想这就是苹果的理念在起作用,他们推荐的应用,其目标是为了让人们的生活更丰富多彩、更高效、更健康,总的来说就是让人们生活的更美好。被推荐的都是为了让人们更好的去创造,这是非常重要的一点。 秘密四,请体现苹果的气质。如果前面大家觉得我说的都在扯淡,那可以从这里开始请认真看,我要开始认真的说了。关于设计,其重要性应该已经形成共识,但是,既然我们在谈如何被苹果推荐,那么这里说的设计风格主要指的是苹果的风格。尤其重要的是,苹果非常喜欢能够跟得上他们的系统迭代的产品。记得IOS7刚出来的时候,他们专门推了一个IOS7风格应用的推荐主题,这是最明显的引导。从Icon设计到内部界面都应该认真对待,试想如果没有达到苹果的水平或者风格差异过大,应用放在App Store上是有损苹果的形象的。 秘密五,最喜欢surprise了。这一点实际是高质量的延伸,高大上的团队一般也喜欢高大上的应用。针对如何让应用显得高大上这个问题,我能给出的建议就是在细节处给用户或者编辑惊喜。一个漂亮的提示,精彩的跳转动画,搞笑的小动画和充满创意的loading都会让你的应用显得与众不同,甚至可以说是区别高质量应用和低质量应用的关键区别。 秘密六,世界的才是最好的。我们当时为产品做了一个英文版本,没想到正中苹果下怀。苹果倾向有多语言版本的应用,因为开发者关系在看到一个感兴趣的应用时,会向多个市场进行推荐,因此有多语言版本的应用,有更大机会获得推荐,这一条的操作请自觉配合前面五条,因为只有在做到前面五点的前提下,多语言版本才显得有意义,算一个加分项。 总的来说,做应用还是要做自己爱的应用,并且将自己的灵魂融入其中,这样才可能做出令人印象深刻的产品,也能让app脱颖而出。面对几百万的开发者,如何脱颖而出,已经不仅仅是一项技术活,而是专注、热情、韧性、天赋和运气的综合比拼。苹果商店是一个公平的舞台,这里只是分享下我的经历和小技巧,文章写的有点乱,最开始以为在写推广,后来发现在写产品。好吧,我承认这是有意而为(才怪),我认为最好的推广是把产品做好,所有资源就自动地会向你靠拢,如果为了迎合渠道而去做产品,可能会忘了初心,迷失方向,你说呢? -
pyRserve: 连接远程 R 语言进程的 Python 客户端
pyRserve是一个纯pyhton的客户端, 用于连接远程的R进程. R是现在开源界最重要和最广为使用的统计语言. 通过pyRserve连接R进程, 可以在python中最大的利用R语言. pyRserve的安装不需要其他依赖包, 子需要使用pip安装即可. 简单的使用代码如下: >>> import pyRserve >>> conn = pyRserve.connect('Rserve.example.com') >>> conn.eval('sum( c(1.5, 4) )') # 直接在R中执行语句 >>> conn.r.myList = [1, 2, 3] # 将python list连接到R中的变量mylist >>> conn.voidEval('func1 >> conn.r.func1(4) # 在R中运行function 16 更多的信息可以查看其文档: https://pythonhosted.org/pyRserve/ -
Want to work for Eventbrite? (part 2)
For various reasons I had to change some things about my Eventbrite test. The new version is listed here and the previous blog post has been updated: 104, 116, 116, 112, 115, 58, 47, 47, 103, 105, 115, 116, 46, 103, 105, 116, 104, 117, 98, 46, 99, 111, 109, 47, 112, 121, 100, 97, 110, 110, 121, 47, 97, 56, 55, 100, 57, 54, 49, 54, 102, 49, 50, 55, 52, 48, 48, 97, 57, 55, 97, 52 Good luck! -
Want to work for Eventbrite? (part 2)
For various reasons I had to change some things about my Eventbrite test. The new version is listed here and the previous blog post has been updated: 104, 116, 116, 112, 115, 58, 47, 47, 103, 105, 115, 116, 46, 103, 105, 116, 104, 117, 98, 46, 99, 111, 109, 47, 112, 121, 100, 97, 110, 110, 121, 47, 97, 56, 55, 100, 57, 54, 49, 54, 102, 49, 50, 55, 52, 48, 48, 97, 57, 55, 97, 52 Good luck! -
Want to work for Eventbrite?
Join me, Andrew Godwin (South, Django migrations), Simon Willison (co-founder of Django, co-founder of Lanyrd), and many other talented people at Eventbrite. We have great challenges, the kind that inspire you to rise to the occasion. We need you to help us overcome them. I should mention that Eventbrite is committed to giving back to the community. Most notably Eventbrite just contributed £5000 to the Django Rest Framework kickstarter, or about US$8500!!. We're a frequent sponsor of events around the world. It doesn't stop there, as Eventbrite managers during the discussion of any tool outside our domain of running events will ask: "When can we open source this?" As someone who loves working on open source, Eventbrite is the place to be. I say this because I know what we're planning to do in the future. If you join us, you'll find out sooner rather than later. ;) What's Eventbrite like as a company? Well, we're rated in the top 20 of best places to work in the United States. We get full benefits, free lunch, educational opportunities, and much more. In addition, I have to say that my co-workers are friendly, intelligent, always learning, and love to do things … -
Want to work for Eventbrite?
Join me, Andrew Godwin (South, Django migrations), Simon Willison (co-founder of Django, co-founder of Lanyrd), and many other talented people at Eventbrite. We have great challenges, the kind that inspire you to rise to the occasion. We need you to help us overcome them. I should mention that Eventbrite is committed to giving back to the community. Most notably Eventbrite just contributed £5000 to the Django Rest Framework kickstarter, or about US$8500!! We're a frequent sponsor of events around the world. It doesn't stop there, as Eventbrite managers during the discussion of any tool outside our domain of running events will ask: "When can we open source this?" As someone who loves working on open source, Eventbrite is the place to be. I say this because I know what we're planning to do in the future. If you join us, you'll find out sooner rather than later. ;) What's Eventbrite like as a company? Well, we're rated in the top 20 of best places to work in the United States. We get full benefits, free lunch, educational opportunities, and much more. In addition, I have to say that my co-workers are friendly, intelligent, always learning, and love to do things … -
网站压力测试工具
转自: http://www.yeolar.com/note/2012/11/24/web-bench-test/ 网站压力测试就是测试网站能够承受多大的访问量,以及在大访问量的情况下网站的性能。这些指标会直接影响用户的体验,因此在网站上线前一般都要做压力测试。压力测试也是考察网站使用的相关web服务器和框架的一个重要手段。 因为和真实的环境不同,压力测试通过模拟得到的结果不会和实际的负载完全相同,但它仍是一个很好的基准比较。做压力测试时也会尽可能地模拟实际的情况。 网上大家推荐的较为常见的网站压力测试工具有ab、webbench、http_load、siege、curl-loader、multi-mechanize、tcpcopy等。 这里的大部分测试工具采用事件驱动模型来创建模拟用户,比如ab使用 apr 包中的 apr_pollset_poll 函数,而其他的工具都使用 select 函数,只有webbench通过 fork 子进程来创建模拟用户,它能模拟的并发数更高。 我把大家的一些总结列在这里: ab Apache自带的压力测试工具,还有一个 独立版本 。主要用于测试网站的每秒处理请求数,多用于静态压力测试。基本用法是: $ ab -n 1000 -c 50 http://192.168.1.101/ -n 总请求数 -c 并发连接数 输出的结果如下: Server Software: Apache/2.2.16 Server Hostname: 192.168.1.101 Server Port: 80 Document Path: / 请求文档路径 Document Length: 14643 bytes 请求文档大小 Concurrency Level: 50 并发数 Time taken for tests: 38.724 seconds 总测试时间 Complete requests: 1000 全部请求数 Failed requests: 14 失败请求数 (Connect: 0, Receive: 0, Length: 14, Exceptions: 0) Write errors: 14 Total transferred: 14847500 bytes 总数据传输量 HTML transferred: 14548500 bytes HTML数据传输量 Requests per second: 25.82 [#/sec] (mean) 平均每秒请求数 Time per request: 1936.210 [ms] (mean) 平均每次并发所有请求时间 Time per request: 38.724 [ms] (mean, across all concurrent requests) 平均每次请求时间 Transfer rate: 374.43 [Kbytes/sec] received 传输速率 Connection Times (ms) min mean[+/-sd] median max Connect: 2 668 1905.0 135 12237 连接时间 Processing: 0 1244 1652.3 902 14963 处理时间 Waiting: 0 1222 1651.1 883 14955 等待时间 Total: 134 1912 2723.5 1126 15096 Percentage of the requests served within a certain time (ms) 50% 1126 66% 1321 75% 1369 80% 1408 90% 1917 95% 10122 98% 13030 99% 13884 100% 15096 (longest request) webbench 它主要测试每秒请求数,同时支持静态、动态和SSL,单例最多可模拟3万并发,适合小型网站的压力测试。 基本用法是: $ webbench -c 100 -t 60 http://192.168.1.101/ -c 并发数 -t 测试时间 测试结果如下: Benchmarking: … -
Django 和 PostgreSQL, 从 SQL 的 LIKE 到全文搜索(Full-Text-Search) (2)
在上一篇中, 我们解决了明确搜索的问题, 这一篇中我们说说口音或相近语的问题. 在使用全文搜索是我们会发现, 使用多种语言搜索document是常有的事情. 我们可以不设置语言而是用to_tsquery, 但是在运行的过程中, 全文搜素总是会自动使用至少一个. 默认的语言设置时英语, 但你必须根据你document的语言使用正确的stemmer, 否则就无法找到匹配. 例如, 我们在西班牙语的document中搜索física, 能得到精确地匹配: => SELECT text FROM terms WHERE to_tsvector(text) @@ to_tsquery('física'); text ------------------------------------------------------------------------- física (aparatos e instrumentos de —) física (educación —) física (investigación en —) rehabilitación física (aparatos de —) para uso médico educación física conversión de datos y programas informáticos, excepto conversión física investigación en física terapia física (8 rows) 但如果搜索fisica, 不带口音设置, 则无法得到任何结果: => SELECT text FROM terms WHERE to_tsvector(text) @@ to_tsquery('fisica'); text ------ (0 rows) 为了能在结果中显示física和其变体(físicas, físico, físicamente, 等), 我们必须使用正确的stemmer. 如果stemmer中没有这个词, 那么我们也无法获得正确的结果: => SELECT ts_lexize('english_stem', 'programming'); ts_lexize ----------- {program} (1 row) => SELECT ts_lexize('spanish_stem', 'programming'); ts_lexize --------------- {programming} (1 row) 但当使用正确的语言设置时: => SELECT text FROM terms WHERE to_tsvector('spanish', text) @@ to_tsquery('spanish', 'física'); text -------------------------------------------------------------------------------- física (aparatos e instrumentos de —) ejercicios físicos (aparatos para —) entrenamiento físico (aparatos de —) físicos (aparatos para ejercicios —) física (educación —) preparador físico personal [mantenimiento físico] (servicios de —) física (investigación en —) ejercicio físico (aparatos de —) para uso médico rehabilitación física (aparatos de —) para uso médico aparatos para ejercicios físicos almacenamiento de soportes físicos de datos o documentos electrónicos clases de mantenimiento físico clubes deportivos [entrenamiento y mantenimiento físico] educación física conversión de datos o … -
Contributing Back to Symposion
Recently Caktus collaborated with the organizers of PyOhio, a free regional Python conference, to launch the PyOhio 2014 conference website. The conference starts this weekend, July 26 - 27. As in prior years, the conference web site utilizes Eldarion’s Symposion, an opensource conference management system. Symposion powers a number of annual conference sites including PyCon and DjangoCon. In fact, as of this writing, there are 78 forks of Symposion, a nod to its widespread use for events both large and small. This collaboration afforded us the opportunity to abide by one our core tenets, that of giving back to the community. PyOhio organizers had identified a few pain points during last year’s rollout that were resolvable in a manner that was conducive to contributing back to Symposion so that future adopters could benefit from this work. The areas we focused on were migration support, refining the user experience for proposal submitters and sponsor applicants, and schedule building. Migration Support https://github.com/pinax/symposion/pull/47 The majority of our projects utilize South for tracking database migrations. They are not an absolute requirement but for those conferences that reused the same code base from year to year, rather than starting a new repository, it would be … -
TCP 的那些事儿(下)
上篇中,我们介绍了TCP的协议头、状态机、数据重传中的东西。但是TCP要解决一个很大的事,那就是要在一个网络根据不同的情况来动态调整自己的发包的速度,小则让自己的连接更稳定,大则让整个网络更稳定。在你阅读下篇之前,你需要做好准备,本篇文章有好些算法和策略,可能会引发你的各种思考,让你的大脑分配很多内存和计算资源,所以,不适合在厕所中阅读。 TCP的RTT算法p TCP的RTT算法 设长了,重发就慢,丢了老半天才重发,没有效率,性能差; 设短了,会导致可能并没有丢就重发。于是重发的就快,会增加网络拥塞,导致更多的超时,更多的超时导致更多的重发。 而且,这个超时时间在不同的网络的情况下,根本没有办法设置一个死的值。只能动态地设置。 为了动态地设置,TCP引入了RTT——Round Trip Time,也就是一个数据包从发出去到回来的时间。这样发送端就大约知道需要多少的时间,从而可以方便地设置Timeout——RTO(Retransmission TimeOut),以让我们的重传机制更高效。 听起来似乎很简单,好像就是在发送端发包时记下t0,然后接收端再把这个ack回来时再记一个t1,于是RTT = t1 – t0。没那么简单,这只是一个采样,不能代表普遍情况。 经典算法 RFC793 中定义的经典算法是这样的: 首先,先采样RTT,记下最近好几次的RTT值。 然后做平滑计算SRTT( Smoothed RTT)。公式为:(其中的 α 取值在0.8 到 0.9之间,这个算法英文叫Exponential weighted moving average,中文叫:加权移动平均) SRTT = ( α * SRTT ) + ((1- α) * RTT) 开始计算RTO。公式如下:RTO = min [ UBOUND, max [ LBOUND, (β * SRTT) ] ] 其中: UBOUND是最大的timeout时间,上限值 LBOUND是最小的timeout时间,下限值 β 值一般在1.3到2.0之间。 Karn / Partridge 算法 但是上面的这个算法在重传的时候会出有一个终极问题——你是用第一次发数据的时间和ack回来的时间做RTT样本值,还是用重传的时间和ACK回来的时间做RTT样本值? 这个问题无论你选那头都是按下葫芦起了瓢。 如下图所示: 情况(a)是ack没回来,所以重传。如果你计算第一次发送和ACK的时间,那么,明显算大了。 情况(b)是ack回来慢了,但是导致了重传,但刚重传不一会儿,之前ACK就回来了。如果你是算重传的时间和ACK回来的时间的差,就会算短了。 所以1987年的时候,搞了一个叫Karn / Partridge Algorithm,这个算法的最大特点是——忽略重传,不把重传的RTT做采样(你看,你不需要去解决不存在的问题)。 但是,这样一来,又会引发一个大BUG——如果在某一时间,网络闪动,突然变慢了,产生了比较大的延时,这个延时导致要重转所有的包(因为之前的RTO很小),于是,因为重转的不算,所以,RTO就不会被更新,这是一个灾难。 于是Karn算法用了一个取巧的方式——只要一发生重传,就对现有的RTO值翻倍(这就是所谓的 Exponential backoff),很明显,这种死规矩对于一个需要估计比较准确的RTT也不靠谱。 Jacobson / Karels 算法 前面两种算法用的都是“加权移动平均”,这种方法最大的毛病就是如果RTT有一个大的波动的话,很难被发现,因为被平滑掉了。所以,1988年,又有人推出来了一个新的算法,这个算法叫Jacobson / Karels Algorithm(参看RFC6289)。这个算法引入了最新的RTT的采样和平滑过的SRTT的差距做因子来计算。 公式如下:(其中的DevRTT是Deviation RTT的意思) SRTT = SRTT + α (RTT – SRTT) —— 计算平滑RTT DevRTT = (1-β)*DevRTT + β*(|RTT-SRTT|) ——计算平滑RTT和真实的差距(加权移动平均) RTO= µ * SRTT + ∂ *DevRTT —— 神一样的公式 (其中:在Linux下,α = 0.125,β = 0.25, μ = 1,∂ = 4 ——这就是算法中的“调得一手好参数”,nobody knows why, it just works…) 最后的这个算法在被用在今天的TCP协议中(Linux的源代码在:tcp_rtt_estimator) TCP滑动窗口 需要说明一下,如果你不了解TCP的滑动窗口这个事,你等于不了解TCP协议。我们都知道,TCP必需要解决的可靠传输以及包乱序(reordering)的问题,所以,TCP必需要知道网络实际的数据处理带宽或是数据处理速度,这样才不会引起网络拥塞,导致丢包。 所以,TCP引入了一些技术和设计来做网络流控,Sliding Window是其中一个技术。 前面我们说过,TCP头里有一个字段叫Window,又叫Advertised-Window,这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。 为了说明滑动窗口,我们需要先看一下TCP缓冲区的一些数据结构: 上图中,我们可以看到: 接收端LastByteRead指向了TCP缓冲区中读到的位置,NextByteExpected指向的地方是收到的连续包的最后一个位置,LastByteRcved指向的是收到的包的最后一个位置,我们可以看到中间有些数据还没有到达,所以有数据空白区。 发送端的LastByteAcked指向了被接收端Ack过的位置(表示成功发送确认),LastByteSent表示发出去了,但还没有收到成功确认的Ack,LastByteWritten指向的是上层应用正在写的地方。 于是: 接收端在给发送端回ACK中会汇报自己的AdvertisedWindow = MaxRcvBuffer – LastByteRcvd – 1; 而发送方会根据这个窗口来控制发送数据的大小,以保证接收方可以处理。 下面我们来看一下发送方的滑动窗口示意图: 上图中分成了四个部分,分别是:(其中那个黑模型就是滑动窗口) #1已收到ack确认的数据。 #2发还没收到ack的。 #3在窗口中还没有发出的(接收方还有空间)。 #4窗口以外的数据(接收方没空间) 下面是个滑动后的示意图(收到36的ack,并发出了46-51的字节): 下面我们来看一个接受端控制发送端的图示: Zero Window 上图,我们可以看到一个处理缓慢的Server(接收端)是怎么把Client(发送端)的TCP Sliding Window给降成0的。此时,你一定会问,如果Window变成0了,TCP会怎么样?是不是发送端就不发数据了?是的,发送端就不发数据了,你可以想像成“Window Closed”,那你一定还会问,如果发送端不发数据了,接收方一会儿Window size 可用了,怎么通知发送端呢? 解决这个问题,TCP使用了Zero Window Probe技术,缩写为ZWP,也就是说,发送端在窗口变成0后,会发ZWP的包给接收方,让接收方来ack他的Window尺寸,一般这个值会设置成3次,第次大约30-60秒(不同的实现可能会不一样)。如果3次过后还是0的话,有的TCP实现就会发RST把链接断了。 注意:只要有等待的地方都可能出现DDoS攻击,Zero Window也不例外,一些攻击者会在和HTTP建好链发完GET请求后,就把Window设置为0,然后服务端就只能等待进行ZWP,于是攻击者会并发大量的这样的请求,把服务器端的资源耗尽。(关于这方面的攻击,大家可以移步看一下Wikipedia的SockStress词条) 另外,Wireshark中,你可以使用tcp.analysis.zero_window来过滤包,然后使用右键菜单里的follow TCP stream,你可以看到ZeroWindowProbe及ZeroWindowProbeAck的包。 Silly Window Syndrome Silly Window Syndrome翻译成中文就是“糊涂窗口综合症”。正如你上面看到的一样,如果我们的接收方太忙了,来不及取走Receive Windows里的数据,那么,就会导致发送方越来越小。到最后,如果接收方腾出几个字节并告诉发送方现在有几个字节的window,而我们的发送方会义无反顾地发送这几个字节。 要知道,我们的TCP+IP头有40个字节,为了几个字节,要达上这么大的开销,这太不经济了。 另外,你需要知道网络上有个MTU,对于以太网来说,MTU是1500字节,除去TCP+IP头的40个字节,真正的数据传输可以有1460,这就是所谓的MSS(Max Segment Size)注意,TCP的RFC定义这个MSS的默认值是536,这是因为 RFC 791里说了任何一个IP设备都得最少接收576尺寸的大小(实际上来说576是拨号的网络的MTU,而576减去IP头的20个字节就是536)。 如果你的网络包可以塞满MTU,那么你可以用满整个带宽,如果不能,那么你就会浪费带宽。(大于MTU的包有两种结局,一种是直接被丢了,另一种是会被重新分块打包发送) 你可以想像成一个MTU就相当于一个飞机的最多可以装的人,如果这飞机里满载的话,带宽最高,如果一个飞机只运一个人的话,无疑成本增加了,也而相当二。 所以,Silly Windows Syndrome这个现像就像是你本来可以坐200人的飞机里只做了一两个人。 要解决这个问题也不难,就是避免对小的window size做出响应,直到有足够大的window size再响应,这个思路可以同时实现在sender和receiver两端。 如果这个问题是由Receiver端引起的,那么就会使用 David D Clark’s 方案。在receiver端,如果收到的数据导致window size小于某个值,可以直接ack(0)回sender,这样就把window给关闭了,也阻止了sender再发数据过来,等到receiver端处理了一些数据后windows size 大于等于了MSS,或者,receiver buffer有一半为空,就可以把window打开让send … -
TCP 的那些事儿(上)
转自: http://coolshell.cn/articles/11564.html TCP是一个巨复杂的协议,因为他要解决很多问题,而这些问题又带出了很多子问题和阴暗面。所以学习TCP本身是个比较痛苦的过程,但对于学习的过程却能让人有很多收获。关于TCP这个协议的细节,我还是推荐你去看W.Richard Stevens的《TCP/IP 详解 卷1:协议》(当然,你也可以去读一下RFC793以及后面N多的RFC)。另外,本文我会使用英文术语,这样方便你通过这些英文关键词来查找相关的技术文档。 之所以想写这篇文章,目的有三个 一个是想锻炼一下自己是否可以用简单的篇幅把这么复杂的TCP协议描清楚的能力。 另一个是觉得现在的好多程序员基本上不会认认真真地读本书,喜欢快餐文化,所以,希望这篇快餐文章可以让你对TCP这个古典技术有所了解,并能体会到软件设计中的种种难处。并且你可以从中有一些软件设计上的收获。 最重要的希望这些基础知识可以让你搞清很多以前一些似是而非的东西,并且你能意识到基础的重要。 所以,本文不会面面俱到,只是对TCP协议、算法和原理的科普。 我本来只想写一个篇幅的文章的,但是TCP真TMD的复杂,比C++复杂多了,这30多年来,各种优化变种争论和修改。所以,写着写着就发现只有砍成两篇。 上篇中,主要向你介绍TCP协议的定义和丢包时的重传机制。 下篇中,重点介绍TCP的流迭、拥塞处理。 废话少说,首先,我们需要知道TCP在网络OSI的七层模型中的第四层——Transport层,IP在第三层——Network层,ARP在第二层——Data Link层,在第二层上的数据,我们叫Frame,在第三层上的数据叫Packet,第四层的数据叫Segment。 首先,我们需要知道,我们程序的数据首先会打到TCP的Segment中,然后TCP的Segment会打到IP的Packet中,然后再打到以太网Ethernet的Frame中,传到对端后,各个层解析自己的协议,然后把数据交给更高层的协议处理。 TCP头格式 接下来,我们来看一下TCP头的格式 你需要注意这么几点: TCP的包是没有IP地址的,那是IP层上的事。但是有源端口和目标端口。 一个TCP连接需要四个元组来表示是同一个连接(src_ip, src_port, dst_ip, dst_port)准确说是五元组,还有一个是协议。但因为这里只是说TCP协议,所以,这里我只说四元组。 注意上图中的四个非常重要的东西: Sequence Number是包的序号,用来解决网络包乱序(reordering)问题。 Acknowledgement Number就是ACK——用于确认收到,用来解决不丢包的问题。 Window又叫Advertised-Window,也就是著名的滑动窗口(Sliding Window),用于解决流控的。 TCP Flag ,也就是包的类型,主要是用于操控TCP的状态机的。 关于其它的东西,可以参看下面的图示 TCP的状态机 其实,网络上的传输是没有连接的,包括TCP也是一样的。而TCP所谓的“连接”,其实只不过是在通讯的双方维护一个“连接状态”,让它看上去好像有连接一样。所以,TCP的状态变换是非常重要的。 下面是:“TCP协议的状态机”(图片来源) 和 “TCP建链接”、“TCP断链接”、“传数据” 的对照图,我把两个图并排放在一起,这样方便在你对照着看。另外,下面这两个图非常非常的重要,你一定要记牢。(吐个槽:看到这样复杂的状态机,就知道这个协议有多复杂,复杂的东西总是有很多坑爹的事情,所以TCP协议其实也挺坑爹的) 很多人会问,为什么建链接要3次握手,断链接需要4次挥手? 对于建链接的3次握手,主要是要初始化Sequence Number 的初始值。通信的双方要互相通知对方自己的初始化的Sequence Number(缩写为ISN:Inital Sequence Number)——所以叫SYN,全称Synchronize Sequence Numbers。也就上图中的 x 和 y。这个号要作为以后的数据通信的序号,以保证应用层接收到的数据不会因为网络上的传输的问题而乱序(TCP会用这个序号来拼接数据)。 对于4次挥手,其实你仔细看是2次,因为TCP是全双工的,所以,发送方和接收方都需要Fin和Ack。只不过,有一方是被动的,所以看上去就成了所谓的4次挥手。如果两边同时断连接,那就会就进入到CLOSING状态,然后到达TIME_WAIT状态。下图是双方同时断连接的示意图(你同样可以对照着TCP状态机看): 另外,有几个事情需要注意一下: 关于建连接时SYN超时。试想一下,如果server端接到了clien发的SYN后回了SYN-ACK后client掉线了,server端没有收到client回来的ACK,那么,这个连接处于一个中间状态,即没成功,也没失败。于是,server端如果在一定时间内没有收到的TCP会重发SYN-ACK。在Linux下,默认重试次数为5次,重试的间隔时间从1s开始每次都翻售,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s,第5次发出后还要等32s都知道第5次也超时了,所以,总共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 2^6 -1 = 63s,TCP才会把断开这个连接。 关于SYN Flood攻击。一些恶意的人就为此制造了SYN Flood攻击——给服务器发了一个SYN后,就下线了,于是服务器需要默认等63s才会断开连接,这样,攻击者就可以把服务器的syn连接的队列耗尽,让正常的连接请求不能处理。于是,Linux下给了一个叫tcp_syncookies的参数来应对这个事——当SYN队列满了后,TCP会通过源地址端口、目标地址端口和时间戳打造出一个特别的Sequence Number发回去(又叫cookie),如果是攻击者则不会有响应,如果是正常连接,则会把这个 SYN Cookie发回来,然后服务端可以通过cookie建连接(即使你不在SYN队列中)。请注意,请先千万别用tcp_syncookies来处理正常的大负载的连接的情况。因为,synccookies是妥协版的TCP协议,并不严谨。对于正常的请求,你应该调整三个TCP参数可供你选择,第一个是:tcp_synack_retries 可以用他来减少重试次数;第二个是:tcp_max_syn_backlog,可以增大SYN连接数;第三个是:tcp_abort_on_overflow 处理不过来干脆就直接拒绝连接了。 关于ISN的初始化。ISN是不能hard code的,不然会出问题的——比如:如果连接建好后始终用1来做ISN,如果client发了30个segment过去,但是网络断了,于是 client重连,又用了1做ISN,但是之前连接的那些包到了,于是就被当成了新连接的包,此时,client的Sequence Number 可能是3,而Server端认为client端的这个号是30了。全乱了。RFC793中说,ISN会和一个假的时钟绑在一起,这个时钟会在每4微秒对ISN做加一操作,直到超过2^32,又从0开始。这样,一个ISN的周期大约是4.55个小时。因为,我们假设我们的TCP Segment在网络上的存活时间不会超过Maximum Segment Lifetime(缩写为MSL - Wikipedia语条),所以,只要MSL的值小于4.55小时,那么,我们就不会重用到ISN。 关于 MSL 和 TIME_WAIT。通过上面的ISN的描述,相信你也知道MSL是怎么来的了。我们注意到,在TCP的状态图中,从TIME_WAIT状态到CLOSED状态,有一个超时设置,这个超时设置是 2*MSL(RFC793定义了MSL为2分钟,Linux设置成了30s)为什么要这有TIME_WAIT?为什么不直接给转成CLOSED状态呢?主要有两个原因:1)TIME_WAIT确保有足够的时间让对端收到了ACK,如果被动关闭的那方没有收到Ack,就会触发被动端重发Fin,一来一去正好2个MSL,2)有足够的时间让这个连接不会跟后面的连接混在一起(你要知道,有些自做主张的路由器会缓存IP数据包,如果连接被重用了,那么这些延迟收到的包就有可能会跟新连接混在一起)。你可以看看这篇文章《TIME_WAIT and its design implications for protocols and scalable client server systems》 关于TIME_WAIT数量太多。从上面的描述我们可以知道,TIME_WAIT是个很重要的状态,但是如果在大并发的短链接下,TIME_WAIT 就会太多,这也会消耗很多系统资源。只要搜一下,你就会发现,十有八九的处理方式都是教你设置两个参数,一个叫tcp_tw_reuse,另一个叫tcp_tw_recycle的参数,这两个参数默认值都是被关闭的,后者recyle比前者resue更为激进,resue要温柔一些。另外,如果使用tcp_tw_reuse,必需设置tcp_timestamps=1,否则无效。这里,你一定要注意,打开这两个参数会有比较大的坑——可能会让TCP连接出一些诡异的问题(因为如上述一样,如果不等待超时重用连接的话,新的连接可能会建不上。正如官方文档上说的一样“It should not be changed without advice/request of technical experts”)。 关于tcp_tw_reuse。官方文档上说tcp_tw_reuse 加上tcp_timestamps(又叫PAWS, for Protection Against Wrapped Sequence Numbers)可以保证协议的角度上的安全,但是你需要tcp_timestamps在两边都被打开(你可以读一下tcp_twsk_unique的源码 )。我个人估计还是有一些场景会有问题。 关于tcp_tw_recycle。如果是tcp_tw_recycle被打开了话,会假设对端开启了tcp_timestamps,然后会去比较时间戳,如果时间戳变大了,就可以重用。但是,如果对端是一个NAT网络的话(如:一个公司只用一个IP出公网)或是对端的IP被另一台重用了,这个事就复杂了。建链接的SYN可能就被直接丢掉了(你可能会看到connection time out的错误)(如果你想观摩一下Linux的内核代码,请参看源码 tcp_timewait_state_process)。 关于tcp_max_tw_buckets。这个是控制并发的TIME_WAIT的数量,默认值是180000,如果超限,那么,系统会把多的给destory掉,然后在日志里打一个警告(如:time wait bucket table overflow),官网文档说这个参数是用来对抗DDoS攻击的。也说的默认值180000并不小。这个还是需要根据实际情况考虑。 Again,使用tcp_tw_reuse和tcp_tw_recycle来解决TIME_WAIT的问题是非常非常危险的,因为这两个参数违反了TCP协议(RFC 1122) 其实,TIME_WAIT表示的是你主动断连接,所以,这就是所谓的“不作死不会死”。试想,如果让对端断连接,那么这个破问题就是对方的了,呵呵。另外,如果你的服务器是于HTTP服务器,那么设置一个HTTP的KeepAlive有多重要(浏览器会重用一个TCP连接来处理多个HTTP请求),然后让客户端去断链接(你要小心,浏览器可能会非常贪婪,他们不到万不得已不会主动断连接)。 数据传输中的Sequence Number 下图是我从Wireshark中截了个我在访问coolshell.cn时的有数据传输的图给你看一下,SeqNum是怎么变的。(使用Wireshark菜单中的Statistics ->Flow Graph… ) 你可以看到,SeqNum的增加是和传输的字节数相关的。上图中,三次握手后,来了两个Len:1440的包,而第二个包的SeqNum就成了1441。然后第一个ACK回的是1441,表示第一个1440收到了。 注意:如果你用Wireshark抓包程序看3次握手,你会发现SeqNum总是为0,不是这样的,Wireshark为了显示更友好,使用了Relative SeqNum——相对序号,你只要在右键菜单中的protocol preference 中取消掉就可以看到“Absolute SeqNum”了 TCP重传机制 TCP要保证所有的数据包都可以到达,所以,必需要有重传机制。 注意,接收端给发送端的Ack确认只会确认最后一个连续的包,比如,发送端发了1,2,3,4,5一共五份数据,接收端收到了1,2,于是回ack 3,然后收到了4(注意此时3没收到),此时的TCP会怎么办?我们要知道,因为正如前面所说的,SeqNum和Ack是以字节数为单位,所以ack的时候,不能跳着确认,只能确认最大的连续收到的包,不然,发送端就以为之前的都收到了。 超时重传机制 一种是不回ack,死等3,当发送方发现收不到3的ack超时后,会重传3。一旦接收方收到3后,会ack 回 4——意味着3和4都收到了。 但是,这种方式会有比较严重的问题,那就是因为要死等3,所以会导致4和5即便已经收到了,而发送方也完全不知道发生了什么事,因为没有收到Ack,所以,发送方可能会悲观地认为也丢了,所以有可能也会导致4和5的重传。 对此有两种选择: 一种是仅重传timeout的包。也就是第3份数据。 另一种是重传timeout后所有的数据,也就是第3,4,5这三份数据。 这两种方式有好也有不好。第一种会节省带宽,但是慢,第二种会快一点,但是会浪费带宽,也可能会有无用功。但总体来说都不好。因为都在等timeout,timeout可能会很长(在下篇会说TCP是怎么动态地计算出timeout的) 快速重传机制 于是,TCP引入了一种叫Fast Retransmit 的算法,不以时间驱动,而以数据驱动重传。也就是说,如果,包没有连续到达,就ack最后那个可能被丢了的包,如果发送方连续收到3次相同的ack,就重传。Fast Retransmit的好处是不用等timeout了再重传。 比如:如果发送方发出了1,2,3,4,5份数据,第一份先到送了,于是就ack回2,结果2因为某些原因没收到,3到达了,于是还是ack回2,后面的4和5都到了,但是还是ack回2,因为2还是没有收到,于是发送端收到了三个ack=2的确认,知道了2还没有到,于是就马上重转2。然后,接收端收到了2,此时因为3,4,5都收到了,于是ack回6。示意图如下: Fast Retransmit只解决了一个问题,就是timeout的问题,它依然面临一个艰难的选择,就是重转之前的一个还是重装所有的问题。对于上面的示例来说,是重传#2呢还是重传#2,#3,#4,#5呢?因为发送端并不清楚这连续的3个ack(2)是谁传回来的?也许发送端发了20份数据,是#6,#10,#20传来的呢。这样,发送端很有可能要重传从2到20的这堆数据(这就是某些TCP的实际的实现)。可见,这是一把双刃剑。 SACK 方法 另外一种更好的方式叫:Selective Acknowledgment (SACK)(参看RFC 2018),这种方式需要在TCP头里加一个SACK的东西,ACK还是Fast Retransmit的ACK,SACK则是汇报收到的数据碎版。参看下图: 这样,在发送端就可以根据回传的SACK来知道哪些数据到了,哪些没有到。于是就优化了Fast Retransmit的算法。当然,这个协议需要两边都支持。在 Linux下,可以通过tcp_sack参数打开这个功能(Linux 2.4后默认打开)。 这里还需要注意一个问题——接收方Reneging,所谓Reneging的意思就是接收方有权把已经报给发送端SACK里的数据给丢了。这样干是不被鼓励的,因为这个事会把问题复杂化了,但是,接收方这么做可能会有些极端情况,比如要把内存给别的更重要的东西。所以,发送方也不能完全依赖SACK,还是要依赖ACK,并维护Time-Out,如果后续的ACK没有增长,那么还是要把SACK的东西重传,另外,接收端这边永远不能把SACK的包标记为Ack。 注意:SACK会消费发送方的资源,试想,如果一个攻击者给数据发送方发一堆SACK的选项,这会导致发送方开始要重传甚至遍历已经发出的数据,这会消耗很多发送端的资源。详细的东西请参看《TCP SACK的性能权衡》 Duplicate SACK – 重复收到数据的问题 Duplicate SACK又称D-SACK,其主要使用了SACK来告诉发送方有哪些数据被重复接收了。RFC-2833 里有详细描述和示例。下面举几个例子(来源于RFC-2833) D-SACK使用了SACK的第一个段来做标志, 如果SACK的第一个段的范围被ACK所覆盖,那么就是D-SACK 如果SACK的第一个段的范围被SACK的第二个段覆盖,那么就是D-SACK 示例一:ACK丢包 下面的示例中,丢了两个ACK,所以,发送端重传了第一个数据包(3000-3499),于是接收端发现重复收到,于是回了一个SACK=3000-3500,因为ACK都到了4000意味着收到了4000之前的所有数据,所以这个SACK就是D-SACK——旨在告诉发送端我收到了重复的数据,而且我们的发送端还知道,数据包没有丢,丢的是ACK包。 … -
E-Commerce Platform Options
The big name in open source e-commerce these days is Magento. In my previous job it was just too early and Magento was pretty buggy but it now seems to be the number one of choice of people I talk to in the industry. The main reason I'm not keen on it is that it is quite a big code base to learn and secondly it is in PHP. My attitude to PHP is similar to most French people's attitude to English: I can speak the language but I find it very inelegant and I'm really not keen on using it day-to-day. Over in Python-land I have a few options. Django Shop seems the best bet as a framework for building from but it seems pretty early days and most of my needs are different so I would end up with the vast bulk of the code being custom. Incidentally I picked up Beginning Django E-Commerce which for me was probably a bit basic but I would thoroughly recommend it for anyone new to e-commerce or Django. -
Python Web Frameworks
I thought long and hard about which framework to choose for this project. My first exposure to Python came from Zope. I really don't like being negative about projects and technologies and I met some very nice people in the Zope community. However I think Zope was a major factor in dooming the project I was working on to failure. The problem we had was the our development was very slow and we had big scaling problems. Zope had a very steep learning curve and while it is theoretically possible to scale it makes life very difficult. I got the chance to see Zope deployed in a variety of larger settings and every single one struggled on scaling. The other issue for me (which is very subjective) is that I simply didn't enjoy developing with Zope, I felt the framework kept pushing me in the wrong direction. I looked at Twisted and I know some very major websites using it and the performance is unbelievable, in fact I would go as far as to say that is the best performing of any Python framework. However I simply couldn't understand it! I'm sure if I'd persevered I would have got it … -
Launch!
It happened! Our first sale today. Somebody actually came to our website and bought from us! The whole system is working pretty much as planned. I find that I make fewer mistakes when I use Django and everything is going so much faster than I'm used to. I suppose there are a few other factors at play: The team is tiny so there is never much discussion.The codebase is also tiny. It is less than 1% the size of the last e-commerce codebase I worked with so there simply are fewer things to go wrong and everything is very easy to understand.I'm working Python rather than PHP so I have a language pushing me to do the right thing. Onwards and upwards. -
Supplier Extranet
One of the big challenges in E-Commerce is managing stock, if you run out it is a disaster but if you order too much that's also a disaster! Working with the manufacturers is always because as soon as you get to any sort of scale you can't simply buy from them, you need to give them forecasts and help them prepare their supply chains too. I'm always keen to automate away tasks so I've created an extranet to allow my manufacturers to get real time information on rate of sale (of their products) and to view rate of sale (ROS) per SKU. The slightly tricky thing here is security. The last time I did this I was working with Zen Cart which doesn't have a concept of permissions: you are either an administrator or not. Fortunately Django's authentication framework is great, very easy to use and allows finer grained access rights. I was thinking about generating weekly emails but I've decided not to bother. The web is just a much system for this type of problem. -
Mea Culpa
Today we had a pretty bad software problem which cost us nearly half the day's sales. We then had another issue due to a failed fix (although this didn't cost any sales). At launch although we had many difficulties the software platform wasn't one of them. It worked very well. The reason was that after it was finished it was tested extensively by Clare before there was a live deployment. Her testing caught many, many errors. Post launch there has been a very substantial redevelopment of the code. In particular, introducing PayPal and introducing i18n (which is still underway) have resulted in very major changes. I have however been testing the code myself rather than putting it out to someone else. This has meant that some of the bugs have got through to customers. From now on, I will get Clare to test all major changes. The other issue has been that my deployment to the live server is not automatic. It was always the plan to be automated via git but despite spending half a day on it I couldn't get it to work. So it was left as a manual and complex process which needless to say eventually …