月度归档:2016年07月

CommandLine Parse Code Fragment

Command Line Parse Code Fragment

 

internal class CommandLine
    {
        /// <summary>
        /// get process command line info
        /// </summary>
        /// <param name="processId"></param>
        /// <returns>command line info, array length is 2, ex: ["C:\Windows\system32\svchost.exe","-k LocalService"]</returns>
        public static String[] GetCommandLineInfo(int processId)
        {
            String[] info = new string[2];
            info[0] = "";
            info[1] = "";
            //
            var commandLine = Wmi.GetCommandLine(processId);
            if (commandLine != "")
            {
                info = ParseCommandLine(commandLine);
            }
            return info;
        }

        /// <summary>
        /// get process command line info
        /// </summary>
        /// <param name="commandLine"></param>
        /// <returns>command line info, array length is 2, ex: ["C:\Windows\system32\svchost.exe","-k LocalService"]</returns>
        public static string[] ParseCommandLine(string commandLine)
        {
            string[] info = new String[2];

            //C:\Windows\system32\svchost.exe -k LocalService
            //"C:\Program Files (x86)\Avira\AntiVir Desktop\avgnt.exe" /min

            if (commandLine[0] == '"')
            {
                int end = commandLine.IndexOf('"', 1);
                if (end == -1)
                {
                    info[0] = commandLine;
                    info[1] = "";
                }
                else if (end + 1 < commandLine.Length)
                {
                    info[0] = commandLine.Substring(1, end + 1);
                    info[1] = commandLine.Substring(end + 1).TrimStart(' ');
                }
                else
                {
                    info[0] = commandLine;
                    info[1] = "";
                }
            }
            else
            {
                int pos = commandLine.IndexOf(' ');
                if (pos == -1)
                {
                    info[0] = commandLine;
                    info[1] = "";
                }
                else if (pos + 1 < commandLine.Length)
                {
                    info[0] = commandLine.Substring(0, pos);
                    info[1] = commandLine.Substring(pos + 1).TrimStart(' ');
                }
                else
                {
                    info[0] = commandLine;
                    info[1] = "";
                }
            }

            return info;
        }
    }

 

 

.

Quartz Misfire处理规则

调度(scheduleJob)或恢复调度(resumeTrigger,resumeJob)后不同的misfire对应的处理规则


CronTrigger

withMisfireHandlingInstructionDoNothing
——不触发立即执行
——等待下次Cron触发频率到达时刻开始按照Cron频率依次执行

withMisfireHandlingInstructionIgnoreMisfires
——以错过的第一个频率时间立刻开始执行
——重做错过的所有频率周期后
——当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行

withMisfireHandlingInstructionFireAndProceed
——以当前时间为触发频率立刻触发一次执行
——然后按照Cron频率依次执行


SimpleTrigger

withMisfireHandlingInstructionFireNow
——以当前时间为触发频率立即触发执行
——执行至FinalTIme的剩余周期次数
——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值

withMisfireHandlingInstructionIgnoreMisfires

——以错过的第一个频率时间立刻开始执行
——重做错过的所有频率周期
——当下一次触发频率发生时间大于当前时间以后,按照Interval的依次执行剩下的频率
——共执行RepeatCount+1次

withMisfireHandlingInstructionNextWithExistingCount
——不触发立即执行
——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
——以startTime为基准计算周期频率,并得到FinalTime
——即使中间出现pause,resume以后保持FinalTime时间不变

withMisfireHandlingInstructionNowWithExistingCount
——以当前时间为触发频率立即触发执行
——执行至FinalTIme的剩余周期次数
——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值

withMisfireHandlingInstructionNextWithRemainingCount
——不触发立即执行
——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
——以startTime为基准计算周期频率,并得到FinalTime
——即使中间出现pause,resume以后保持FinalTime时间不变

withMisfireHandlingInstructionNowWithRemainingCount
——以当前时间为触发频率立即触发执行
——执行至FinalTIme的剩余周期次数
——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到

——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值

MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
——此指令导致trigger忘记原始设置的starttime和repeat-count
——触发器的repeat-count将被设置为剩余的次数

——这样会导致后面无法获得原始设定的starttime和repeat-count值


Adf.Smtp

配置描述:

默认实例可通过Smtp.Config,  Global.Config, AppSetting 配置

优先级以 AppSetting->Global.Config->Smtp.Config

 

配置项:

 

SmtpEnabled:    是否启用 ,必需,值为 true/false

SmtpHost:    主机地址,例: smtp.mail.com,非必需

SmtpPort:    端口,非必需, 默认为 25

SmtpAccount:    在配置了SmtpHost时,登录主机的帐号,非必需

SmtpPassword:    在配置了SmtpHost时,登录主机的帐号,非必需

SmtpSender:    默认的邮件发送者地址,与SmtpSenderRandomDomain互斥,非必需

SmtpName:    默认的发送者显示名称,非必需

SmtpSSLEnabled:    是否启用SSL登录,默认false,非必需

SmtpSenderRandomDomain:    默认随机产生邮件发送地址的域名部份与SmtpSender互斥,非必需

 

注:以上SmtpSender / SmtpSenderRandomDomain必需配置或在应用程式中设置一个

 

配置示例:

Smtp.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <!-- 是否启用 -->
  <item name="SmtpEnabled" value="true"/>
  <!-- 发送主机 -->
  <item name="SmtpHost" value="smtp.mymail.com" />
  <!-- 发送端口 -->
  <item name="SmtpPort" value="25" />
  <!-- 登录主机的帐户 -->
  <item name="SmtpAccount" value="" />
  <!-- 登录主机的帐户名 -->
  <item name="SmtpPassword" value="" />
  <!-- 邮件默认发送者, 此配置与SmtpSenderRandomDomain互斥 -->
  <item name="SmtpSender" value="" />
  <!-- 邮件默认发送显示名 -->
  <item name="SmtpName" value="" />
  <!-- 是否启动SSL连接-->
  <item name="SmtpSSLEnabled" value="" />
  <!-- 默认邮件发送使用的随机发送地址域名部份,为空时不启用, 此配置与SmtpSender互斥 -->
  <item name="SmtpSenderRandomDomain" value="" />


</configuration>

 

 

 

 .

MySQL大数据场景的优化和运维之道

前言

MySQL数据库大家应该都很熟悉,而且随着前几年的阿里的去IOE,MySQL逐渐引起更多人的重视。

MySQL历史

  • 1979年,Monty Widenius写了最初的版本,96年发布1.0

  • 1995-2000年,MySQL AB成立,引入BDB

  • 2000年4月,集成MyISAM和replication

  • 2001年,Heikki Tuuri向MySQL建议集成InnoDB

  • 2003发布5.0,提供了视图、存储过程等功能

  • 2008年,MySQL AB被Sun收购,09年推出5.1

  • 2009年4月,Oracle收购Sun,2010年12月推出5.5

  • 2013年2月推出5.6 GA,5.7开发中

MySQL的优点

  • 使用简单

  • 开源免费

  • 扩展性“好”,在一定阶段扩展性好

  • 社区活跃

  • 性能可以满足互联网存储和性能需求,离不开硬件支持

上面这几个因素也是大多数公司选择考虑MySQL的原因。不过MySQL本身存在的问题和限制也很多,有些问题点也经常被其他数据库吐槽或鄙视

MySQL存在的问题

  • 优化器对复杂SQL支持不好

  • 对SQL标准支持不好

  • 大规模集群方案不成熟,主要指中间件

  • ID生成器,全局自增ID

  • 异步逻辑复制,数据安全性问题

  • Online DDL

  • HA方案不完善

  • 备份和恢复方案还是比较复杂,需要依赖外部组件

  • 展现给用户信息过少,排查问题困难

  • 众多分支,让人难以选择


到了刚才讲的MySQL的优势和劣势,可以看到MySQL面临的问题还是远大于它的优势的,很多问题也是我们实际需要在运维中优化解决的,这也是
MySQL
DBA的一方面价值所在。并且MySQL的不断发展也离不开社区支持,比如Google最早提交的半同步patch,后来也合并到官方主线。
Facebook Twitter等也都开源了内部使用MySQL分支版本,包含了他们内部使用的patch和特性。

数据库开发规范

数据库开发规范定义:开发规范是针对内部开发的一系列建议或规则, 由DBA制定(如果有DBA的话)。

开发规范本身也包含几部分:基本命名和约束规范,字段设计规范,索引规范,使用规范。

规范存在意义

  • 保证线上数据库schema规范

  • 减少出问题概率

  • 方便自动化管理

  • 规范需要长期坚持,对开发和DBA是一个双赢的事情

想想没有开发规范,有的开发写出各种全表扫描的SQL语句或者各种奇葩SQL语句,我们之前就看过开发写的SQL 可以打印出好几页纸。这种造成业务本身不稳定,也会让DBA天天忙于各种救火。

基本命名和约束规范

  • 表字符集选择UTF8 ,如果需要存储emoj表情,需要使用UTF8mb4(MySQL 5.5.3以后支持)

  • 存储引擎使用InnoDB

  • 变长字符串尽量使用varchar varbinary

  • 不在数据库中存储图片、文件等

  • 单表数据量控制在1亿以下

  • 库名、表名、字段名不使用保留字

  • 库名、表名、字段名、索引名使用小写字母,以下划线分割 ,需要见名知意

  • 库表名不要设计过长,尽可能用最少的字符表达出表的用途

字段规范

  • 所有字段均定义为NOT NULL ,除非你真的想存Null

  • 字段类型在满足需求条件下越小越好,使用UNSIGNED存储非负整数 ,实际使用时候存储负数场景不多

  • 使用TIMESTAMP存储时间

  • 使用varchar存储变长字符串 ,当然要注意varchar(M)里的M指的是字符数不是字节数;使用UNSIGNED INT存储IPv4 地址而不是CHAR(15) ,这种方式只能存储IPv4,存储不了IPv6

  • 使用DECIMAL存储精确浮点数,用float有的时候会有问题

  • 少用blob text

关于为什么定义不使用Null的原因

* 1.浪费存储空间,因为InnoDB需要有额外一个字节存储

* 2.表内默认值Null过多会影响优化器选择执行计划

关于使用datatime和timestamp,现在在5.6.4之后又有了变化,使用二者存储在存储空间上大差距越来越小 ,并且本身datatime存储范围就比timestamp大很多,timestamp只能存储到2038年

点击查看原图

索引规范

  • 单个索引字段数不超过5,单表索引数量不超过5,索引设计遵循B+ Tree索引最左前缀匹配原则

  • 选择区分度高的列作为索引

  • 建立的索引能覆盖80%主要的查询,不求全,解决问题的主要矛盾

  • DML和order by和group by字段要建立合适的索引

  • 避免索引的隐式转换

  • 避免冗余索引

关于索引规范,一定要记住索引这个东西是一把双刃剑,在加速读的同时也引入了很多额外的写入和锁,降低写入能力,这也是为什么要控制索引数原因。之前看到过不少人给表里每个字段都建了索引,其实对查询可能起不到什么作用。

冗余索引例子

  • idx_abc(a,b,c)

  • idx_a(a) 冗余

  • idx_ab(a,b) 冗余

隐式转换例子

字段:remark varchar(50) NOT Null

MySQL>SELECT id, gift_code FROM gift WHERE deal_id = 640 AND remark=115127; 1 row in set (0.14 sec)

MySQL>SELECT id, gift_code FROM pool_gift WHEREdeal_id = 640 AND remark=‘115127’; 1 row in set (0.005 sec)

字段定义为varchar,但传入的值是个int,就会导致全表扫描,要求程序端要做好类型检查

SQL类规范

  • 尽量不使用存储过程、触发器、函数等

  • 避免使用大表的JOIN,MySQL优化器对join优化策略过于简单

  • 避免在数据库中进行数学运算和其他大量计算任务

  • SQL合并,主要是指的DML时候多个value合并,减少和数据库交互

  • 合理的分页,尤其大分页

  • UPDATE、DELETE语句不使用LIMIT ,容易造成主从不一致

数据库运维规范

运维规范主要内容

  • SQL审核,DDL审核和操作时间,尤其是OnlineDDL

  • 高危操作检查,Drop前做好数据备份

  • 权限控制和审计

  • 日志分析,主要是指的MySQL慢日志和错误日志

  • 高可用方案

  • 数据备份方案

版本选择

  • MySQL社区版,用户群体最大

  • MySQL企业版,收费

  • Percona Server版,新特性多

  • MariaDB版,国内用户不多

建议选择优先级为:MySQL社区版 > Percona Server > MariaDB > MySQL 企业版

不过现在如果大家使用RDS服务,基本还以社区版为主

Online DDL问题

原生MySQL执行DDL时需要锁表,且锁表期间业务是无法写入数据的,对服务影响很大,MySQL对这方面的支持是比较差的。大表做DDL对DBA来说是很痛苦的,相信很多人经历过。如何做到Online DDL呢,是不是就无解了呢?当然不是!

点击查看原图

上面表格里提到的 Facebook OSC和5.6 OSC也是目前两种比较靠谱的方案

MySQL 5.6的OSC方案还是解决不了DDL的时候到从库延时的问题,所以现在建议使用Facebook OSC这种思路更优雅

下图是Facebook OSC的思路

点击查看原图

后来Percona公司根据Facebook OSC思路,用perl重写了一版,就是我们现在用得很多的pt-online-schema-change,软件本身非常成熟,支持目前主流版本。

使用pt-online-schema-change的优点有:

  • 1.无阻塞写入

  • 2.完善的条件检测和延时负载策略控制

值得一提的是,腾讯互娱的DBA在内部分支上也实现了Online DDL,之前测试过确实不错,速度快,原理是通过修改InnoDB存储格式来实现。

使用pt-online-schema-change的限制有:

  • 改表时间会比较长(相比直接alter table改表)

  • 修改的表需要有唯一键或主键

  • 在同一端口上的并发修改不能太多

可用性

关于可用性,我们今天分享一种无缝切主库方案,可以用于日常切换,使用思路也比较简单

在正常条件下如何无缝去做主库切换,核心思路是让新主库和从库停在相同位置,主要依赖slave start until 语句,结合双主结构,考虑自增问题。

点击查看原图

MySQL集群方案:

  • 集群方案主要是如何组织MySQL实例的方案

  • 主流方案核心依然采用的是MySQL原生的复制方案

  • 原生主从同步肯定存在着性能和安全性问题

MySQL半同步复制:

现在也有一些理论上可用性更高的其它方案

  • Percona XtraDB Cluster(没有足够的把控力度,不建议上)

  • MySQL Cluster(有官方支持,不过实际用的不多)

点击查看原图

红框内是目前大家使用比较多的部署结构和方案。当然异常层面的HA也有很多第三方工具支持,比如MHA、MMM等,推荐使用MHA

sharding拆分问题

  • Sharding is very complex, so itʼs best not to shard until itʼs obvious that you will actually need to!

  • sharding是按照一定规则数据重新分布的方式

  • 主要解决单机写入压力过大和容量问题

  • 主要有垂直拆分和水平拆分两种方式

  • 拆分要适度,切勿过度拆分

  • 有中间层控制拆分逻辑最好,否则拆分过细管理成本会很高

曾经管理的单表最大60亿+,单表数据文件大小1TB+,人有时候就要懒一些

点击查看原图

上图是水平拆分和垂直拆分的示意图

数据库备份

首先要保证的,最核心的是数据库数据安全性。数据安全都保障不了的情况下谈其他的指标(如性能等),其实意义就不大了。

备份的意义是什么呢?

  • 数据恢复!

  • 数据恢复!

  • 数据恢复!

目前备份方式的几个纬度:

  • 全量备份 VS 增量备份

  • 热备 VS 冷备

  • 物理备份 VS 逻辑备份

  • 延时备份

  • 全量binlog备份

建议方式:

  • 热备+物理备份

  • 核心业务:延时备份+逻辑备份

  • 全量binlog备份

借用一下某大型互联网公司做的备份系统数据:一年7000+次扩容,一年12+次数据恢复,日志量每天3TB,数据总量2PB,每天备份数据量百TB级,全年备份36万次,备份成功了99.9%。

主要做的几点:

  • 备份策略集中式调度管理

  • xtrabackup热备

  • 备份结果统计分析

  • 备份数据一致性校验

  • 采用分布式文件系统存储备份

备份系统采用分布式文件系统原因:

  • 解决存储分配的问题

  • 解决存储NFS备份效率低下问题

  • 存储集中式管理

  • 数据可靠性更好

使用分布式文件系统优化点:

* Pbzip压缩,降低多副本存储带来的存储成本,降低网络带宽消耗

* 元数据节点HA,提高备份集群的可用性

* erasure code方案调研

数据恢复方案


前的MySQL数据恢复方案主要还是基于备份来恢复,可见备份的重要性。比如我今天下午15点删除了线上一张表,该如何恢复呢?首先确认删除语句,然后用
备份扩容实例启动,假设备份时间点是凌晨3点,就还需要把凌晨3点到现在关于这个表的binlog导出来,然后应用到新扩容的实例上,确认好恢复的时间
点,然后把删除表的数据导出来应用到线上。

性能优化

复制优化

MySQL复制:

  • 是MySQL应用得最普遍的应用技术,扩展成本低

  • 逻辑复制

  • 单线程问题,从库延时问题

  • 可以做备份或读复制

问题很多,但是能解决基本问题

点击查看原图

上图是MySQL复制原理图,红框内就是MySQL一直被人诟病的单线程问题

单线程问题也是MySQL主从延时的一个重要原因,单线程解决方案:

  • 官方5.6+多线程方案

  • Tungsten为代表的第三方并行复制工具

  • sharding

点击查看原图

上图是MySQL5.6 目前实现的并行复制原理图,是基于库级别的复制,所以如果你只有一个库,使用这个意义不大

当然MySQL也认识到5.6这种并行的瓶颈所在,所以在5.7引入了另外一种并行复制方式,基于logical timestamp的并行复制,并行复制不再受限于库的个数,效率会大大提升

点击查看原图

上图是5.7的logical timestamp的复制原理图

刚才我也提到MySQL原来只支持异步复制,这种数据安全性是非常差的,所以后来引入了半同步复制,从5.5开始支持

点击查看原图

上图是原生异步复制和半同步复制的区别。可以看到半同步通过从库返回ACK这种方式确认从库收到数据,数据安全性大大提高

在5.7之后,半同步也可以配置你指定多个从库参与半同步复制,之前版本都是默认一个从库

对于半同步复制效率问题有一个小的优化,就是使用5.6+的mysqlbinlog以daemon方式作为从库,同步效率会好很多

关于更安全的复制,MySQL 5.7也是有方案的,方案名叫Group replication 官方多主方案,基于Corosync实现

点击查看原图

主从延时问题

原因:一般都会做读写分离,其实从库压力反而比主库大/从库读写压力大非常容易导致延时。

解决方案:

  • 首先定位延时瓶颈

  • 如果是IO压力,可以通过升级硬件解决,比如替换SSD等

  • 如果IO和CPU都不是瓶颈,非常有可能是SQL单线程问题,解决方案可以考虑刚才提到的并行复制方案

  • 如果还有问题,可以考虑sharding拆分方案

提到延时不得不提到很坑人的Seconds behind master,使用过MySQL的应该很熟悉

这个值的源码里算法

long time_diff= ((long)(time(0) – mi->rli.last_master_timestamp) – mi->clock_diff_with_master);

Secondsbehindmaster来判断延时不可靠,在网络抖动或者一些特殊参数配置情况下,会造成这个值是0但其实延时很大了。通过heartbeat表插入时间戳这种机制判断延时是更靠谱的

复制注意点:

  • Binlog格式,建议都采用row格式,数据一致性更好

  • Replication filter应用

主从数据一致性问题:

  • row格式下的数据恢复问题

InnoDB优化

成熟开源事务存储引擎,支持ACID,支持事务四个隔离级别,更好的数据安全性,高性能高并发,MVCC,细粒度锁,支持O_DIRECT。

主要优化参数:

  • innodbfileper_table =1

  • innodbbufferpool_size,根据数据量和内存合理设置

  • innodbflushlog_attrxcommit= 0 1 2

  • innodblogfile_size,可以设置大一些

  • innodbpagesize

  • Innodbflushmethod = o_direct

  • innodbundodirectory 放到高速设备(5.6+)

  • innodbbufferpool_dump

  • atshutdown ,bufferpool dump (5.6+)

    点击查看原图

 

上图是5.5 4G的redo log和5.6 设置大于4G redo log文件性能对比,可以看到稳定性更好了。innodblogfile_size设置还是很有意义的

InnoDB比较好的特性:

  • Bufferpool预热和动态调整大小,动态调整大小需要5.7支持

  • Page size自定义调整,适应目前硬件

  • InnoDB压缩,大大降低数据容量,一般可以压缩50%,节省存储空间和IO,用CPU换空间

  • Transportable tablespaces,迁移ibd文件,用于快速单表恢复

  • Memcached API,full text,GIS等

InnoDB在SSD上的优化:

  • 在5.5以上,提高innodbwriteiothreads和innodbreadiothreads

  • innodbiocapacity需要调大

  • 日志文件和redo放到机械硬盘,undo放到SSD,建议这样,但必要性不大

  • atomic write,不需要Double Write Buffer

  • InnoDB压缩

  • 单机多实例

也要搞清楚InnoDB哪些文件是顺序读写,哪些是随机读写

随机读写:

  • datadir

  • innodbdata file_path

  • innodbundo directory

顺序读写:

  • innodbloggrouphomedir

  • log-bin

InnoDB VS MyISAM:

  • 数据安全性至关重要,InnoDB完胜,曾经遇到过一次90G的MyISAM表repair,花了两天时间,如果在线上几乎不可忍受

  • 并发度高

  • MySQL 5.5默认引擎改为InnoDB,标志着MyISAM时代的落幕

TokuDB:

  • 支持事务 ACID 特性,支持多版本控制(MVCC)

  • 基于Fractal Tree Index,非常适合写入密集场景

  • 高压缩比,原生支持Online DDL

  • 主流分支都支持,收费转开源 。目前可以和InnoDB媲美的存储引擎

目前主流使用TokuDB主要是看中了它的高压缩比,Tokudb有三种压缩方式:quicklz、zlib、lzma,压缩比依次更高。现在很多使用zabbix的后端数据表都采用的TokuDB,写入性能好,压缩比高。

下图是我之前做的测试对比和InnoDB

点击查看原图

点击查看原图

上图是sysbench测试的和InnoDB性能对比图,可以看到TokuDB在测试过程中写入稳定性是非常好的。

tokudb存在的问题:

  • 官方分支还没很好的支持

  • 热备方案问题,目前只有企业版才有

  • 还是有bug的,版本更新比较快,不建议在核心业务上用

比如我们之前遇到过一个问题:TokuDB的内部状态显示上一次完成的checkpoint时间是“Jul 17 12:04:11 2014”,距离当时发现现在都快5个月了,结果堆积了大量redo log不能删除,后来只能重启实例,结果重启还花了七八个小时

MySQL优化相关的case

Query cache,MySQL内置的查询加速缓存,理念是好的,但设计不够合理,有点out。

锁的粒度非常大MySQL 5.6默认已经关闭

When the query cache helps, it can help a lot. When it hurts, it can hurt a lot.明显前半句已经没有太大用处,在高并发下非常容易遇到瓶颈。

关于事务隔离级别 ,InnoDB默认隔离级别是可重复读级别,当然InnoDB虽然是设置的可重复读,但是也是解决了幻读的,建议改成读已提交级别,可以满足大多数场景需求,有利于更高的并发,修改transaction-isolation。

点击查看原图

点击查看原图

上图是一个比较经典的死锁case,有兴趣可以测试下

关于SSD

关于SSD,还是提一下吧。某知名大V说过“最近10年对数据库性能影响最大的是闪存”,稳定性和性能可靠性已经得到大规模验证,多块SATA SSD做Raid5,推荐使用。采用PCIe SSD,主流云平台都提供SSD云硬盘支持。

最后说一下大家关注的单表60亿记录问题,表里数据也是线上比较核心的。

先说下当时情况,表结构比较简单,都是bigint这种整型,索引比较多,应该有2-3个,单表行数60亿+,单表容量1.2TB左右,当然内部肯定是有碎片的。

形成原因:历史遗留问题,按照我们前面讲的开发规范,这个应该早拆分了,当然不拆有几个原因:

  1. 性能未遇到瓶颈 ,主要原因

  2. DBA比较“懒“

  3. 想看看InnoDB的极限,挑战一下。不过风险也是很大的,想想如果在一个1.2TB表上加个字段加个索引,那感觉绝对酸爽。还有就是单表恢复的问题,恢复时间不可控。

我们后续做的优化 ,采用了刚才提到的TokuDB,单表容量在InnoDB下1TB+,使用Tokudb的lzma压缩到80GB,压缩效果非常好。这样也解决了单表过大恢复时间问题,也支持online DDL,基本达到我们预期。

今天讲的主要针对MySQL本身优化和规范性质的东西,还有一些比较好的运维经验,希望大家能有所收获。今天这些内容是为后续数据库做平台化的基础。我今天分享就到这里,谢谢大家。

QA

Q1:use schema;select * from table; 和select * from schema.table;两种写法有什么不一样吗?会对主从同步有影响吗?

对于主从复制来说执行效率上差别不大,不过在使用replication filter时候这种情况需要小心,应该要使用ReplicateWildIgnoreTable这种参数,如果不使用带wildignore,第一种方式会有问题,过滤不起作用。

Q2:对于用于MySQL的ssd,测试方式和ssd的参数配置方面,有没有好的建议?主要针对ssd的配置哈

关于SATA SSD配置参数,建议使用Raid5,想更保险使用Raid50,更土豪使用Raid 10

点击查看原图

上图是主要的参数优化,性能提升最大的是第一个修改调度算法的

Q3:数据库规范已制定好,如何保证开发人员必须按照规范来开发?

关于数据库规范实施问题,也是有两个方面吧,第一、定期给开发培训开发规范,让开发能更了解。第二、还是在流程上规范,比如把我们日常通用的建表和字段策略固化到程序,做成自动化审核系统。这两方面结合 效果会比较好。

Q4:如何最大限度提高innodb的命中率?

这个问题前提是你的数据要有热点,读写热点要有交集,否则命中率很难提高。在有热点的前提下,也要求你的你的内存要足够大,能够存更多的热点数据。尽量不要做一些可能污染bufferpool的操作,比如全表扫描这种。

Q5:主从复制的情况下,如果有CAS这样的需求,是不是只能强制连主库?因为有延迟的存在,如果读写不在一起的话,会有脏数据。

如果有CAS需求,确实还是直接读主库好一些,因为异步复制还是会有延迟的。只要SQL优化的比较好,读写都在主库也是没什么问题的。

Q6:关于开发规范,是否有必要买国标?

这个国标是什么东西,不太了解。不过从字面看,国标应该也是偏学术方面的,在具体工程实施时候未必能用好。

Q7:主从集群能不能再细化一点那?不知道这样问合适不?

看具体哪方面吧。主从集群每个小集群一般都是采用一主多从方式,每个小集群对应特定的一组业务。然后监控备份和HA都是在每个小集群实现。

Q8:如何跟踪数据库table某个字段值发生变化?

追踪字段值变化可以通过分析row格式binlog好一些。比如以前同事就是通过自己开发的工具来解析row格式binlog,跟踪数据行变化。

Q9:对超大表水平拆分,在使用MySQL中间件方面有什么建议和经验分享?

对于超大表水平拆分,在中间件上经验不是很多,早期人肉搞过几次。也使用过自己研发的数据库中间件,不过线上应用的规模不大。关于目前众多的开源中间件里,360的atlas是目前还不错的,他们公司内部应用的比较多。

Q10:我们用的MySQL proxy做读负载,但是少量数据压力下并没有负载,请问有这回事吗?

少量数据压力下,并没有负载 ,这个没测试过,不好评价

Q11:对于binlog格式,为什么只推荐row,而不用网上大部分文章推荐的Mix ?

这个主要是考虑数据复制的可靠性,row更好。mixed含义是指如果有一些容易导致主从不一致的SQL ,比如包含UUID函数的这种,转换为row。既然要革命,就搞的彻底一些。这种mix的中间状态最坑人了。

Q12: 读写分离,一般是在程序里做,还是用proxy ,用proxy的话一般用哪个?

这个还是独立写程序好一些,与程序解耦方便后期维护。proxy国内目前开源的比较多,选择也要慎重。

Q13: 我想问一下关于mysql线程池相关的问题,什么情况下适合使用线程池,相关的参数应该如何配置,老师有这方面的最佳实践没有?

线程池这个我也没测试过。从原理上来说,短链接更适合用线程池方式,减少建立连接的消耗。这个方面的最佳配置,我还没测试过,后面测试有进展可以再聊聊。

Q14: 误删数据这种,数据恢复流程是怎么样的(从库也被同步删除的情况)?


你删除数据的情况,如果只是一张表,单表在几GB或几十GB。如果能有延时备份,对于数据恢复速度是很有好处的。恢复流程可以参考我刚才分享的部分。目前
的MySQL数据恢复方案主要还是基于备份来恢复
,可见备份的重要性。比如我今天下午15点删除了线上一张表,该如何恢复呢。首先确认删除语句,然后用备份扩容实例启动,假设备份时间点是凌晨3点。就还
需要把凌晨3点到现在关于这个表的binlog导出来,然后应用到新扩容的实例上。确认好恢复的时间点,然后把删除表的数据导出来应用到线上。

Q15: 关于备份,binlog备份自然不用说了,物理备份有很多方式,有没有推荐的一种,逻辑备份在量大的时候恢复速度比较慢,一般用在什么场景?

物理备份采用xtrabackup热备方案比较好。逻辑备份一般用在单表恢复效果会非常好。比如你删了一个2G表,但你总数据量2T,用物理备份就会要慢了,逻辑备份就非常有用了

 

 

 

 

摘自:http://sanwen8.cn/p/10913Vm.html

.NET Core dotnet 命令大全

命令目录:

dotnet-new

dotnet-restore

dotnet-run

dotnet-build

dotnet-test

dotnet-pack

dotnet-publish

 

现在来详细讲解。

创建(dotnet new)

首先我们创建一个项目 ,这里我们创建控制台程序。

dotnet new

点击查看原图

 

dotnet 更多命令请参考帮助。

 

还原(dotnet restore 及 dotnet pack)

我们在创建一个 class lib  也就是类库。

dotnet new -t lib

点击查看原图

创建好以后,编写一些自己的代码然后进行打包。

点击查看原图

 

我编写了两个方法,现在来打包。

dotnet restore

dotnet pack

点击查看原图

.NET Core 怎样添加离线引用包呢?现在答案就揭晓了。

打包好以后,我们将applib 添加到 app的 project.json 。

点击查看原图

添加好以后切到app 目录,然后进行还原。

还原使用的命令是:dotnet restore -f E:\dotnet\applib\bin\Debug\

dotnet restore -f 包的路径

点击查看原图

这样我们就能直接在项目里调用applib 里面的方法。

我们在代码里编写对应的调用,然后执行程序。可以看到正确输出class lib 的结果。

点击查看原图

 

运行(dotnet build 及 dotnet run)

以app 为例:

dotnet build 编译代码

点击查看原图

 

dotnet run 执行程序

点击查看原图

 

dotnet xx.dll 也是执行程序

点击查看原图

 

测试(dotnet test)

这里我们要新建一个文件夹及项目了。

新建测试项目: dotnet new -t xunittest 

点击查看原图

 

新建好项目我们可以在里面添加测试方法,这里我直接运行测试。

dotnet restore

dotnet test

点击查看原图

 

发布(dotnet publish)

重点来了,发布项目使其可以跨平台运行。

dotnet publish 默认发布

点击查看原图

发布后定位到publish目录使用 dotnet xx.dll 执行应用。

 

下面来跨平台发布。

可以参考我之前的文章:http://www.cnblogs.com/linezero/p/5475246.html

在 project.json 加入 runtimes 节点 注释掉 "type": "platform"

点击查看原图

首先我们要dotnet restore

这里我还原的时候有些久,大家耐心等待一下。

dotnet publish -r win10-x64

点击查看原图

这里发布后,可以直接定位到发布publish目录,执行 app.exe 即可。 

dotnet publish -r ubuntu.14.04-x64

点击查看原图

将publish 文件夹上传至linux系统 ,设置app的权限为可执行,然后 ./app 就可以运行了。

dotnet publish -r 指定runtimes节点里系统ID

 

.

转自: http://www.cnblogs.com/linezero/p/dotnet.html

参考: https://docs.microsoft.com/en-us/dotnet/articles/core/tools/index

回车换行,CRLF

历史

回车”(Carriage Return)和“换行”(Line Feed)这两个概念的来历和区别。

符号        ASCII码        意义

\n               10          换行

\r                13            回车CR

在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33,Linux/Unix下的tty概念也来自于此)的玩意,每秒钟可以打10个字符。但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正 好可以打两个字符。要是在这0.2秒里面,又有新的字符传过来,那么这个字符将丢失。

于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做“回车”,告诉打字机把打印头定位在左边界;另一个叫做“换行”,告诉打字机把纸向下移一行。这就是“换行”和“回车”的来历,从它们的英语名字上也可以看出一二。

后来,计算机发明了,这两个概念也就被般到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是,就出现了分歧。

在Windows中:

'\r' 回车,回到当前行的行首,而不会换到下一行,如果接着输出的话,本行以前的内容会被逐一覆盖;

'\n' 换行,换到当前位置的下一行,而不会回到行首;

Unix系统里,每行结尾只有“<换行>”,即"\n";Windows系统里面,每行结尾是“<回车><换 行>”,即“\r\n”;Mac系统里,每行结尾是“<回车>”,即"\r";。一个直接后果是,Unix/Mac系统下的文件在 Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。

例:

$ echo -en '12\n34\r56\n\r78\r\n' > tmp.txt
点击查看原图
点击查看原图
分别在Windws和Linux中查看此文件可知:
Linux中遇到换行符("\n")会进行回车+换行的操作,回车符反而只会作为控制字符("^M")显示,不发生回车的操作。而windows中要回车符+换行符("\r\n")才会回车+换行,缺少一个控制符或者顺序不对都不能正确的另起一行。

P3P 简述

IE中   IFRAME,JSONP 跨域  COOKIE

P3P: CP=CAO PSA OUR

 

参考表:

浏览器 默认允许第三方Cookie 是否支持P3P 禁止第三方Cookie后,配置P3P简明策略头的效果 补充
IE6

HTTP可读写Cookie
JS可读Cookie
首次读到P3P头,JS无写Cookie权限.第二次才OK

(第二次.直接Cache.也不行.除非第一次非Cache并读到p3p头.后面我会提到解决方案.)

避免JS的写操作
IE7-IE9
HTTP、JS,可随意读写. -
FireFox HTTP、JS都不可读写 -
Chrome 部分支持,趋势-否 趋势为HTTP、JS可读不可写. -
Safari HTTP、JS可读不可写 借助Post提交表单,实现写操作.
Opera
JS可读写
HTTP可读不可写.
-


相关资源:   http://www.w3.org/2002/04/P3Pv1-header.html
 
Compact Policies(简洁策略)
 
简洁策略,本质上就是P3P策略的一个摘要. 他们的作用是,使用户代理,可以快速敏捷的获取到站点的P3P策略信息,所以是对性能有益的.
为了深入的解释简洁策略,按照 P3P1.0[4]规范,我们列出下面这些限制性的语法:

compact-policy-field         =   `CP="` compact-policy `"`

compact-policy                = compact-token *(" " compact-token)

compact-token                = compact-access           |
                                        compact-disputes         |
                                        compact-remedies         |
                                        compact-non-identifiable |
                                        compact-purpose          |
                                        compact-recipient        |
                                        compact-retention        |
                                        compact-categories       |
                                        compact-test

compact-access           = "NOI" | "ALL" | "CAO" | "IDC" | "OTI" | "NON"

compact-disputes            = "DSP"

compact-remedies          = "COR" | "MON" | "LAW"

compact-non-identifiable = "NID"

compact-purpose           = "CUR"        | "ADM" [creq] | "DEV" [creq] | "TAI" [creq] |
                                       "PSA" [creq] | "PSD" [creq] | "IVA" [creq] | "IVD" [creq] |
                                       "CON" [creq] | "HIS" [creq] | "TEL" [creq] | "OTP" [creq]

creq                              = "a" | "i" | "o"

compact-recipient       = "OUR" | "DEL" [creq] | "SAM" [creq] | "UNR" [creq] |
                                        "PUB" [creq] | "OTR" [creq]

compact-retention          = "NOR" | "STP" | "LEG" | "BUS" | "IND"

compact-category           = "PHY" | "ONL" | "UNI" | "PUR" | "FIN" | "COM" |

                                  "NAV" | "INT" | "DEM" | "CNT" | "STA" | "POL" |

                                        "HEA" | "PRE" | "LOC" | "GOV" | "OTC"

compact-test                  = "TST"
 

常用的简洁策略的 P3P头为 -   P3P : CP=CAO PSA OUR (其实, CP=. 就可以了.或者其他任何值都是可以的)分别对应了 :

compact-access(访问)    :  CAO -  contact-and-other
Identified Contact Information and Other Identified Data: access is given to identified online and physical contact information as well as to certain other identified data.
直译 : 被识别的联系信息,和其他被识别的数据: 网上,或现实中的联系信息,和某些被识别的数据,允许被访问.
我的理解: 应该是, 允许被确认的信息和数据的访问. (允许第三方cookie的读写)

compact-purpose(目的)  :  PSA -  pseudo-analysis .身份验证、分析
 

compact-recipient(受体) :  OUR - ours
Ourselves and/or entities acting as our agents or entities for whom we are acting as an agent: An agent in this instance is defined as a third party that processes data only on behalf of the service provider for the completion of the stated purposes. (e.g., the service provider and its printing bureau which prints address labels and does nothing further with the information
直译 :  我们自己,以及(或)实体作为我们自己的代理,或被我们所代理方的实体:这种情况下的代理,被定义为,相关进程数据,代表服务提供者,用来完成其所设定服务的,第三方.(就好像,一个印刷局作为提供打印服务的,服务提供者,其只负责打印标签神马的,但是却不会进一步,对相关的信息,做任何事情 )

 

备注:

. IE P3P简洁策略,可以最简写成: P3P:CP=. 

. IE6的实现有bug.需要注意.首次访问第三方页面,JS无法写入第三方Cookie的bug.建议尽量避免JS对Cookie的写操作.

. 对于第三方来说,建议避免使用JS操作Cookie,最多用来读,而不是写. 除非是和登录验证有关,否则建议使用Storage代替Cookie的使用.

 

参考:

1. http://p3ptoolbox.org/tools/ 
2. http://www.w3.org/P3P/implementations/
3. http://www.w3.org/P3P/
4. http://www.w3.org/TR/2002/REC-P3P-20020416/
5. https://www.w3.org/2002/04/P3Pv1-header.html

6.Validate at: http://www.w3.org/P3P/validator.html
7.Learn more at: http://www.fiddler2.com/redir/?id=p3pinfo
8. http://www.w3.org/P3P/details.html

C# 的一些发展轨迹

搞自 c# 7.0展望

 

C# 2.0 引入泛型。

C# 3.0 通过扩展方法、lambda表达式、匿名类型和其他相关特性带来了LINQ。

C# 4.0 都是关于与动态非强类型语言的互操作。

C# 5.0 简化异步编程和异步等待等关键词。

C# 6.0 完全重写,并且引入了各种各种更易实现的小特性和改进。你可以在DotNetCurry(DNC)杂志2016年1月版上找到一篇C#6.0特性的概述文章: U升级现有C#代码到 C# 6.0 。