使用免费工具WCAT为Web应用程序进行压力测试

原文地址:http://blogs.msdn.com/alikl/archive/2008/03/09/stress-test-asp-net-web-application-with-free-wcat-tool.aspx

步骤:
1.安装WCAT
2.创建配置文件
3.运行测试
4.检查结果

安装WCAT
下载并安装Internet Information Services (IIS) 6.0 Resource Kit Tools,其中包含WCAT。

创建配置文件
有三个文本文件需要创建和配置:
1.script.txt
此文件定义了请求,换句话说就是请求哪些页面和如何请求。下面是一个简单的script.txt示例:

NEW TRANSACTION
classId = 1
NEW REQUEST HTTP
Verb = “GET”
URL = “http:// localhost / BankingShmanking / Default.aspx”

2.distribution.txt
定义了不同请求的权重。例如,我需要我需要在1.aspx上生成2倍于2.aspx的请求,我就会在 此文件中进行描述。只请求一个页面的时候,这个文件是没什么作用的。如下是一个distribution.txt文件的示例(1代表设置classId为 1的请求,50代表50%的请求被分配到了以此classId为标识的请求上):
1 50
3.config.txt
定义了测试间隔和生成多少客户端进行请求Web应用程序,下面是一个config.txt文件的示例:
Warmuptime 5s
Duration 30s
CooldownTime 5s
NumClientMachines 1
NumClientThreads 20

这些文件保存于”C:\Program Files\IIS Resources\WCAT Controller”文件夹。

运行测试

在命令行模式下,进入到”C:\Program Files\IIS Resources\WCAT Controller”文件夹,执行如下命令:
wcctl -c config.txt -d distribution.txt -s script.txt -a localhost
再打开令一个命令行窗口,到C:\Program Files\IIS Resources\WCAT Client文件夹下,执行命令:
wcclient.exe localhost

检查结果
结果会直接显示到屏幕上:


同时在C:\Program Files\IIS Resources\WCAT Controller目录下生成日志文件。

使用WCAT对你的Asp.net进行测试

WCAT – Simple Performance Test Tool for your .NET web app

By 16 Sep 2011

WCAT (Web Capacity Analysis Tool) is a tiny but excellent tool from Microsoft to perform load test your web application on IIS.  This tool enables you to do performance analysis on various scenarios of your web application.  All “perfmon” performance counters (like processor time, private bytes usage,  disk queue length,  total bytes sent or received in network) can be specified for the performance testing.  A performance test is for a business scenario, hence a test needs to include all servers (application server, database server) involved in the business scenario.  This is tool is as handy as possible to perform a load test even on single machine.

Once you specify the scenario in your application (i.e. appropriate URLs), a number of virtual clients from various client machines  will visit the URL with appropriate request data.  Like other performance tools, the following players are involved in a performance testing:

  • Server – machines on which your web application components are running
  • Client – A virtual client on a machine which acts as end-user to visit the URL
  • Controller – This coordinates a test among the virtual clients on various machines.  It also capture and collate the performance counters from appropriate servers.

I’ve created a small ASP.NET MVC3 application with following actions:
* http://localhost/myapp/load/create – to insert a simple “comment” field  value into the database (using POST data COMMENT =  “<value>”)
* http://localhost/myapp/load – to lists all comments

WCAT uses Windows Scripting and you can use JavaScript syntax to define the scenario for your test.  Below is a sample scenario in a file scenario.ubr:

scenario
 {
 name    = "IIS Home Page";

warmup      = 30;
 duration    = 50;

default
 {
 // send keep-alive header
 setheader
 {
 name    = "Connection";
 value   = "keep-alive";
 }

// set the host header
 setheader
 {
 name    = "Host";
 value   = server();
 }

// HTTP1.1 request
 version     = HTTP11;

// keep the connection alive after the request
 close       = ka;
 }

//
 // This script is made for IIS7
 //
 transaction
 {
 id = "My App Load Test";
 weight = 1;

request
 {
 url = "/myapp/load/create";
 verb = POST;
 postdata = "Comment=Tested";
 statuscode= 200;
 }

request
 {
 url         = "/MyBooks/load";
 statuscode  = 200;
 }

close
 {
 method      = reset;
 }
 }
 }

A scenario file normally contains warmup time (ramp up), test duration, cooldown time (ramp down).  The default section enables you to specify default HTTP headers for the test.  The transaction section is used to specify the actual business scenarios.  The weight property is used to set the priority of this transaction.  The request section is used to specify individual page request in the transaction.  A “request” contains

  • URL of the page
  • Optionally the HTTP verb (default GET).  In case of posting data, you have to specify the POST as verb.
  • POSTDATA for POST
  • Status code which is normally 200, but for some cases you may need to specify 300 or 302 for moving request

The other test details like servers and client machine names,  number of virtual clients, performance counters can be specified to WCAT through another script file called “setting file”.  Below is a sample setting file named “setting.ubr”:

settings
 {
 clientfile     = "scenario.ubr";
 server         = "localhost";
 clients        = 2;
 virtualclients = 10;

counters
 {
 interval = 10;

counter = "Processor(_Total)\\% Processor Time";
 counter = "Processor(_Total)\\% Privileged Time";
 counter = "Processor(_Total)\\% User Time";
 counter = "Processor(_Total)\\Interrupts/sec";

counter = "Memory\\Available KBytes";

counter = "Process(w3wp)\\Working Set";

counter = "System\\Context Switches/sec";
 counter = "System\\System Calls/sec";

counter = "Web Service(_Total)\\Bytes Received/sec" ;
 counter = "Web Service(_Total)\\Bytes Sent/sec" ;
 counter = "Web Service(_Total)\\Connection Attempts/sec" ;
 counter = "Web Service(_Total)\\Get Requests/sec" ;
 }

// other settings
 }

A setting file usually contains the following:

  • The scenario file the clients need to execute
  • Server machines
  • Number of physical client machines for this test
  • Number of virtual clients for this test
  • Performance counters
  • Registry settings

Note that you can use any file extension for scenario and setting files.  I have followed the convention”ubr” is used in WCAT sample.

Initial Setup

  1. Download the tool from http://snip.udooz.net/wcat63.   It has x64 version also.
  2. Add the installed folder path into system PATH.

This setup has following three exeutables and one Windows script file along with documentation and samples folders:

  • wcctl.exe – controller
  • wcclient.exe – client
  • wcutil.exe – small utility to view a brief report of a test
  • wcat.wsf – used to update, terminate and run wcclient on various client machines.

Initially, you need to update WCAT setup on all client machines by

 wcat.wsf –terminate –update –clients {comma separated list of WCAT client machines}

Steps for the Testing

To perform a test, you need a machine for “controller”, one or more machines for “clients” and the server machines.  You can do the testing even within a single machine by specifying “localhost”.

  1. Once you prepare the scenario and setting files, create a folder  in the controller machine for your test and copy these files on to it.
  2. Open the command prompt as Administrator.
  3. Run wcctl -t scenario.ubr -f settings.ubr -x on the controller machine.  The output will be like

4. Run wcclient.exe on all client machines.

After the test run, the output in the controller command prompt would be like

After all the test run completed, result will be stored in log.xml file in the controller’s  machine current directory.  WCAT has a XSLT “report.xsl” to transform this XML into readable in its installed folder.  Copy the file into log.xml.  Open the log.xml in the browser to see the output.  A part of log.xml file is

<?xml version='1.0'?>
 <?xml-stylesheet type='text/xsl' href='report.xsl'?>
 <report name="wcat" version="6.4.0" level="1" top="100">
 <section name="header" key="90000">
 ...

<item>
 <data name="counter" >\Processor(_Total)\% Processor Time</data>
 <data name="avg" >1.82</data>
 <data name="min" >1.82</data>
 <data name="max" >1.82</data>
 <data name="delta" >0.00</data>
 <item>
 <data name="time" >0.00</data>
 <data name="current" >1.82</data>
 </item>
 </item>
 <item>
 <data name="counter" >\Process(w3wp)\Private Bytes</data>
 <data name="avg" >98455552.00</data>
 <data name="min" >98455552.00</data>
 <data name="max" >98455552.00</data>
 <data name="delta" >0.00</data>
 <item>
 <data name="time" >0.00</data>
 <data name="current" >98455552.00</data>
 </item>
 </item>
 </table>

...
 </report>

Final Words

WCAT might not help to test an entire application which normally has so many user interaction which are not simply captured by single POST request.  However, it would help to perform load testing on every atomic part of your application or to perform technology evaluation as part of prototype engineering.

License

This article, along with any associated source code and files, is licensed under The Creative Commons Attribution-ShareAlike 2.5 License

一次移动记账 App 的设计探索

现代智能手机给我们提供了非常多丰富实用的功能,比如平时颇为在意金钱去向的我,就是一个 手机记账 App 的使用者,曾经尝试过各种记账 App,但好像都有那么一点不满意,于是我就想如果是我来设计这么一款 App 的话,我会怎么去设计呢?本文记录的就是一次移动记账 App 的设计探索过程。

一. 设计前的思考

简单、高效和安全是设计之初就想到的三个关键词

在一天的使用过程中,我很可能存在多次记账的需求,这也意味着我会频繁打开这个产品,简单和高效可以让我更快的完成任务。记账因为涉及到资金这个问题,所以它同样需要一定的安全性。如果要给这个 App 一个定位的话,我认为它是一款 “能满足大众基本记账需求的轻便的移动记账 App ” 。

基于以上的思考,很快就产出了以下稿子:

一次移动记账 App 的设计探索

视觉呈现上,我把它做的非常简洁干净,在进入密码解锁以后直接呈现一个列表,左下角则是有一个常驻的悬浮着的绿色添加按钮,用来添加一笔支出或者收入。

当然也有比按钮更优雅一点的方案:

一次移动记账 App 的设计探索

通过手势下拉的操作展开一笔新的支出或收入,因为手势的优势在于没有固定的需要点按的操作位置,能有更高的效率。

尽管看似合理的初步方案就这么出现了,但是如果仔细深入思考的话,会发现它并没有实际解决你希望能够更高效记账这个行为。出于安全的考虑,你始终在打开记账 App 后需要输入四位的密码,然后才能进入记账的行为,这个过程会让你在每次记账的时候都需要多按几次手机。

为了解决这个痛点,我从最基本的使用场景出发,思考了以下几个问题:

  1. 我打开记账 App 的目的是干什么?
  2. 为什么记账?
  3. 什么时候记账?

针对第一个问题,答案很显然:目的就是记账或者查看收入和支出的报表。 第二个问题,记账的目的则是因为想了解自己的财务状况 / 收支分布。 而针对第三个问题:一般情况下则是在完成一笔消费后,或者可能是晚上回忆一下整天的消费统一记录。

在重新整理完这些思考以后,我最终决定重新拟一套设计方案。

二. 思考后的重设计

非首要功能,不应成为主路径上的障碍

在我常试过的很多记账 App 中,它们都提供了密码保护的功能,但也却因为这个密码保护功能使得记账的操作多了很多的步骤。在这一点上,金蝶的 “随手记” 做的不错,在密码保护界面提供了快捷入口。然而从我个人的角度来看,我并不是非常喜欢在密码保护界面多那么几个快捷入口的方式,至少我希望在不影响实际体验的情况下,能使界面显得更简洁一点。我反复思考后得出的结论是:密码保护需要保护的是账单隐私,而不是 “记账” 这个行为。

可以做一个大胆的设定,打开 App 后,如果直接进入记账界面,可以为我节省很多操作的步骤,甚至减去了密码保护界面点击一次快捷入口的行为。

一次移动记账 App 的设计探索

于是重新设计的界面出炉了。

当我打开 App,呈现在我眼前的就是记账界面,我可以直接输入数字以后点击对勾就完成一笔记账操作。右上角有个查看报表的功能入口,当我点击这个图标的时候,会弹出密码框,输入密码就可以进入报表界面。

智能一点点,就能提升用户体验

回到此前思考的第二个问题,我记账的目的是为了 “了解我的财务状况” 。 所以预算功能及与其相关联的提醒功能就变得尤为必要。我设想了一个叫做 “预算” 的功能,当我设置了我每月的预算,并且每月的支出超出我设定的预算以后,那么在首页的记账界面,Titlebar 会变成红色以警示你应该省着点花钱。

一次移动记账 App 的设计探索

至于我何时会记账这个问题,因为在很多时候可能会存在我完成一笔消费的时候记账,因此我的想法是根据打开的时间来预判,比如午餐时间打开的话,分类图标则默认选中 Food 选项。周末下午茶时间打开的话,分类图标则默认自动选中休闲类的选项,如果在程序开发上合入了智能学习的模块,它甚至可以根据用户的个人习惯,为每个记账的时间作分类的选择。通过使用预判的情况来减少我可能会去点击的操作,从而减少不必要的步骤。

为效率服务,在交互细节上的优化

在查看报表界面的时候,会遇到一些需要切换年份,月份或者周为单位的时候,因为手机屏幕在不断变大的情况下,如果将 Tab 放置在顶部,单手操作的时候切换会变得不太容易。因此对于切换时间这个维度的操作,我也重新思考了一下,利用下拉手势来解决。

一次移动记账 App 的设计探索

三. 视觉设计

我给这款产品起名叫 Save+,也就是给予更节省的寓意,产品虽然是一个以记账为目的的 App,但是我希望传达给用户的并不是我每个月花掉了多少钱,而是省下多少钱的感觉。因此在 icon 的设计上使用了储蓄罐作为隐喻。

一次移动记账 App 的设计探索

轻快、亲和

简单,高效是设计这个 App 的初衷,视觉呈现上需要传递给用户 “轻” 的感觉,简明清晰的图标和键盘作为主界面的元素符合直观的感受,让人在打开后就能直接进行操作。对每一枚分类图标都做了一个彩色选中态的处理,温和的颜色使界面显得不单调的同时更具亲和力。

一次移动记账 App 的设计探索 一次移动记账 App 的设计探索 一次移动记账 App 的设计探索

图标中的图形奥义

分类 icon 众多,视觉设计上保持统一的语言可以使整体感更强。对分类图标类型进行视觉上的归纳后主要分为三种类型:圆形、方形和斜形,以此为依据保持图标的整体统一性和饱满度。

一次移动记账 App 的设计探索

结语

当设计给定一个命题后,我相信从不同的使用场景和需求角度来解读往往会给出不同的设计解,从实际的使用场景中出发,瞄准一个哪怕很细微的痛点进行思考,往往也能发现一个新的突破点,而这个突破点则更可能是直接起到决定产品差异化走向的关键因素。当思路不够开阔的时候,不妨暂时先放下手中的设计任务,先找出这个突破点,以此为设计的依据和导向来设计产品。

感谢你的阅读,本文由 腾讯ISUX 版权所有,转载时请注明出处,违者必究,谢谢你的合作。
注明出处格式:腾讯ISUX (http://isux.tencent.com/finance-mobile-app-design.html)

git学习总结

从svn到git

两者都是优秀的版本管理工具(giter请不要鄙视svner)

  • svn上手非常容易,操作简单
  • git功能强大,但是要熟练使用分支不算容易

git因为是分布式的,所以其核心就是分支(只有master分支情况下和svn差不多?),分支的意义在于,可以将项目代码按照功能、模块拆分成不同的分支。比如这个产品要加一个支付功能和一个登陆功能,可以创建两个分支,交给不同的开发人员并行开发。登陆功能先开发完,测试无误后合并改分支到master分支,master分支部署上线。支付功能虽然没有开发完成,但是在另一条分支上,所以产品上线和功能开发完全不受影响。这才是分布式开发的高效模式。

被git坑了一个星期之后决心把官方文档看一下,结合实践经验进行了整理。


新手常见问题

  1. 如何查看有哪些分支?
    git branch -a
  2. 如何强制检出/切换分支或分支指定文件
    git checkout <branch> [file] [-f]
    强制更新,以branch版本的代码为主
  3. 提交代码出现冲突冲突怎么办?
    hint: Updates were rejected because the tip of your current branch is behind
    hint: its remote counterpart. Integrate the remote changes (e.g.
    hint: 'git pull ...') before pushing again.
    hint: See the 'Note about fast-forwards' in 'git push --help' for details.
    先切换分支,然后拉取分支上最新的代码覆盖到本地
    git pull
    添加或者提交代码,解决冲突之后
    git push

  4. 如何新建分支
    git checkout -b <branch_name>
    本地建立 branch 並立即切換到新分支
    git branch -m <new_name>
    修改分支名称
  5. 从远程仓库拉取代码到本地仓库,并建立跟踪关系
    git clone http://xxx.git
    或者
    get clone git@xxx.git
    然后
    git checkout -b <本地新分支名> <对应的远程分支名>
  6. 远程仓库新建了一个分支,如何更新远程分支信息
    git fetch <remote base>
  7. 如何在远程仓库新建一个分支
    git branch <branch name>
    新建一个本地分支,按照正常流程提交完代码后,推送到远程
    git push <remote base> <local branch>:<remote branch>

实用指令

reset

git reset [file]
取消暂存

remote

查看远程仓库名

git remote -v
查看远程仓库url

git remote add <basename> <url>
新增远程仓库

git remote show <basename>
查看远程仓库详细信息

git remote rename <old basename> <new basename>
重命名远程仓库

pull

相当于fetch和merge

push

git push [remote_branch] [local_branch]
推送本地仓库代码到远程仓库,相当于svn的commit

git push <remote base> [tag name]
推送本地标签到远程仓库

git push <remote base> <remote branch>:<local branch>
将本地分支推送到指定的远程分支

git push <remote base> --delete <remote branch>
删除远程分支

tag

查看标签(用来标记标志性的稳定版本信息)

git tag -l '[expression]'
查看那符合正则表达式的

git tag -a <tag name> -m <comment>
添加带注释的标签

git tag -a <tag name> <md5>
对某个版本打标签

git tag [tag name]
如果没有标签名,则为查看所有标签。带标签名则为新建标签

merge

git merge <branch name>
将其他分支合并到本分支

commit

git commit -a -m 'xx'
暂存并提交

branch

git branch
查看本地仓库分支

git branch -v
查看本地仓库分支最后一次提交情况

git branch -vv
查看分支跟踪情况

git branch <branch name>
新建分支

git branch -d <branch name>
删除分支

git branch [--merged | --no-merged]
查看已合并|未合并的本地仓库分支

git branch -u <remote base>/<remote branch>
修改当前跟踪分支

commit

git commit -a -m 'xx'
提交并且暂存暂存的方法

checkout

git checkout -- [file]
恢复文件

git checkout -b [branchname] [tagname]
在特定的版本上创建一个新的分支并切换到此分支

git checkout -b [local branch] [remote base]/[remote branch]
将远程分支检出到本地分支

git checkout --track <remote base>/<remote branch>
让当前分支跟踪远程分支

git checkout --track <remote base>/<remote branch>
git checkout -b <local branch> <remote base>/<remote branch>
让当前分支跟踪到远程分支。两条命令作用基本一致,不同的是第二条命令可以重命名检出的分支。

rebase

git rebase [basebranch]
变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。

小技巧

查看配置

git config -1

设置别名

git config --global alias.<name> <commend>

保存用户名和密码

对于http(s)协议,可以用下面命令临时缓存

git config --global credential.helper cache
开启linux缓存
git config --global credential.helper wincred
开启windows缓存

对于ssh协议,可以用ssh key,具体教程网上很多

权威教程

博客:http://yalishizhude.github.io
作者:亚里士朱德

如何设计类似微信的多终端数据同步协议 | Grouk实践分享

本文由王渊命在高可用架构群所做的分享整理而来,转载请注明高可用架构公众号:ArchNotes。

王渊命,团队协作IM服务Grouk联合创始人及CTO,技术极客,曾任新浪微博架构师、微米技术总监。2014年作为联合创始人创立团队协作IM服务Grouk,长期关注团队协作基础工具和研发环境建设,Docker深度实践者。

我们Grouk是一个创业团队,面向团队通讯的主打产品应用刚开始公测,因此我们也需要实现类似微信的多端数据同步功能,下面我主要从技术和产品的结合场景进行一些心得分享,感觉我们在这方面的探索还是值得和大家探讨的,这种需求业界也没有非常成熟的公开解决方案。

、移动互联网时代多终端数据同步面临的挑战

首先要讲的是,多终端同步的含义及应用场景。

多终端同步是指用户在多个终端切换时可获得一致性体验,不丢失上下文,同时隐含的一个含义是,如果用户多个终端同时在线要能做到实时同步。

举几个应用的例子:

1 Trello 看板应用

用户打开后,其他人操作看板,要能实时变化,不依赖用户刷新页面。如果用户在多个终端操作,也需要做到实时变化。通过测试,我发现Trello在移动端和PC同步的时候还是有Bug的。例如,PC设置离线,手机上操作card。PC连网,不刷新页面,数据经常无法同步。

2 Quip这样的多人协作编辑

某人的编辑结果,其他人要能实时看到。同时还支持离线编辑、冲突合并。例如,Evernote多人协作是文档锁定模式的,冲突很难自动合并,体验上就差些。

这几种典型的应用场景是移动互联网爆发以来,应用富客户端化带来的一种趋势性变化。

移动端上是独立应用,PC端是基于JavaScript的应用,和原来PC互联网时代刷页面的交互体验完全不一样。这个当然原来也有,但应用没现在这么广泛。

移动客户端的爆发和应用富客户端化带来以下几个挑战:

  • 服务器端的输出由HTML变成结构化数据(json等)。原来基于浏览器和HTTP协议的缓存规则机制失效,客户端需要针对具体的业务场景设计缓存。没有缓存的话,每次全量拉取很浪费流量。
  • 用户习惯从多个终端进行操作,对跨屏操作的体验要求比较高了。
  • 多人协作场景下,数据需要实时同步到不同用户的不同设备上。

、多终端数据同步与传统消息投递协议的差异

接下来说一下多终端数据同步和IM的关系

虽然数据同步机制和IM消息投递是两个问题,但如果实现了实时同步,基本上就实现了一种特殊的IM。所以先说一下传统的IM投递机制。

传统的IM投递协议,大家应该都比较熟悉,5月的时候群里沈剑分享过一次。

这里借用其中的一句话:

消息可达性即消息的可靠投递,有一个著名的定理:SMC定理,Single-Message Communication,Published in :Communications, IEEE Transactions on (Volume:24 , Issue: 2 ) ,很短的一个论文。文章的结论是:任何端到端的消息传递协议,消息既不丢失,也不重复是不可能的。

也就是说传统的IM消息投递要么接受消息丢失,要么接受消息确认重试导致的重复问题。当然可以通过应用层面的排重机制来解决一问题。这里不再细说传统IM的投递机制,大家想了解可以看本公众号中沈剑的分享(【直播全文记录】 从零开始搭建高可用IM系统)。

虽然传统的IM投递机制+历史记录,也可以实现多终端同步:

  • 所有设备都在线的情况下,直接投递。
  • 离线→在线时,拉取历史记录补充缺失记录。

但这样做比较困难的地方在于:

  • 变更如何同步?我们的消息不像传统IM,是不可变对象,我们的消息是可变的。同时,群组列表,联系人列表,这些都是可变的,如何同步?
  • 投递确认机制的缺陷会导致一致性不好控制,如果出现多个终端不一致的情况,客户端无法自修复。只能提供特殊的刷新机制,由用户自己刷新。

比如,我前面提到的Trello的情况。当然,Trello的具体实现没分析过,这里只是推测。于是,我们考虑使用同步协议。说到同步机制当然要说一下微信,今天说分享的时候有人就提到了微信的SYNC。

微信的SYNC协议没有详细的公开分享,按照公开说明,是参考Activesyec实现的。据我的观察,当然,以下微信协议的说明不保证正确性,群里也有微信的同学,可以纠正。

  • 同步机制是通过服务器通知,客户端拉取机制实现的。IM协议投递的是新消息的通知,拉取是根据版本号增量同步,将消息投递转换为基于状态同步的协议。(这个有公开说明)
  • 每个Folder的版本号是严格有序递增的,Folder不是按照会话划分的。
  • 微信投递消息和邮件类似,是将消息投递到每个人的收件箱中,每投递一个消息增加一个版本号。

以上只是我个人的简单分析,不确定微信的服务器端是如何存储的。也不确定微信是如何处理变更的,比如,通讯录的同步。所以我们还是得自己设计一个同步协议。

三、Grouk在多终端数据同步协议上的探索实践

到这里,先总结下我们设计的该同步协议的目标 :

  • 解决接口数据做本地缓存需要根据具体接口单独设计的问题,设计一种统一的客户端缓存数据机制。这个问题应该是所有App类应用都会遇到的问题。
  • 实现消息的多终端增量同步,然后通过同步机制确保不丢消息。同步机制必须避免流量浪费,所以需要做增量。
  • 消息同步和联系人/群组等同步使用同一套机制。这个也为以后的业务数据类型扩充做准备。
  • 客户端数据能自修复达到最终一致性。
  • 不解决冲突合并问题。因为我们的消息比较轻量,不需要像文档一样考虑冲突问题,降低复杂性。

有了目标后,我们首先想到了Git等版本管理系统。因为二者要解决的问题是类似的,区别在于实时性上,还有Git的Server和Client是对等的,而我们这里的Client只是Server的子集。

因为时间关系,关于Git等版本管理系统的机制这里不细说了。直接说一下我们的抽象和解决方案 。

数据结构图,如下:

  • 每个需要同步的数据集抽象成一个Folder,Folder可能是多人共享的,也可能是某人专用的。这里的Folder相当于一个索引表,引用的是对象ID。
  • 每个Folder维护一个变更集(ChangeSet),增量同步通过变更实现,变更的版本号有序递增。变更是每次操作生成的,每一次Folder索引或者Folder引用对象的操作都生成一个变更。
  • 变更(Change)有对应的操作(OP)。如:新增、更新、删除等。包括索引变更和索引引用对象的变更。携带变更数据。客户端根据操作要在本地实现重放逻辑。
  • 每个Folder中的索引对象会被分配一个该Folder中的有序递增ID。每个索引对象也可以拥有自定义属性。
  • 所有的数据对象都统一定义,有更新时间,等基本字段。抽象出通用的操作接口(ObjectStore)。
  • 客户端会通过Change将服务器的Folder及对象库同步下去,不过同步的只是服务器上的一个子集,并不是全量。

客户端可以通过对象的更新时间来确定本地缓存的有效性。

下图是我们利用这套机制的流程:

  • 用户发消息、修改消息、修改个人信息等操作,都触发一次相关Folder的变更,存到变更集中,实时投递到在线客户端。
  • 在线客户端收到变更后,检查本地的版本号和当前版本号是否连续。如果不连续说明有消息丢失,从服务器拉取二者之间丢失的变更。然后客户端根据操作定义将变更应用(apply change)到本地的Folder和对象库。
  • 离线客户端上线后,带上本地的Folder的版本号,发起sync request,去服务器端同步变更。同步后需要进行的操作同上。
  • 所有的对象通过统一的接口获取。支持类似于HTTP的ETag,变更更新模式,不过是针对每个对象的版本,以增强本地缓存机制。

可以说,相当于实现一个服务器和客户端实时同步的轻型数据库。

以下是我们这样设计的优缺点。

优点:

  • 用户在线的情况下,大多数情况变更是直接投递下去的。比通知→拉取模式的和服务器的交互少,更省资源。
  • 离线缓存比较容易实现,离线浏览的体验会比较好。
  • 能保证终端和服务器的数据一致性。
  • 相对比较通用,可以适用于多个业务场景。

缺点:

  • 本地客户端的实现逻辑比较重。微信的思想是轻客户端,重服务器。我估计我们在这里还得踩些坑。
  • 只能保证同一个Folder的最终一致性。

基本协议设计就讲这里了,再说一下我们的技术栈。

主要还是基于Java+Netty研发。我们撸了一个简单的前端框架,主要是为了实现用同一套逻辑,服务多个接入层。

我们的接入层支持的协议有HTTP,自定义TCP,WebSocket。通过接入层转换后,变为内部的request/response,后面共享同一套逻辑。也就是说同一个请求,可以通过HTTP发送,也可以通过长连接(TCP/WebSocket)发送。

数据对象上,我们接口支持JSON/Protobuf两种。根据客户端的accept自动适配。接口输出格式统一定义对象,客户端可以和服务器端共用。

总结下当前应用,尤其是工具应用的一种趋势。

IM已经变得不像IM,不是IM的要变成IM。前半句是说,当前的IM已经逐渐不像传统的IM了,无论是微信,还是Slack,还是我们的Grouk,和传统的IM区别越来越大。后半句是说,不是IM的应用因为要做多终端实时同步,协议越来越靠近IM机制了。

另外个人感觉这种趋势不一定仅局限在工具类。哪怕是电商网站,如果能同步用户的购物车到多个终端,用户的体验也会更进一步。

我们应用使用同步协议已实现的效果 :

  • 多终端数据保持一致,用户切换后不会丢失上下文(比如QQ的消息只投递到一个终端)。
  • 允许多个终端登录,比如,多个手机、多个Web。
  • 历史记录可以在任何一个端获取,也可以通过搜索从任何一条历史消息开始上下回溯。
  • 未读数/收藏实时同步。
  • 联系人信息/群组信息实时同步。
  • 更多欢迎注册体验 https://grouk.com(顺便打个广告)。

最后,再说一个题外话,就是创业公司做技术类的创新是否值得?

我们也讨论过,假设当初直接拿现成的XMPP来做,估计我们的推出时间也可以早几个月。我们在这套机制上花费的时间也不少。但我们还是觉得当前IM这么多,用户的体验已经被QQ、微信等工具教育的情况下,如果体验不能更进一步,估计用户连尝试的愿望都没有。但到底花多少时间,估计要做个平衡。

Q&A

Q1:为什么不采用XMPP协议呢?多人协作时后端出现用户不在一台服务器上如何同步?


XMPP由于众所周知的原因,XML不太适合移动使用。一般移动上使用都要做压缩,比如WhatsApp。另外就是前面描述的,做变更同步比较麻烦。

Q2:客户端所有请求都是通过和服务器的长连接过来吗?没有走比如短连接HTTP协议之类的?


不是所有,有走短连接的。我们采用一种动态机制,长连接优先。消息上我们没有采用长轮询的方式。客户端是TCP长连接,Web版本是WebSocket。

Q3:这个版本号必须是有序的吗?是否可以跟Git一样用随机字符+链表的方式做?


我们这个方案里版本号必须是有序严格递增的,因为要靠这个判断是否丢失消息。Git的方案是因为需要离线写操作,我们当前没这个需求,写都是通过服务器中心写的。

Q4QQ的消息只投递到一个终端?这是多年前了吧?

QQ是对移动端做了写优化,离线登陆后会补充投递一部分消息,但做不到全终端一致同步。

Q5:如何选择客户端服务器之间心跳的时长?有哪些选择的因素考虑,怎么权衡?


这个说实话我们也在摸索。没有太多数据支撑的经验。移动端其实心跳已经不是很重要了,大家的使用习惯基本上是查看消息回复,然后就沉后台了。我们做了点优化就是所有的消息都视为一种心跳。心跳其实是服务器端判断客户端是否在线的一种方式。移动客户端网络变化能收到通知,一般是几分钟一次。 Web版本没有这种功能,所以要靠心跳来判断网络,一般是几秒钟一次。

Q6:发现消息版本不连续后,是全量拉取吗?还是可以判断拉去到哪?


发现消息不连续后,由于版本号是有序递增的,可以计算出中间的差距,直接拉缺失的即可。当然服务器的版本是有限的,如果发现客户端的本地数据太旧,是需要重新全量拉取的。全量拉取的机制不同,Folder的规则不一样。

想和群内专家继续交流有关高可用架构的问题,请关注公众号后,回复arch,申请进群。

阿里云组建医疗大数据:未来数据化一个人是否有可能?

9 月 18 日报道  (文/吴艳梅)

埃里克托普在《颠覆医疗》一书中有过数字化人类的描述:

通过将肉体置于我们外延的神经系统中,通过电子媒体的方式,我们建立起一个动态系统,将快速成熟的数字化、非医学领域的移动设备、云计算和社交网络与蓬勃发展的基因组学、生物传感器和先进成像技术的数字化医学领域合为一体,将这些工具和能力加以综合,我们就能为每一个人获取关于 ta 的解剖学、生理和生物数据。

但这些数据如何在一个更长的时间维度上,对人体进行更全面的数据采集和汇总,如糖尿病、高血压、心脏病、体检、运动、睡眠数据等多个场景,并让医疗健康生态链上的各个角色都能够使用上这份完整的数据,是否能造福每一个生命?

9 月 17 日,阿里云同深圳中瑞奇、杭州金卫健康宣布,三方将合作组建“云上安心”联盟。通过联合社区医院、三级综合医院、医疗硬件厂商、医疗健康 APP、健康体检中心、医疗健康分析模型提供商,在患者知情并授权下,将散落各处的健康医疗数据进行汇聚打通,以期实现基于数据的精准医疗。

阿里云

以心脏病治疗为例,通过将“云上安心”联盟中的心电设备产品“好朋友”接入人体,并连接“好朋友心电图”APP 后,用户便可查看自身心电数据。同时,数据同医院同步,如出现异常,医生或急救中心可提前介入。中瑞奇创始人汪远思表示,“该产品直接面向个人用户开发,并提供专业医护服务。” 也就是说,每一个用户都相当于拥有了一位私人医生。

在今年 7 月初的试点中,阿里云和中瑞奇向杭州米市巷社区 2 万老人中的心脑血管疾病患者发放了相关设备,金卫健康提供面向居民、社区医院的心电数据采集及心脏健康管理服务,帮助社区居民能够及早发现心脏方面潜在风险,将高危人群纳入监护体系。

“云上安心”联盟的生态参与方所有数据都将存放于阿里云上,借助阿里云强大的计算能力和开放的心电算法,实现对亿万级数据的并行处理。诸如心电图的记录过程、心电噪音的过滤,特征值抓取(如p波,r波,st 段)等。通过阿里云大数据处理平台 ODPS、分析型数据库 ADS 还可以进行离线数据和实时数据处理,快速接入更多标准的应用及第三方医疗数据。

阿里云高级产品专家武凯表示,联盟将以心电数据为中心,打通医院生化指标、诊断数据和医院外心电、血糖数据,以及其它体征、运动等各种碎片数据,以期更加全面立体的描述一个患者的健康情况,从而达到精准医疗的目的。

据介绍,心电数据收集类似声音数据采集,对传感器数据的采集频率高,且心电数据量非常大,一个人 24 小时的心电数据大概在 150M 左右,一个人一生心脏跳动 25-30 亿次,会产生人均 4394G 心电数据量。在当前的医疗工程界,无论是院内的静态心电数据,还是动态心电数据,用于疾病检测完之后,都会因数据量巨大而被闲置或清除。

武凯表示,这些数据如果被利用起来,将对中国整个心脏疾病的检测产生不可估量的价值。“挑战在于,海量的心电数据不仅需要无限扩容的储存空间,更需要强大的数据处理分析能力,这两者都是阿里云的优势。”

据悉,心电数据库在美国和欧洲已经成为普遍的医学指标,但在中国,目前并无完整心电数据库。且心电算法处理模式还仅仅是基于小样本特征识别的心电信号分类。“希望在未来建立基于大数据能力的统计分析心电信号的分类方法,以及面对医疗行业的大数据样本,逐步实现人体数据化。”武凯表示。