请选择 进入手机版 | 继续访问电脑版

默认
打赏 发表评论 9
移动端IM实践:Android版微信如何大幅提升交互性能(二)

本文由微信开发团队人员编写,转自 WeMobileDev,感谢。


前言


本文是Android版微信交互性能优化文章的第二篇(共二篇),接上篇:《移动端IM实践:Android版微信如何大幅提升交互性能(一)》,从如何优化SQLite读写性能着手,继续讲述提升用户交互性能。

发现问题


我们有自己的SQL性能数据上报系统,通过该系统,可以查看到外头用户SQL的执行耗时情况从上报的SQL性能统计系统来看,在会话内记录数较大情况下某些场景(进入会话,向上翻页,查看大图,删除历史消息等等)存在一定程度性能问题,见下图

原始SQL语句.jpg

上面“message"为我们微信用于存储消息的表名,“lasttime”则是对应SQL的平均执行耗时(单位毫秒),以"talker=?"打头作为where过滤条件的SQL是消息模块涉及的查询语句,从平均的执行耗时来看这些SQL应该存在一定的优化空间。

首先我们挑2条直接影响进入会话/会话内数据刷新速度的2条SQL语句进行explain query plan分析。

1. 计算会话内消息条数:
计算会话内消息条数.jpg

2. 查找会话内最近的18条消息并以时间升序方式排序:
最近的18条消息并以时间升序.jpg

先简要介绍一下explain query plan :没用过的同学可以直接看(http://www.sqlite.org/eqp.html),引用官方的一段话:

The EXPLAIN QUERY PLAN SQL command is used to obtain a high-level description of the strategy or plan that SQLite uses to implement a specific SQL query. Most significantly, EXPLAIN QUERY PLAN reports on the way in which the query uses database indices


简而言之,该指令是查看sqlite在执行SQL时候所采用的计划,例如,可以看到执行该SQL时候所采用的index(索引),并且可以看到执行该SQL过程前sqlite对整个查询所涉及的元数据条数的预估。

此前,通过该指令,我们很轻松解决了很多明显的SQL设计上的问题,但这次貌似该指令也无法让我们清晰定位到性能瓶颈, 从explain query plan 的结果来看,在进行上述2个查询时候,sqlite 已经采用了我们预期指定的索引,并且预估值约是10条左右。

OK,一切看起来很正常。那么,问题又出在哪里?针对该问题,在与ios相关同事交流过后,我们首先想到的是:拆表!

推测拆表之后的优势


数据内聚,减少I/O:

sqlite所有的表是通过B+树进行存储,当整个message表数据量较大的时候,因该表所在的B+树的深度较大,所有的查询或更新操作都会因此而多走很多的磁盘I/O流程。 而把message表按照talker(联系人)为单位分表,一个联系人一个表。则整个消息的存储就在物理空间上被分成了多个区间,同一个联系人的消息,在空间上被内聚到临近的磁盘块,这样的话,整个消息模块所在的B+树的深度就降低了,读取时候也会因磁盘的临近性(连续4k,磁盘一次读取最小的单位,大小根据不同磁盘的实际设定而定)而减少不少的磁盘I/O,上面的查询慢的问题也就解决了。(背景:关于B+树介绍,可见http://www.semaphorecorp.com/btp/algo.html

增加损坏后恢复数据成功机率:

用过sqlite的同学应该清楚,其存在不可避免的损坏机率,(关于损坏的介绍,建议直接看官方介绍 http://sqlite.org/howtocorrupt.html),我们此前对这种损坏的情况做了一套DB损坏后尝试恢复数据的方案,该方案从统计数据看恢复成功率在80%左右,而把消息分散到各个talker表,即便db损坏了,进行数据恢复的时候,恢复数据的成功率就会相应的比此前更高,因为损坏的范围缩小到以当前的talker为单位,与其他联系人的会话数据不会丢失。

事实并非如此


从上面2个分析的点来看,听上去很有道理,而且实际带来的优势也的确如此,但我们只看到了好的一面,还没有看到负面的影响,在经过一段时间的拆表改造之后,陆陆续续发现问题来了。

第一点:开发周期长,牵扯范围大

message是整个微信的主模块,各个子模块都或多或少与其有干系,不少模块直接把message的id当作自己模块主表的外键,还有直接以message的id值作为文件路径的,此外按照talker分表后,原来以非talker开头的多列索引全部被废掉,涉及到这些索引的一系列功能需要重新实现等等。。。简而言之,牵扯的范围非常广,且往后的数据迁移几乎成了不可能。

第二点:启动速度被拖垮,内存暴涨

这个点,也是我们真正放弃拆表的最主要的原因:在创建了一定数量的联系人会话,我们发现,启动速度越来越慢了,经过分析之后发现,在创建了2000个消息会话(也就是2000张表)之后,进程重启后首次调用sqlite db模块进行prepare SQL(sqlite在执行每条SQL前需要先将该SQL编译成用于查询引擎执行的字节码,该过程为prepare)耗时将近2s !

通过Android系统自带的traceview跟踪如图(2000个联系人会话):
traceview跟踪如图.jpg

拆表后启动时首次prepare SQL 占整个启动过程cpu开销的40%以上!这还仅仅是2000个联系人会话,随着会话数的增多,该值线性增大。

这个数据与ios同学的此前对ios版本db-init 耗时的统计一致,这里引用一下ios组提供的一组数据。
在iphone4 上面,在联系人会话数2k以内,启动时间达到2-5s:
ios组提供的数据.jpg

另外,对微信进程通过dumpsys meminfo 查看内存占用情况:拆表版本pss进程比单表版本高10mb!

拆表:
0 (5).jpeg

单表:
0 (6).jpeg

可以清晰的看到,拆表后Native Heap 比原来单表情况飙升10mb。这个sqlite 首次prepare SQL耗时如此之久,且暴涨的10mb内存,源自何处?能否进行优化?

首先我们尝试google,去查询这块资料,遗憾的是,我们并没有找到比较详细的这块的资料,带着问题,我们来到sqlite底层进行profile及debug调试分析。

通过Counters分析, sqlite db首次prepare SQL:
0 (7).jpeg

可见,实际耗时较大位置的在sqlite3Parser里面,分别为yy_reduce 及 sqlite3Malloc,其中yy_reduce为由文法自动生成解析器代码,sqlite3Malloc为对malloc的包装,用于底层分配内存。 通过调试源码发现,上面两步实际为对sqlite系统表"sqlite_master"内所有存储的"create"语句(包括create table,index 等)进行分词,解析等一系列操作,生成一个常驻的内存结构,见sqliteInt.h:
0 (8).jpeg

顾名思义,该结构体用于存放该db schema相关的一些信息,包括该db所有的表名,索引名,触发器名,正是有了这个结构体,sqlite prepare SQL时候才知道该怎么解释Tokenizer(分词器)传进来的一个个词,才有后面代码生成器对语法树进行字节码的生成。

也就说,这部分内存,对于后续所有SQL的编译都是必不可少的,这块想去掉除非不用VDBE引擎,否则只能按照它的规则。而加快其解析过程,我们目前也正在研究,尝试把schema对应的内存序列化到磁盘,在init时候直接从磁盘反序列化回来,倒也是种思路,但像sqlite 里面的struct,稍有研究的同学应该都知道,其每个struct内部,都包含了多个其他struct,并且不少通过链表,hash 表等的形式组织,故单纯一个schema,实际上里面包含的struct信息都是相当多的,并且要想完全把其序列化到磁盘,必须对其内部每个结构都相当了解才能做到,最少以我们目前对其的研究程度,还做不到这个事情。

所以,这里的耗时及内存占用,以我们目前的研究程度,还无法优化的,得到这个结论之后,我们放弃了拆表这个方案,并开始另觅性能可以达到或者接近拆表后的方案。

新的方案


饶了一圈,回到问题的起点,那就是为何上面的SQL从explain query plan 检测看到了实际已经采用了索引,看上去是没什么问题的,但最后在外面的用户上报的统计来看,会有不少超过1s乃至更高的耗时?

带着这个问题,继续挖深挖sqlite 整个查询过程到底都干了什么? 在对同一个会话制造了一定量的数据之后,使用counters分析其执行过程如下:
0 (9).jpeg

从图上可见,整个查询耗时最长的部分为sqliteVdbeExec 及 seekAndRead。sqliteVdbeExec为Vdbe引擎计算查询结果的执行函数,中间涉及较大量的计算,包括一系列的查找策略及对每条记录的解析,字节码执行等等 ,seekAndRead 则为查询过程所调用的I/O函数,性能直接取决于操作系统对应的磁盘速度:
0 (10).jpeg

从上面的trace分析中,可见要降低整个查询的耗时,有2个较大的瓶颈需要解决,一个是磁盘I/O的数量,另外一个引擎的计算量,而引擎的计算量经过实际测试其与查询过程所需的用到Page的数量是成线性正比关系的,也就是说,要降低整个查询时长,必须先想办法降低整个查询过程中需要用到的Page数量。

PAGE 数量降低分析

首先在了解清楚sqlite 查询前需要先了解清楚数据在sqlite 每个Page内部的存放情况,详细的可以到官方主页上看 ( https://www.sqlite.org/fileformat2.html),这里不细说,引入一个图,每个page头部的格式(8-12字节):
每个page头部的格式.jpg

这里只需要知道怎么区分每个Page类型就足够了,从上面的格式上看,我们可以看到,只需要通过页头首字节就能够区分出其page类型。 sqlite的Page通过页头首字节划分,有如下几种类型:对于索引页,内部页为 0X02,叶子页为0X0a ,对于表页,内部页为0X05 ,叶子页为0X0d。 在弄清楚每个page实际类型怎么区分之后,我们就可以在数据加载的关键地方加入信息跟踪整个查询涉及的page页面及其流向。

PAGE加载跟踪小工具-PageTracer

为了方便调试,我们单独写了一个小工具用于跟踪统计SQLite执行过程中Page的加载类型,累积个数及跳转流程等,名字叫" PageTracer",其原理是在对每个page加载的必经函数前后插入回调函数进行统计,在整个SQL执行完毕后输出该执行过程统计结果。

PageTracer工具入参为具体SQL,结果为对应page统计数量。 PageTracer 日志输出涵义:
  • PageCount :总Page数量
  • Table embedded : 表内部页数量 Table leaf:表叶子页数量
  • Index embedded :索引内部页数量 Index leaf :索引叶子页数量

对拆表与不拆表同一个talker 相同数据量情况下 Page 加载的类型及个数进行统计。

- 表前SQL:

> PageTrace "SELECT count(*) FROM message where talker = '3494847533@chatroom'"
result:all PageCount:1118 ,Table embedded :1,Table leaf :6,Index embedded:45 ,Index leaf :1066


- 拆表后SQL:

> PageTrace "SELECT count(*) FROM talker_3494847533@chatroom"  
result:all PageCount:414 ,Table embedded :1,Table leaf :6,Index embedded:8 ,Index leaf :329


从上述2组log一对比,我们可以很清晰的看到,真正差距就在索引页上,可见拆表前后上述2条SQL, 相差70%左右的索引页的加载。而经过时间打点看到,上述2组SQL查询时间差距也在70%左右,从这一角度来看,拆表的优势很明显。现在的问题就是为何2种实现sqlite对索引页加载的 Page 数量差这么大。

单条索引的构成

在经过对官网对索引格式介绍的了解及单条索引的debug跟踪后,总结出不拆表前索引条目内部元数据(不包含头部格式)构成如下图:
不拆表前索引条目.jpg

可见,在整条索引数据项里面,talker字段的长度占整条索引内部空间超过70%。到这里,先引入一下SQLite可变长整数的介绍:

可变长整数是SQLite的特色之一,使用它既可以处理大整数,又可以节省存储空间。由于单元中大量使用可变长整数。可变长整数由1~9个字节组成,每个字节的低7位有效,第8位是标志位。在组成可变长整数的各字节中,前面字节(整数的高位字节)的第8位置1,只有最低一个字节的第8位置0,表示整数结束。可变长整数可用于存储rowid、字段的字节数或Btree单元中的数据。


故实际每个byte能够表示的整数个数为128(因只有低7位可用)。

上图之所以描述rowid 占用长度为1-3byte, 实际原因为3个byte可以表示的整数个数为 128 * 128 * 128 ~= 209w 。 假设不拆表,则按照微信正常的使用情况,用户的聊天记录数在 200w 以内,则对rowid的存储,3个字节完全足够了,若聊天记录在 1.6w 以内,则需2个字节则可存储。

在拆表后,单条索引构成如下:
单条索引构成.jpg

可见,拆表后,真正产生优化的原因为头部talker字段的占用被去除,另外,因为message被拆分成多个talker表,故对于部分talker表,由于聊天记录总数变小,该talker表内条数只要小于1.6w,rowid就只占用2个字节以内, 这种情况下rowid会节省1个字节,但不是主要的优化因素,关键还是头部大小的节省。

至此,整个拆表带来的性能优势从存储的角度就已经很清晰的分析出来,整个优化效应链是:单条索引记录占用降低 —> 用于存储索引的Page数量降低 —> 用于查询加载的Page量降低 —> 整个查询时间降低

从上面对其优势分析清楚之后,我们考虑到,既然这里talker字段是大头,而sqlite 对整数的是可变长整数,也就说,我们通过以talker作为索引第一个字段,占据了整个索引条目空间的60-70%,而我们的talker在数据库是以用户username(字符串)来存储,对于群聊及大部分用户的username,这个字符个数都将近20-24个字符,而我们的索引组的后面几列字段都是整型存储,说也就是大部分情况我们的索引条目除去talker字段外的几个字段,均是1-3个字节的占用,也就说以一个page大小1024个字节算,光存储talker字段就占了将近600-700个字节。这样子的话,对索引空间的利用率是极低的。

实际情况中,对同一个用户,联系人会话实际情况基本不会超过1w个,也就是这1w个不同的联系人,我们如果用整型作为id存储的话,整数范围只是1-10000,按照前面的说法,在大多数情况下,2个字节已经完全足够了,原因前面可变长整数那里已经介绍了,2个字节实际能表示的整数个数为128 * 128 = 16384个数据,也就说对于1w个联系人的情况,索引头也仅仅需要2个字节而已。相对原来的20个字节,降低了90%的占用。

针对该情况,我们对原来的talker字段进行了一级映射,把原来的字符串形式映射成整型字段(1~10000内),并对该字段建立相应的索引,代替掉旧索引。在进行这一级的优化后,所有会话内对talker字段的查询,均在底层进行了一次转换,以新的整型id代替原来的字符串,单条索引的空间占用降低为原来的30%,优化后索引条目构成如下图:
优化后索引条目构成.jpg

这样的话,对索引进行查找的过程,就只需要原来的30%的page加载就可以完成。

- PageTrace一下看看结果:

> PageTrace "SELECT COUNT(*) FROM message where talkerid = 202"  
result:all PageCount:437 ,Table embedded :1, Table leaf :6,Index embedded:10 ,Index leaf :349


可见,虽然还没完全达到拆表后的性能,但整个查询过程中索引Page数量在总量上已经接近了,与拆表比,索引叶子Page多加载20个,内部Page多加载2个,综合内存及启动速度考虑,明显这个方案更优。

同理,通过PageTracer分析进入会话涉及的另外一条SQL我们也轻易发现问题。

- 查找会话最近18条消息:

此前SQL:

> PageTrace "SELECT * FROM message where talker = '3494847533@chatroom' order by createTime ASC limit -1 offset 30000"  
result:all PageCount:1382 ,Table embedded :11,Table leaf :213,Index embedded:10 ,Index leaf :349


优化后SQL:

> PageTrace "SELECT * FROM (SELECT * FROM message where  talker='3494847533@chatroom'order by createTime desc limit 18)order by createTime ASC"  
result:all PageCount:22 ,Table embedded :4,Table leaf :13,Index embedded:4 ,Index leaf :1   

优化后的性能测试


写操作测试结果(会话内30w条记录):
sql写操作性能.jpg

读操作测试结果(会话内30w条记录):
在会话内条数达到10w以上之后,进入会话及刷速度提升幅度超过70%。
sql读操作性能jpg.jpg

至此,整个优化流程就完毕了,整个优化到最后看起来结论很简单,但每一步的验证,背后都是大量的研究及论证的过程,分享此文出来,希望能减少大家在此走的弯路。

全站即时通讯技术资料分类


[1] 网络编程基础资料:
TCP/IP详解 - 第11章·UDP:用户数据报协议
TCP/IP详解 - 第17章·TCP:传输控制协议
TCP/IP详解 - 第18章·TCP连接的建立与终止
TCP/IP详解 - 第21章·TCP的超时与重传
理论经典:TCP协议的3次握手与4次挥手过程详解
理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程
计算机网络通讯协议关系图(中文珍藏版)
NAT详解:基本原理、穿越技术(P2P打洞)、端口老化等
UDP中一个包的大小最大能多大?
Java新一代网络编程模型AIO原理及Linux系统AIO介绍
NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战
NIO框架入门(四):Android与MINA2、Netty4的跨平台UDP双向通信实战
>> 更多同类文章 ……

[2] 有关IM/推送的通信格式、协议的选择:
为什么QQ用的是UDP协议而不是TCP协议?
移动端即时通讯协议选择:UDP还是TCP?
如何选择即时通讯应用的数据传输格式
强列建议将Protobuf作为你的即时通讯应用数据传输格式
移动端IM开发需要面对的技术问题(含通信协议选择)
简述移动端IM开发的那些坑:架构设计、通信协议和客户端
理论联系实际:一套典型的IM通信协议设计详解
58到家实时消息系统的协议设计等技术实践分享
>> 更多同类文章 ……

[3] 有关IM/推送的心跳保活处理:
Android进程保活详解:一篇文章解决你的所有疑问
Android端消息推送总结:实现原理、心跳保活、遇到的问题等
为何基于TCP协议的移动端IM仍然需要心跳保活机制?
微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)
微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)
移动端IM实践:实现Android版微信的智能心跳机制
移动端IM实践:WhatsApp、Line、微信的心跳策略分析
>> 更多同类文章 ……

[4] 有关WEB端即时通讯开发:
新手入门贴:史上最全Web端即时通讯技术原理详解
Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE
SSE技术详解:一种全新的HTML5服务器推送事件技术
Comet技术详解:基于HTTP长连接的Web端实时通信技术
WebSocket详解(一):初步认识WebSocket技术
socket.io实现消息推送的一点实践及思路
>> 更多同类文章 ……

[5] 有关IM架构设计:
浅谈IM系统的架构设计
简述移动端IM开发的那些坑:架构设计、通信协议和客户端
一套原创分布式即时通讯(IM)系统理论架构方案
从零到卓越:京东客服即时通讯系统的技术架构演进历程
蘑菇街即时通讯/IM服务器开发之架构选择
腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT
微信技术总监谈架构:微信之道——大道至简(演讲全文)
如何解读《微信技术总监谈架构:微信之道——大道至简》
快速裂变:见证微信强大后台架构从0到1的演进历程(一)
17年的实践:腾讯海量产品的技术方法论
>> 更多同类文章 ……

[6] 有关IM安全的文章:
即时通讯安全篇(一):正确地理解和使用Android端加密算法
即时通讯安全篇(二):探讨组合加密算法在IM中的应用
即时通讯安全篇(三):常用加解密算法与通讯安全讲解
即时通讯安全篇(四):实例分析Android中密钥硬编码的风险
传输层安全协议SSL/TLS的Java平台实现简介和Demo演示
理论联系实际:一套典型的IM通信协议设计详解(含安全层设计)
微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解
来自阿里OpenIM:打造安全可靠即时通讯服务的技术实践分享
>> 更多同类文章 ……

[7] 有关实时音视频开发:
即时通讯音视频开发(一):视频编解码之理论概述
即时通讯音视频开发(二):视频编解码之数字视频介绍
即时通讯音视频开发(三):视频编解码之编码基础
即时通讯音视频开发(四):视频编解码之预测技术介绍
即时通讯音视频开发(五):认识主流视频编码技术H.264
即时通讯音视频开发(六):如何开始音频编解码技术的学习
即时通讯音视频开发(七):音频基础及编码原理入门
即时通讯音视频开发(八):常见的实时语音通讯编码标准
即时通讯音视频开发(九):实时语音通讯的回音及回音消除概述
即时通讯音视频开发(十):实时语音通讯的回音消除技术详解
即时通讯音视频开发(十一):实时语音通讯丢包补偿技术详解
即时通讯音视频开发(十二):多人实时音视频聊天架构探讨
即时通讯音视频开发(十三):实时视频编码H.264的特点与优势
即时通讯音视频开发(十四):实时音视频数据传输协议介绍
即时通讯音视频开发(十五):聊聊P2P与实时音视频的应用情况
即时通讯音视频开发(十六):移动端实时音视频开发的几个建议
即时通讯音视频开发(十七):视频编码H.264、V8的前世今生
简述开源实时音视频技术WebRTC的优缺点
良心分享:WebRTC 零基础开发者教程(中文)
>> 更多同类文章 ……

[8] IM开发综合文章:
移动端IM开发需要面对的技术问题
开发IM是自己设计协议用字节流好还是字符流好?
请问有人知道语音留言聊天的主流实现方式吗?
IM系统中如何保证消息的可靠投递(即QoS机制)
谈谈移动端 IM 开发中登录请求的优化
完全自已开发的IM该如何设计“失败重试”机制?
微信对网络影响的技术试验及分析(论文全文)
即时通讯系统的原理、技术和应用(技术论文)
开源IM工程“蘑菇街TeamTalk”的现状:一场有始无终的开源秀
>> 更多同类文章 ……

[9] 开源移动端IM技术框架资料:
开源移动端IM技术框架MobileIMSDK:快速入门
开源移动端IM技术框架MobileIMSDK:常见问题解答
开源移动端IM技术框架MobileIMSDK:压力测试报告
开源移动端IM技术框架MobileIMSDK:Android版Demo使用帮助
开源移动端IM技术框架MobileIMSDK:Java版Demo使用帮助
开源移动端IM技术框架MobileIMSDK:iOS版Demo使用帮助
开源移动端IM技术框架MobileIMSDK:Android客户端开发指南
开源移动端IM技术框架MobileIMSDK:Java客户端开发指南
开源移动端IM技术框架MobileIMSDK:iOS客户端开发指南
开源移动端IM技术框架MobileIMSDK:Server端开发指南
>> 更多同类文章 ……

[10] 有关推送技术的文章:
iOS的推送服务APNs详解:设计思路、技术原理及缺陷等
Android端消息推送总结:实现原理、心跳保活、遇到的问题等
扫盲贴:认识MQTT通信协议
一个基于MQTT通信协议的完整Android推送Demo
求教android消息推送:GCM、XMPP、MQTT三种方案的优劣
移动端实时消息推送技术浅析
扫盲贴:浅谈iOS和Android后台实时消息推送的原理和区别
绝对干货:基于Netty实现海量接入的推送服务技术要点
移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)
为何微信、QQ这样的IM工具不使用GCM服务推送消息?
>> 更多同类文章 ……

[11] 更多即时通讯技术好文分类:
http://www.52im.net/forum.php?mod=collection&op=all

附录:有关QQ、微信的文章汇总


[1] 有关QQ、微信的技术文章:
微信后台团队:微信后台异步消息队列的优化升级实践分享
微信团队原创分享:微信客户端SQLite数据库损坏修复实践
腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率
腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(下篇)
腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(上篇)
微信Mars:微信内部正在使用的网络层封装库,即将开源
如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源
开源libco库:单机千万连接、支撑微信8亿用户的后台框架基石 [源码下载]
微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解
微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)
微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)
Android版微信从300KB到30MB的技术演进(PPT讲稿) [附件下载]
微信团队原创分享:Android版微信从300KB到30MB的技术演进
微信技术总监谈架构:微信之道——大道至简(演讲全文)
微信技术总监谈架构:微信之道——大道至简(PPT讲稿) [附件下载]
如何解读《微信技术总监谈架构:微信之道——大道至简》
微信海量用户背后的后台系统存储架构(视频+PPT) [附件下载]
微信异步化改造实践:8亿月活、单机千万连接背后的后台解决方案
微信朋友圈海量技术之道PPT [附件下载]
微信对网络影响的技术试验及分析(论文全文)
一份微信后台技术架构的总结性笔记
架构之道:3个程序员成就微信朋友圈日均10亿发布量[有视频]
快速裂变:见证微信强大后台架构从0到1的演进历程(一)
快速裂变:见证微信强大后台架构从0到1的演进历程(二)
微信团队原创分享:Android内存泄漏监控和优化技巧总结
全面总结iOS版微信升级iOS9遇到的各种“坑”
微信团队原创资源混淆工具:让你的APK立减1M
微信团队原创Android资源混淆工具:AndResGuard [有源码]
Android版微信安装包“减肥”实战记录
iOS版微信安装包“减肥”实战记录
移动端IM实践:iOS版微信界面卡顿监测方案
微信“红包照片”背后的技术难题
移动端IM实践:iOS版微信小视频功能技术方案实录
移动端IM实践:Android版微信如何大幅提升交互性能(一)
移动端IM实践:Android版微信如何大幅提升交互性能(二)
移动端IM实践:实现Android版微信的智能心跳机制
移动端IM实践:WhatsApp、Line、微信的心跳策略分析
移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)
移动端IM实践:iOS版微信的多设备字体适配方案探讨
>> 更多同类文章 ……

[2] 有关QQ、微信的技术故事:
技术往事:创业初期的腾讯——16年前的冬天,谁动了马化腾的代码
技术往事:史上最全QQ图标变迁过程,追寻IM巨人的演进历史
开发往事:深度讲述2010到2015,微信一路风雨的背后
开发往事:微信千年不变的那张闪屏图片的由来
开发往事:记录微信3.0版背后的故事(距微信1.0发布9个月时)
一个微信实习生自述:我眼中的微信开发团队
>> 更多同类文章 ……

即时通讯网 - 即时通讯开发者社区! 来源: - 即时通讯开发者社区!

上一篇:移动端IM实践:Android版微信如何大幅提升交互性能(一)下一篇:移动端IM实践:iOS版微信小视频功能技术方案实录

本帖已收录至以下技术专辑

推荐方案
评论 9
文章写的很有深度,大赞!
弱弱地问一句,文章里用到的调试工具叫啥名?
文章写的是很不错,微信团队技术人员确实能静下心把事做好
签名: 《同为IM社交产品中的王者,QQ与微信到底有什么区别》http://www.52im.net/thread-2235-1-1.html
引用:火影V我来了 发表于 2016-03-04 16:26
弱弱地问一句,文章里用到的调试工具叫啥名?

第一个工具目测是Navicat for MySQL,这工具这SQL查询客户端(当然mysql官方工具也挺好用),
用它来打开sqlite.db文件很方便,要在Andorid或iOS建本地库前,可以用这玩意先建库、测试查询语句等,测试ok后再放到android或ios代码里去建库就不会因为各种低级错误而费劲巴拉地去调试了。
签名: 《同为IM社交产品中的王者,QQ与微信到底有什么区别》http://www.52im.net/thread-2235-1-1.html
引用:火影V我来了 发表于 2016-03-04 16:26
弱弱地问一句,文章里用到的调试工具叫啥名?

第二个工具应该是android自带的profile工具,如果是用Eclipse+ADT的话,
直接点DDMS打开这个界面,就可以看到了。
android-ddms.png
签名: 《同为IM社交产品中的王者,QQ与微信到底有什么区别》http://www.52im.net/thread-2235-1-1.html
引用:火影V我来了 发表于 2016-03-04 16:26
弱弱地问一句,文章里用到的调试工具叫啥名?

第三个调试神器iOS开发的人应该比较熟,看那字体像是Mac OS X下的软件。

按照文章里说的,在网上很难查到Counters这个东西,其它那工具名确实不叫这个。
我打开XCode找了下,确实这个工具就是XCode的Profile工具——Instuments,很牛逼的调试工具,
有图有真相:
Instruments.png
签名: 《同为IM社交产品中的王者,QQ与微信到底有什么区别》http://www.52im.net/thread-2235-1-1.html
有关sqlite的性能调优化,非常好。

总结下来,微信的android端sqlite性能优化就是将之前的变长string主键改成为定长的int型,
进而带来了70%以上的性能提升,真是牛啊。
签名: 好想把妹!
学习了
写得很好,值得学习
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部