2012 Archives

转:http://www.dbanotes.net/review/China_Android_Market_UE.html

by Fenng@dbanotes.net

近一段时间在发布 丁香园用药助手 Android 版的过程中把国内几个重要的 Android Market 用了个遍,每次要发布新版本的时候都要感慨一下:几乎所有的 Android Market 后台的用户体验都不怎么好。

信息各有一套

国内所有的 Android Market 和 Google 官方 Android Market 都是不"兼容"的,无论是产品的描述信息以及应用类别划分,每一家都是自成一套。比如,软件截图,各有各自的要求,尺寸、格式如果不一致的话,还要针对性的单独人工处理,对开发者的工作量无形中增加了许多。对产品的描述也是千奇百怪,有的支持富文本编辑,有的只支持普通文本。有的更新软件要求写更新内容,有的则不提示填写,如果自己想写的话,需要修改整个 App 的描述信息。再比如分类信息,丁香园用药助手在有的 Market 上只能列入到「生活」类,而在另一个 Market 或许就要被迫列入「其他」,因为实在找不到和健康或是医疗相关的类目。

版本控制问题

只有少数一两家对版本控制还算有点意识,多数都没有相对靠谱的版本控制机制。有放任自流派:开发者在后台任意更新版本;也有关卡审核派:让你处于一个无法修改也无法撤销的"审核中"状态,一旦发现错误,想更正只能等下一个版本。至于审核周期,也是千奇百怪,有的立等可取,有的需要人工联系「我们发布了一个新版本,抽空给审核一下吧」,也有的长达一周。

后台可访问性

有的后台速度慢(这是很难让我想通的问题),甚至应用截图都不能正常显示;而上传的接口,也有很多细节问题,比较离谱的是有几家居然不提示上传进度,整个上传过程中只能凭感觉,等待,刚好丁香园用药助手的软件包还比较大,有的时候遇到传输中断,简直令人抓狂。

界面信息混乱

第一次注册后提交软件的时候要把整个流程跑通还是比较难的,提示和术语都要理解半天才知道是怎么回事,文案差异性太大。登录到后台后,一个典型的情况是多数 Market 从后台找不到发布后的应用在前台的链接,比如应用汇。而有的 Market 更加离谱的是,后台还是传统的表格形式的展示,比如魅族。

数据不够准确

几乎所有的 Android 市场,统计信息都不是特别准确,有些甚至下载统计数天都不更新,有的甚至后台就不做数据统计,下载多少要前台页面自己去看。想得到靠谱的 Android 下载数据,哦,你实际上得不到靠谱的 Android 下载数据,如果想统计应用打开的数据,最好是早点启用类似友盟这样的应用统计服务。

流程足够复杂

流程复杂这个主要是针对联通、移动、联想这些富有官僚气息的 Market 来说的,比如用户资质信息最多的有上百条信息要填写,你就折腾吧,没有几个小时,没有公司上下配合(还要营业执照副本什么的)你根本搞不定,在你提交应用之前你准会崩溃。所以,有些时候,对这样的市场不得不放弃,即使有用户真的要从这些渠道下载你的应用,也没办法。

结束语

其实,倒也不只是国内的 Android 市场对开发者的用户体验差,Google 官方的菜市场也不咋地。每天在网上看到网友数落这个网站用户体验差,那个网站用户体验差什么的,其实如果你去用一下这些Android软件市场,就知道用户体验差其实是没有底线的。

前几天参加移动开发者大会,发现 App Market 俨然已是各大互联网公司的标配,都在纷纷的推出自己的 Market ,恐怕以后还会更乱。据悉,已经有创业团队在开发一次性提交到多个 Market 的工具了,不知道什么时候能看到。很明显,这也是吃力不讨好的事儿。

也可能是每家 Android Market 都在拼前台的用户体验呢吧,真心期待国内 Android Market 能早日关注一下针对开发者和维护者的用户体验问题,这也是每个 Android 开发者期待的,让开发者有更多精力做应该做的事情。

--EOF--

Instagram 架构分析笔记

| No Comments | No TrackBacks

转 http://www.dbanotes.net/arch/instagram.html

by Fenng@dbanotes.net

Instagram 团队上个月才迎来第 7 名员工,是的,7个人的团队。作为 iPhone 上最火爆的图片类工具,instagram 用户数量已经超过 1400 万,图片数量超过 1.5 亿张。不得不说,这真他妈是个业界奇迹。

几天前,只有三个人的 Instagram 工程师团队发布了一篇文章:What Powers Instagram: Hundreds of Instances, Dozens of Technologies,披露了 Instagram 架构的一些信息,足够勾起大多数人的好奇心。读罢做点笔记,各种线索还是有一定参考价值的。能打开原文的建议直接读原文。

Instragram.png

Instagram 开发团队奉行的三个核心原则:

  • Keep it very simple (极简主义)
  • Don't re-invent the wheel (不重复发明轮子)
  • Go with proven and solid technologies when you can(能用就用靠谱的技术)

OS/主机

操作系统的选择,在Amazon EC2上跑 Ubuntu Linux 11.04 (Natty Narwhal) ,这个版本经过验证在 EC2 上够稳定。因为只有三名工程师,只有三名工程师,所以自己部署机器到 IDC 是不靠谱的事情。幸好有亚马逊。

负载均衡

此前曾用过两台 Nginx 做 DNS 轮询承载前端请求,这样做会有副作用,现在已经迁移到Amazon的ELB(Elastic Load Balancer),起了三个 Nginx 实例,在 ELB 层停掉了 SSL , 以缓解 CPU 压力。DNS 服务使用 Amazon Route53 服务。

应用服务器

启用了 25 个 Django 实例,运行在 High-CPU Extra-Large 类型的服务器实例上,之所以用 High-CPU Extra-Large 实例是因为应用请求是 CPU 密集型而非 IO 密集型。

使用 Gunicorn 作为 WSGI 服务器。过去曾用过 Apache 下的 mod_wsgi 模块,不过发现 Gunicorn 更容易配置并且节省 CPU 资源。使用 Fabric 加速部署。

数据存储

用户信息、图片元数据、标签等大部分数据存储在 PostgreSQL 中。主要的 Shard 数据库集群有 12个节点。

实践中发现 Amazon 的网络磁盘系统单位时间内寻道能力不行,所以有必要将数据尽量放到内存中。创建了软 RAID 以提升 IO 能力,使用的 Mdadm 工具进行 RAID 管理。

管理内存中的数据,vmtouch 这个小工具值得推荐。

PostgreSQL 设置为 Master-Replica 方式,流复制模式。利用 EBS 的快照进行数据库备份。使用 XFS 文件系统,以便和快照服务充分配合。 使用 repmgr 这个小工具做 PostgreSQL 复制管理器器。

连接池管理,用了 PgbouncerChristophe Pettus 的文章包含了不少 PostgreSQL 数据库的信息。

TB 级别的海量图片存储在 Amazon S3 上,CDN 采用的也是 Amazon 的服务,CloudFront。

Instagram 也是 Redis 的重度用户,Feed 以及 Session 信息都用 Redis 处理,Redis 也是以 Master-Replica 方式部署。在 Replica 节点上进行数据备份。

使用了 Apache Solr 承担 Geo-search API 的工作,Solr 简单的 JSON 接口也不错。

缓存使用了 6 个 Memcached 实例,库使用 pylibmc 和 libmemcached。亚马逊也提供缓存服务-Elastic Cache service ,Instagram 也有尝试,不过不便宜。

任务队列/发布通知

队列服务使用 Gearman ,通知系统则使用 pyapns 来实现。

监控

前面提及的服务器实例数量加起来,的确有100多个,有效的监控是相当有必要的。使用 Munin 作为主要监控工具 , 也写了不少定制插件,外部监控用 Pingdom 的服务。通知服务使用 PagerDuty

对于 Python 的错误报告,使用 Disqus 团队开源的 Sentry 来处理。

几个感想

0)轻装上阵说起来容易,做起来非常难。这也是 Instagram 团队目前最令人着迷的地方;

1)Python 社区已经足够成熟,各个环节上都已经有不错的解决方案了。

2)如果要问我最大的一个感慨,我要说:Amazon 真是一家伟大的公司,甚至比 Google 还伟大

--EOF--


Enhanced by Zemanta

NSString 和hex code 互转

| No Comments | No TrackBacks

NSString *artist=@"王杰";

NSString *song=@"什么时候才能够";


转换后

Artist=8B737067&Title=C04E484EF66519504D62FD801F59

算法

-(NSString*)toUnichar:(NSString*)src

{

    NSMutableString *arX=[NSMutableString string];

    for (int i = 0 ; i<[src length]; i++) {

        unichar ch= [src characterAtIndex:i];

        unichar b = ((((unsigned long)(ch) & 0xff00) >> 8) | (((unsigned long)(ch) & 0x00ff) << 8));

        [arX appendFormat:@"%X",b];

    }

    return arX;

}

反转

NSString *str=@"32003000310032003C68B1838E7FF397504E27595659ED70E8954C6BF266A86350830A00ED70E8950F5CF48B92634C889C69"

2012格莱美音乐大奖热门歌曲推荐


算法

-(NSString*)toString:(NSString*)uniStr

{

    NSMutableString *outStr = [NSMutableString string];

    int len=[uniStr length]/4;

    unichar *oux=alloca(len*sizeof(unichar));

    unichar *p = oux;

   

    for (int i=0; i<[uniStr length]/4; i++) {

        

        NSString *str=[uniStr substringWithRange:NSMakeRange(i*4, 4)];

        

        unichar a =toInde([str characterAtIndex:0]);//3 3c

        unichar b =toInde([str characterAtIndex:1]);//2

        unichar c =toInde([str characterAtIndex:2]) ;//0 68

        unichar d =toInde([str characterAtIndex:3]);//0

        

        

        unichar x = c*16*16*16+d*16*16+ a*16+b;//十进制 3c68->683c

        

        memcpy(p, &x, 2);

        printf("%c,%x",*p,x);

        p++;

        

    }

    NSString *x=[[NSString alloc] initWithCharacters:oux length:len];

    

    return outStr;

}

int toInde(unichar x)

{

    int i;

    

    switch (x) {

        case 48:

            i=0;

            break;

        case 49:

            i=1;

            break;

        case 50:

            i=2;

            break;

        case 51:

            i=3;

            break;

        case 52:

            i=4;

            break;

        case 53:

            i=5;

            break;

        case 54:

            i=6;

            break;

        case 55:

            i=7;

            break;

        case 56:

            i=8;

            break;

        case 57:

            i=9;

            break;

        case 65:

            i=10;

            break;

        case 66:

            i=11;

            break;

        case 67:

            i=12;

            break;

        case 68:

            i=13;

            break;

        case 69:

            i=14;

            break;

        case 70:

            i=15;

            break;

        default:

            break;

    }

    return  i;

}



好久不写C,后面的的函数写的比较...

再奉送一个将NSString 转换成UTF8 str

-(NSString*)toUtf8Char:(NSString*)src

{

    

    NSMutableString *arX=[NSMutableString string];

    NSData *data=[src dataUsingEncoding:NSUTF8StringEncoding];

    const char *p= [data bytes];

    for (int i = 0 ; i<[data length]; i++) {

        Byte ch = *p;

        NSLog(@"%02X,%X",*p,ch);

        p++;


        [arX appendFormat:@"%X",ch];

    }

    return arX;

}

@"梁静茹丝路"转换后为

"E6A281 E99D99 E88CB9E4B89DE8B7AF"
顺便推荐一款内码查询器UnicodeChecker,官方网站 http://earthlingsoft.net
Enhanced by Zemanta