docker部署中遇到的mysql坑

前几天在用docker部署游戏服务器组,方便运维和开服合服操作,我自己制作的docker镜像包括 1) mysql镜像 2) redis镜像 3)认证服务器镜像 4) 网关服务器镜像 5) 游戏逻辑服务器镜像,镜像做完把它们部署到外网测试服务器(这里表达一下对docker开发人员的感谢, 真的是解放了我的双手,整个外网测试服务器组在几分钟内部署调试完毕,这在以前是不能想象的), 服务器部署完毕在使用过程中没有发现任何问题。过了几天因为有新的需求需要在本地调试服务器代码,以前我是直接在本机环境开n多进程调试的,其实写2个脚本脚本start server 和stop server也停放便的,由于前几天刚刚做完docker镜像,自己按耐不住对docker的冲动,啪啪啪,干脆直接在本地测试也用docker得了,好,说干就干,啪啪啪几个命令敲完,本地测试环境搭建完毕,开始进行开发了测试,现在问题来了,在开发调试阶段突然发现整个服务器组响应很慢很慢,这对于我这个性子比较急的coder来说当然是不能忍受的,开始啪啪啪查问题,首先要定位问题,刚开始我怀疑是服务部署的问题(经排查没有问题),然后又怀疑是网络环境的问题(经验证容器网络环境也没有任何问题)……..(中间省略n久的查错和排错过程), 最好通过开启游戏逻辑服务器的sql打印才发现是访问数据库慢,难道是数据库容器有问题,可是外网测试环境也是用的相同的容器呀!!!!!,真是日了狗了,后来在网上查到(一下引用自网络):

mysql优化之–skip-name-resolve

mysql优化之–skip-name-resolve

同一IDC ,IDC内部有DNS服务器,对各服务器的IP做了反向解析,
但未对内网IP做反向解析,所以使用skip-name-resolve以后用内网地址向mysqlslap请求响应快了一半

附录: 7.5.6. MySQL如何使用DNS

涉及参数 –skip-name-resolve ,–skip-host-cache ,–skip-networking

当新的客户连接mysqld时,mysqld创建一个新的线程来处理请求。该线程先检查是否主机名在主机名缓存中。如果不在,线程试图解析主机名:

·         如果操作系统支持线程安全gethostbyaddr_r ()和gethostbyname_r()调用,线程使用它们来执行主机名解析。

·         如果操作系统不支持线程安全调用,线程锁定一个互斥体并调用gethostbyaddr()和gethostbyname()。在这种情况下,在第1个线程解锁互斥体前,没有其它线程可以解析不在主机名缓存中的主机名。

你可以用–skip-name-resolve选项启动mysqld来禁用DNS主机名查找。然而,在这种情况下,你只可以使用MySQL中的授权表中的IP号。

如果你有一个很慢的DNS和许多主机,你可以通过用–skip-name-resolve禁用DNS查找或增加HOST_CACHE_SIZE定义(默认值:128)并重新编译mysqld来提高性能。

你可以用–skip-host-cache选项启动服务器来禁用主机名缓存。要想清除主机名缓存,执行FLUSH HOSTS语句或执行mysqladmin flush-hosts命令。

如果你想要完全禁止TCP/IP连接,用–skip-networking选项启动mysqld。

附录.抓包数据 待补全

连接mysql时,都会向DNS做反向地址查询
只有等超时失败后,mysql才会响应客户端
等待解析的mysql进程都是 login状态

访问mysql之所以会慢是因为mysql服务器反向地址查询,docker容器启动的时候如果本机没有配置nameserver 那么默认会用 8.8.8.8 和8.8.4.4这两个域名解析服务器相信大家一看就知道问题了吧。

接觉得办法是在运行docker的时候加–dns 127.0.1.1(这里代表自己指定的dns server)。

sudo docker run -p 3308:3306 –dns 10.202.72.118 –dns 10.202.72.116 -d centos_mysql:1.0.0 sh /root/run.sh

架构师的职责(写的挺好的)

0、前言

架构师是一个没有被严格定义的角色。

在写这篇文章之前,我特意把这几年看过的关于架构和架构师的 书重新翻了一遍,结果发现它们的定义或多或少有一些不一样,而经过了这几年,一些之前同意的观点,现在的我也不敢苟同了。另一方面,业界对于架构师这个岗 位,其实也没有统一的角色定位。在阿里巴巴,前几年是有专职的“架构师”职位的,现在已经回归到“工程师”、“专家”、“研究员”这样的纯技术职位。而我 面试过的人中,也有各种各样的“架构师”,很多小团队里,项目经理就经常自认为架构师。大概架构师目前还不至于称为一个职业,更多的是在项目中的一个角 色,而其角色定位也是模糊的,因此,这个文章里,我主要还是从自己的理解出发,阐述一下这个角色的定位和个人发展的建议。
1、架构师的定义

架构师:任何复杂结构的设计人员。

架构师的名字来自于建筑业,Software Architect直译应该叫“软件建筑师”。从很多方面讲,软件架构师的工作跟建筑师很像,为了寻根问祖,曾经我也看了不少建筑设计的书(推荐一本《建筑的永恒之道》),最后我发现,两者一脉相承,现阶段分道扬镳,未来也许殊途同归。

一脉相承——不管是建筑师还是软件架构师,都是为了“大图”而存在,做好顶层设计,充当需求方和实施者的桥梁,是其最重要的两个职责。

分道扬镳——两者的发展 阶段不同所致。建筑业实践绵延数千年,理论根基有数百年,真正成为一门学科也有一百多年,而软件架构真正出现不过二十年。建筑业已经在足够高的层面上模式 化,建筑师能够真正去“设计”,也就是决定“做什么”。而软件行业还在高速发展中,各个层面的技术还在百花齐放。技术的选择意味着权衡,因此软件架构师更 多还在关注“怎么做”——这也是建筑师可以称设计师,而软件架构师只能算高阶工程师的原因,设计师更关注美感,而美感在软件架构师的考虑优先级里,排不上 第一。

殊途同归——计算机发展 的几十年,也是技术不断往上抽象和模式化的几十年。SOA、IoT、IFTTT等技术理念已经接近于建筑行业的模块化级别,各种“智慧城市”、“生态城 市”已经在架构层面上考虑“做什么”。假以时日,架构师也许能成为一个真正的纯“设计”的职业,到时候大学里也可以开设“软件架构”的专业了,那一句“建 筑设计师在成为建筑设计师之前,是不会成为建筑工人或工程师的“也能在软件行业成为现实。

当然,这只是可能的未来,这需要我们这些前辈技术人员,能够和建筑行业的前辈一样,把技术规范化,设计模式化,还要有一套关于架构美学和功能设计的完整统一的约束,任重而道远。
2、架构的职责

在软件技术发展的前几十年,是没有架构师这个称谓的。所有的 人都是程序员,可能有个带头的人,叫主程序员。随着计算机技术的发展,软件覆盖的领域越来越大,软件本身也越来越复杂,现在,动辄几百万行、几千万行代码 的软件系统已经非常普遍。软件的复杂化,对于开发人员的脑力负担也不断增大,而人脑所能处理的信息量是有限的,于是,软件开发工具、开发方法也在不断发 展,从汇编语言到高级语言,从函数到框架,从面向过程到面向对象,从设计模式到架构模式……

总体而言,人类在软件开发工具的各个维度上都在做着“封装” 和“抽象”,架构设计是这种抽象和封装的最高层次。从架构的维度上,已经不需要考虑语言、函数、设计模式这一类的抽象,而是站在整体软件系统的高度上,考 虑系统设计的技术合理性,需求实现的完整性,商业诉求的匹配度(主要是成本和效率)——这是架构的技术职责。

另一方面,随着行业的发展,软件项目的参与角色和人员也越来 越多,从起初只有程序员和需求方,发展到技术、产品、设计、商务、项目管理多团队,技术团队内部的分工也越来越细化,前端、后端、测试、运维、售前售后技 术、集成技术等应运而生。架构师是技术团队面向产品设计等团队的接口人,承担着弥合技术与非技术团队之间知识和语言体系差异的职责,同时作为技术团队的带 头人,要负责勾勒蓝图,明确边界,让不同技能的团队通力协作,最终完成软件系统的整体建设和发布——这是架构的组织职责。
2.1、架构的技术职责

首先,架构师经常被类比于建筑师,但是有两个建筑领域的基础理念,在软件架构领域是不成立的(至少现阶段不成立):

建筑设计师在成为建筑设计师之前,是不会成为建筑工人或工程师的。——现阶段的软件架构师,一定是从软件工程师成长起来的。

建筑学和工程学之间的区别表现在“做什么”和“怎么做”:建筑师决定做什么,工程师想出怎么做。——现阶段的软件架构师,除了决定做什么,也要决定关键部分怎么做。

架构的技术职责分为三大块:

抽象设计;
非功能设计;
关键技术设计。

首先是抽象设计。架构师需要能自由地在不同的抽象层次和视角上分析需求,不同的架构层次/视角提供了不同的视图,这些视图互相验证,又能构成整体的设计大图。架构的抽象层次分成两个维度:

垂直维度

从上到下,分成企业架构、解决方案架构、应用架构、系统架构 等,这个分层的逻辑,是提供不同颗粒度的业务建模。CTO关注企业架构,它提现了一个企业整体的IT技术建设的战略选择,典

型的就是集中式和SOA、大型 机和云计算的选择等;产品经理和运维关注应用架构,这里映射了产品的业务流程和应用的整体部署依赖;外部客户关注解决方案架构,它定义了如何通过产品的整 合和协同,解决特定客户的特定的技术方案需求;研发工程师关注系统架构,这里定义了单个系统的领域建模和系统框架。

水平维度

具体到对某一个业务的架构设计,又可以区分出业务架构、数据 架构、技术架构、应用架构几个不同的视角。业务架构是对业务领域和业务流程的分析抽象,需要提炼出业务的核心领域模型,业务的可变和不变部分,这是架构师 和产品经理协同完成的;数据架构基于业务架构提炼的核心领域模型做数据模型和存储模型的设计;技术架构基于业务的性能,可用性,安全等非功能性指标,确定 语言、框架、中间件、部署等技术选型;应用架构基于业务抽象设计应用系统的层次结构、系统边界等。

在这些架构划分中,企业架构匹配商业模式,业务架构匹配业务模式,其他几个架构的划分,更多的是从技术的不同视角来看,他们提供了从不同的抽象层次,不同的切面对于功能需求的分析和建模。

同时需要说明的是,架构的抽象是匹配于业务的,就像桥梁设计师不能直接转做摩天大楼设计,架构抽象也是区分领域的,每一个业务领域都有自己的独特性,因此在架构上也是千人千面的,好的架构设计也是对于业务抽象得最好的设计。

架构师的另一个技术职责,是对非功能需求的分析。这 也是“架构服务于功能,高于功能”的含义。这里的非功能性需求包括了软件系统的可靠性、扩展性、可测性、数据一致性、安全和性能等。考虑到成本和运行环境 等限制,这些非功能性需求很多时候是不能同时满足的。这个时候就需要“权衡”

转自: http://my.oschina.net/u/1589651/blog/676078

geohash:用字符串实现附近地点搜索

geohash是一种地址编码,它能把二维的经纬度编码成一维的字符串。比如,北海公园的编码是wx4g0ec1。

geohash有以下几个特点:

首先,geohash用一个字符串表示经度和纬度两个坐标。某些情况下无法在两列上同时应用索引(例如MySQL 4之前的版本,Google App Engine的数据层等),利用geohash,只需在一列上应用索引即可。

其次,geohash表示的并不是一个点,而是一个矩形区域。比如编码wx4g0ec19,它表示的是一个矩形区域。使用者可以发布地址编码,既能表明自己位于北海公园附近,又不至于暴露自己的精确坐标,有助于隐私保护。

第三,编码的前缀可以表示更大的区域。例如wx4g0ec1,它的前缀wx4g0e表示包含编码wx4g0ec1在内的更大范围。这个特性可以用于附近地点搜索。首先根据用户当前坐标计算geohash(例如wx4g0ec1)然后取其前缀进行查询(SELECT * FROM place WHERE geohash LIKE ‘wx4g0e%’),即可查询附近的所有地点。

geohash的算法

下面以(39.92324, 116.3906)为例,介绍一下geohash的编码算法。首先将纬度范围(-90, 90)平分成两个区间(-90, 0)、(0, 90),如果目标纬度位于前一个区间,则编码为0,否则编码为1。由于39.92324属于(0, 90),所以取编码为1。然后再将(0, 90)分成 (0, 45), (45, 90)两个区间,而39.92324位于(0, 45),所以编码为0。以此类推,直到精度符合要求为止,得到纬度编码为1011 1000 1100 0111 1001。

纬度范围 划分区间0 划分区间1 39.92324所属区间
(-90, 90) (-90, 0.0) (0.0, 90) 1
(0.0, 90) (0.0, 45.0) (45.0, 90) 0
(0.0, 45.0) (0.0, 22.5) (22.5, 45.0) 1
(22.5, 45.0) (22.5, 33.75) (33.75, 45.0) 1
(33.75, 45.0) (33.75, 39.375) (39.375, 45.0) 1
(39.375, 45.0) (39.375, 42.1875) (42.1875, 45.0) 0
(39.375, 42.1875) (39.375, 40.7812) (40.7812, 42.1875) 0
(39.375, 40.7812) (39.375, 40.0781) (40.0781, 40.7812) 0
(39.375, 40.0781) (39.375, 39.7265) (39.7265, 40.0781) 1
(39.7265, 40.0781) (39.7265, 39.9023) (39.9023, 40.0781) 1
(39.9023, 40.0781) (39.9023, 39.9902) (39.9902, 40.0781) 0
(39.9023, 39.9902) (39.9023, 39.9462) (39.9462, 39.9902) 0
(39.9023, 39.9462) (39.9023, 39.9243) (39.9243, 39.9462) 0
(39.9023, 39.9243) (39.9023, 39.9133) (39.9133, 39.9243) 1
(39.9133, 39.9243) (39.9133, 39.9188) (39.9188, 39.9243) 1
(39.9188, 39.9243) (39.9188, 39.9215) (39.9215, 39.9243) 1

经度也用同样的算法,对(-180, 180)依次细分,得到116.3906的编码为1101 0010 1100 0100 0100。

经度范围 划分区间0 划分区间1 116.3906所属区间
(-180, 180) (-180, 0.0) (0.0, 180) 1
(0.0, 180) (0.0, 90.0) (90.0, 180) 1
(90.0, 180) (90.0, 135.0) (135.0, 180) 0
(90.0, 135.0) (90.0, 112.5) (112.5, 135.0) 1
(112.5, 135.0) (112.5, 123.75) (123.75, 135.0) 0
(112.5, 123.75) (112.5, 118.125) (118.125, 123.75) 0
(112.5, 118.125) (112.5, 115.312) (115.312, 118.125) 1
(115.312, 118.125) (115.312, 116.718) (116.718, 118.125) 0
(115.312, 116.718) (115.312, 116.015) (116.015, 116.718) 1
(116.015, 116.718) (116.015, 116.367) (116.367, 116.718) 1
(116.367, 116.718) (116.367, 116.542) (116.542, 116.718) 0
(116.367, 116.542) (116.367, 116.455) (116.455, 116.542) 0
(116.367, 116.455) (116.367, 116.411) (116.411, 116.455) 0
(116.367, 116.411) (116.367, 116.389) (116.389, 116.411) 1
(116.389, 116.411) (116.389, 116.400) (116.400, 116.411) 0
(116.389, 116.400) (116.389, 116.394) (116.394, 116.400) 0

接下来将经度和纬度的编码合并,奇数位是纬度,偶数位是经度,得到编码 11100 11101 00100 01111 00000 01101 01011 00001。

最后,用0-9、b-z(去掉a, i, l, o)这32个字母进行base32编码,得到(39.92324, 116.3906)的编码为wx4g0ec1。

十进制 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
base32 0 1 2 3 4 5 6 7 8 9 b c d e f g
十进制 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
base32 h j k m n p q r s t u v w x y z

解码算法与编码算法相反,先进行base32解码,然后分离出经纬度,最后根据二进制编码对经纬度范围进行细分即可,这里不再赘述。不过由于geohash表示的是区间,编码越长越精确,但不可能解码出完全一致的地址。

geohash的应用:附近地址搜索

geohash的最大用途就是附近地址搜索了。不过,从geohash的编码算法中可以看出它的一个缺点:位于格子边界两侧的两点,虽然十分接近,但编码会完全不同。实际应用中,可以同时搜索当前格子周围的8个格子,即可解决这个问题。

以geohash的python库为例,相关的geohash操作如下:

>>> import geohash
>>> geohash.encode(39.92324, 116.3906, 5)  # 编码,5表示编码长度
'wx4g0'
>>> geohash.expand('wx4g0')                # 求wx4g0格子及周围8个格子的编码
['wx4ep', 'wx4g1', 'wx4er', 'wx4g2', 'wx4g3', 'wx4dz', 'wx4fb', 'wx4fc', 'wx4g0']

最后,我们来看看本文开头提出的两个问题:速度慢,缓存命中率低。使用geohash查询附近地点,用的是字符串前缀匹配:

SELECT * FROM place WHERE geohash LIKE 'wx4g0%';

而前缀匹配可以利用geohash列上的索引,因此查询速度不会太慢。另外,即使用户坐标发生微小的变化,也能编码成相同的geohash,这就保证了每次执行相同的SQL语句,使得缓存命中率大大提高。

注: 利用geohash将二维的经纬度编码成以为的字符串,将编码后的字符串取前缀存入数据库,利用数据库索引查询实现附近搜索, 有一个为题就是没有办法精确到具体的范围搜索, 如果需要精确的范围搜索,可以考虑pg和redis(3.2+支持geo)

参考:http://blog.jobbole.com/80633/