zhaohui's 小站


  • Home

  • Tags

  • Categories

  • Archives

LeetCode_Solutions

Posted on 2017-03-09 | In 技术探索

以后代码都放这里了LeetCode_Solutions

MySQL学习

Posted on 2017-02-17 | In 技术探索

首先推荐三篇文章:
1.MySQL索引背后的数据结构及算法原理
总体概括了MySQL内部的索引原理及索引使用策略
2.剖析Mysql的InnoDB索引
侧重剖析了InnoDB的Page结构,更加详细的见Jeremy Cole的博客
3.Judy的B树
侧重数据结构的分析,注意只是数据结构。。
此外还有官方的InnoDB文档

总结重要的内容如下:
1. 使用B+的原因,相对于红黑树等二叉查找树,树的高度低,能减少IO次数。相对于B-树,稳定,更利于范围查询。相对于Hash表,更利于范围查询,伸缩性更好(在无法预知表中记录数时),详细见这里的讨论
2. InnoDB与MyISAM索引实现的区别,聚集索引和非聚集索引的区别
3. 建索引时的最左前缀原理,数据库表的主键选择
4. 慢查询日志及explain关键字

GitHub浅探

Posted on 2017-02-04 | In 技术探索

学习The-Art-Of-Programming-By-July,感觉写的不错,突然想看下github上比较流行的Repositories
可以在这里,对github上的资源进行自定义搜索,这里(貌似需要翻墙.手动汗..)也有比较新的总体的统计
截止当前,有以下结论:
1.star数大于10000的项目有354个, 其中JavaScript的项目占了127个。。
git1
2.按组织来查看,前16名如下:
git2
其中的第三四名。。我也不太懂。
取前16,只是因为第16名。。其他的有
git3
三大组织在排名上,还有一些分支,大家可以自行查看
个人分析:
一.JavaScript项目较多,可能因为
1.在web上,后端有多种语言实现,而前端的业务逻辑实现主要使用JavaScript
2.node及相关项目也被归到了JavaScript
3.前段JavaScript由浏览器执行,相对难以加密
4.JavaScript相对于后端代码库,更容易集成到项目中
二.国内公司的开源力度(技术水平?),相比国际顶尖公司,还是有些差距
三.教程类项目容易获得高star,比如free-programming-books,awesome,google-interview-university…内容也的确不错。。

"MySQL server has gone away"

Posted on 2017-01-19 | In 技术探索

一个很久没有运行的后台服务,在接收到数据,运行时,报了这个错误
原因是服务用的Django ORM与mysql在长久没有数据交互后,它们之间的长连接断掉了。

以下分析基于django1.6.0
Djando自带的ORM是比较定制化的,在django处理一个web请求时,在请求开始时,和请求处理完成时,Django都会尝试关闭数据库连接,如下代码所示:

1
2
3
4
5
6
7
8
9
10
11
12
# Register an event to reset transaction state and close connections past
# their lifetime. NB: abort() doesn't do anything outside of a transaction.
def close_old_connections(**kwargs):
for conn in connections.all():
# Remove this when the legacy transaction management goes away.
try:
conn.abort()
except DatabaseError:
pass
conn.close_if_unusable_or_obsolete()
signals.request_started.connect(close_old_connections)
signals.request_finished.connect(close_old_connections)

不过,根据close_if_unusable_or_obsolete的定义,除了自动提交和发生错误两种情况外,连接是否确定关闭,还取决于close_at的值,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def close_if_unusable_or_obsolete(self):
"""
Closes the current connection if unrecoverable errors have occurred,
or if it outlived its maximum age.
"""
if self.connection is not None:
# If the application didn't restore the original autocommit setting,
# don't take chances, drop the connection.
if self.get_autocommit() != self.settings_dict['AUTOCOMMIT']:
self.close()
return
if self.errors_occurred:
if self.is_usable():
self.errors_occurred = False
else:
self.close()
return
if self.close_at is not None and time.time() >= self.close_at:
self.close()
return

self.close_at会在连接时改变:

1
2
max_age = self.settings_dict['CONN_MAX_AGE']
self.close_at = None if max_age is None else time.time() + max_age

所以,具体到每个请求是否关闭连接,还取决于CONN_MAX_AGE的配置,而CONN_MAX_AGE的默认值是0,所以默认情况下,每次处理完毕web请求时,都会关闭数据库连接。
另外一个很重要的一点是,Django中,存储数据库连接的字典是基于线程的:

1
2
3
4
5
6
7
8
class ConnectionHandler(object):
def __init__(self, databases=None):
"""
databases is an optional dictionary of database definitions (structured
like settings.DATABASES).
"""
self._databases = databases
self._connections = local()

所以,如果你的web服务器的网络架构是多线程或者多进程的,即使设置CONN_MAX_AGE不为0,也不会复用旧的数据库连接,在这种情况下,如果数据库是mysql,因为Django orm不再会主动关闭数据库连接,mysql服务器会根据wait_timeout的设置,一直等待着,这种情况下,很有可能,造成mysql连接数过多,反而适得其反。
如果web服务器是单线程或者协程的,例如我测试用的gunicorn+gevents,适当的设置CONN_MAX_AGE,则会复用数据库连接,提升性能。

回到我们遇到的错误。。
我们的服务只用到了Django的ORM,所以在web请求开始和关闭时,django对数据库连接的尝试关闭对于我们的情况完全无效,服务又是一直跑着的单进程单线程,所以,在服务启动时,直到终止,会一直只用同一个数据库连接,长时间的服务不连接数据库,mysql会根据wait_timeout的设置,关闭了连接,所以也就导致了2006,’MySQL server has gone away’错误。
之前,使用tornado提供web服务,而使用Django的ORM时,也遇到过这样的错误,原理一样。
解决方法有:
1.增加mysql中wait_timeout的值,但这有一定的风险,而且不能从根本上解决问题。
2.同Django中的做法,在不需要数据库连接时或者开始数据库操作前,尝试关闭数据库连接。
3.自己DIY了一个变量CONN_WAIT_AGE,同时修改代码如下:
修改函数,增加:

1
2
self.conn_wait_age = settings_dict.get("CONN_WAIT_AGE", None)
self.last_access_at = time.time()

修改函数,增加:

1
self.last_access_at = time.time()

修改函数为:

1
2
3
4
5
6
7
8
9
10
def _cursor(self):
# add by zhaohui, in case, "2006, 'MySQL server has gone away'" error
if self.conn_wait_age is not None:
n = time.time()
if self.last_access_at + self.conn_wait_age < n and self.connection is not None and not self.is_usable():
self.close()
self.last_access_at = n
self.ensure_connection()
with self.wrap_database_errors:
return self.create_cursor()

CONN_WAIT_AGE需要设置为比wait_timeout小的值,不设置为不启用。

安装GitBook小记

Posted on 2017-01-19 | In 技术探索

看小程序文档时,发现文档是使用gitbook生成的,很喜欢这种风格的页面,于是尝试着在自己的服务器上也搭建一个。
从这里,首先在服务器上安装npm,使用命令yum install npm,能找到安装包,可是总在安装过程中被莫名杀死。
于是尝试着下载nodejs安装包,编译安装,同样报错被杀死
6然后尝试下载编译好的程序,解压时报错
5终于发现是服务器的内存问题。。
3可用内存不足100MB
然后发现
123个php-fpm进程占据了将近70%的内存。
我是使用的阿里云的云服务器,内存只买了1G的,包括这个wordpress博客,mysql数据库,一些自己弄着玩的程序都跑在这台服务器上。php-fpm使用的是默认的配置,结果造成内存使用率过高。
而实际上,我的博客的访问量并不算大(可以说很小。),于是,更改php-fpm配置,降低其工作进程数,重启后
2然后使用yum install npm,终于安装了npm..
接下来按部就班。。
请见第一个book

一个H5

Posted on 2017-01-11 | In 技术探索

请见:H5(非广告。。)

实现原理大致是控制多张图片的显示方式,如前三张图片是1,2,3,前一张图片的图像是后一张图片的图像的一部分(大小不同)。

实现并不复杂,但真的很有创意。

Web性能压力测试

Posted on 2017-01-11 | In 技术探索

用ApacheBench进行网站压力测试
原理:ab命令会创建很多的并发访问线程,模拟多个访问者同时对某一URL地址进行访问。
使用方式网上有很多,主要参数是-n(请求总数,设为参数n)和-c(并发数,创建的线程数, 设为参数c)
结果分析:
Concurrency Level: 即参数c
Time taken for tests: 整个测试持续的时间, 设为参数t
Total transferred: 整个测试过程网络数据传输量,设为b
Requests per second(mean): 即n/t
Time per request(mean): 即t/(n/c)
Time per request(mean, across all concurrent requests): 即t/n
Transfer rate: 即b/t
根据我的使用经验,需要注意的是:
1.这个只是服务器性能测试,并不能测试网络状况。也因此,测试机网络状况需要足够好,相对于服务器的带宽要足够高(大于Transfer rate)
2.因为是固定URL, 可能有时测试并不能反映实际情况
3.根据需求,可以做集群压测,或者是单机压测

从ftp服务器上下载文件或文件夹

Posted on 2016-12-14 | In 技术探索

`
def download_paths(ftp_object, path, destination):
“””
从ftp服务器上下载文件或文件夹
:param ftp_object: 一个已连接的ftplib.FTP对象
:param path: ftp上的路径
:param destination: 本地文件夹
“””
to_path = os.path.join(destination, os.path.basename(path))

file_list = ftp_object.nlst(path)
if len(file_list) == 1 and file_list[0] == path:  # 如果是文件
    ftp_object.retrbinary("RETR " + path, open(to_path, "wb").write)
elif len(file_list) > 0:
    if not os.path.exists(to_path):
        os.makedirs(to_path)
    for f in file_list:
        download_paths(ftp_object, f, to_path)

`

Django中的索引和约束

Posted on 2016-11-07 | In 技术探索

1.db_index控制单个field是否要创建索引
2.如果field是外键类型,则db_constraint控制是否有外键约束
3.如果是外键类型,默认会创建索引和约束
4.unique_together和index_together控制创建联合索引,在mysql中,联合索引中field的顺序会对部分查询产生影响

我对Web后台的一些看法

Posted on 2016-09-29 | In 技术探索

1. qps, 曾今分析过公司的Nginx日志,单台应用服务器的日访问量大约等于30000峰值qps,而我们web服务的单日访问最高达8亿,如此算来,我们web服务的峰值qps也有25000以上,当然,实际到达后端web应用的访问应该不到其1/4,这些访问又会分发到不同的服务器上。具体到每台服务器,假设每个请求耗费10msCPU时间,单台服务器是16核,完美情况下单台服务器能处理的最高qps也就是10016=1600。
2. 服务器抗压分析,首先当然是数据库,处理一个请求时,业务逻辑上的处理,可以通过增加服务器来解决,但是通常为了数据的一致性,数据都存在一个数据库中,高并发时,数据库的访问压力会比较大,解决方案通常是优化业务代码,减少数据库访问,对数据库建立适当的索引,数据库主从甚至多主,使用缓存。如果业务逻辑比较复杂,处理一个请求的时间相对较长,可以考虑使用消息队列,专门一组机器处理后台逻辑。如果后台处理时,IO操作比较多,后台web服务器的网络架构最好选择事件驱动模式或混合模式。根据业务,可以分组服务器。静态文件可以使用CDN等。
3. 页面加载速度,首先是从客户端发出请求,到收到所有数据,这个过程就像在客户端和服务器之间架有一条管道,首先一部分水从客户端流向服务器,之后服务器返回响应水流。管道的长度,BGP多线,CDN的存在,就是为了缩短管道的长度。从服务器端收到请求,到服务器开始返回响应,可尽量降低后台处理请求的时间(后端缓存,异步处理数据等)。服务器响应数据的大小,假设用户使用移动3G网络,网速为100KB/s,如果一个页面的数据(包括js,css,图片)是400KB(电脑版baidu首页的级别),只是下载数据就至少需要4s(排除客户端缓存)。前端优化可见这里。

123…5
zhaohui

zhaohui

和平,宁静,奋斗

45 posts
2 categories
45 tags
© 2017 zhaohui
Powered by Hexo
|
Theme — NexT.Muse v5.1.2