GitHub’s online schema migration for MySQL

项目地址:gh-ost

1.简介

  • gh-ost是一个无触发器的MySQL schema在线迁移解决方案。它是可测试的,并提供了可用性、动态控制/重新配置、审计和许多操作功能。
  • 在整个迁移过程中,gh-ost在主库上产生的工作负载较轻,与迁移表上的现有工作负载解耦。
  • 它是根据多年使用现有解决方案的经验设计的,并更改了表迁移的范例。

2.为什么不用触发器 ?

  • 已存在的工具有:

    • pt-osc
    • Facebook OSC
    • LHM
    • oak-online-alter-table
  • 它们都使用触发器将表上的活动,传输更新到正在缓慢同步的鬼/影表。这些工具的工作方式不尽相同:大多数工具使用同步方法(应用于ghost表的所有更改),而Facebook工具使用异步方法(将更改追加到更改日志表,稍后将审查并应用于ghost表)。
  • 触发器的使用简化了动态表迁移中的许多流程,但也带来了一些限制或困难。以下是我们选择为模式迁移设计无触发解决方案design a triggerless solution的原因。

3.命名由来

  • 最初它被命名为gh-osc: GitHub Online Schema Change,类似于Facebook online schema change和pt-online-schema-change。

    但后来发生了一种罕见的基因突变,c变成了t。这让我们走上了寻找一个新的缩略词的道路。gh-ost(发音:Ghost),代表GitHub的在线模式转换器/变形器。

4.亮点

  • 通过在从库上测试gh-ost来建立您对它的信任。gh-ost将发出与主表相同的流,迁移复制表上的表,而不实际替换原始表,将复制表保留为两个表,然后您可以比较并确信该工具操作正确。这就是我们在生产中不断测试gh-ost的方法。
  • 真正的暂停:当gh-ost停止throttles时,它真正停止对master上的写:没有行复制,也没有正在进行的事件处理。通过节流,可以将主服务器返回到其原始工作负载
  • 动态控制:即使迁移仍在运行,您也可以交互式interactively地重新配置gh-ost。您可以强制启动节流
  • 审计:您可以查询gh-ost的状态。在unix套接字或TCP上监听gh-ost
  • 切换阶段的控制:可以指示gh-ost推迟可能是最关键的步骤:表的交换,直到您可以方便地使用为止。没有必要担心ETA在办公时间之外
  • 外部挂载hooks可以将gh-ost与您的特定环境结合起来

5.使用

  • 详细说明都在

    cheatsheet

    。您可能对以各种模式调用gh-ost感兴趣:

    • noop迁移(仅仅测试迁移是有效的和良好的)
    • 使用从库进行的真正迁移(如果您的主库使用基于语句的复制,则需要在主库上运行;gh-ost可以识别涉及的服务器的身份。)
    • 一个真正的迁移,直接在主库上运行(但是gh-ost更喜欢前者)
    • 在从库上做真实迁移(主版本未受影响)
    • 在从库上做测试迁移,您可以通过这种方式与gh-ost的操作建立信任。

6.它是如何工作的?

  • 所有现有的在线模式变更工具以类似的方式操作:他们创建一个与你原始表相似的ghost表,缓慢而逐步将数据从原始表复制到ghost表,同时不断传输增量 (任何insert、delete、update应用到你的表)到ghost表。
  • 最后,在适当的时候,它们会用ghost表替换原来的表。
  • gh-ost使用相同的模式。但是,它不同于所有现有的工具,不使用触发器。我们已经认识到触发器是许多限制和风险的根源many limitations and risks
  • 相反,gh-ost使用binlog流捕获表更改uses the binary log stream,并异步地将它们应用到ghost表。gh-ost承担了一些其他工具留给数据库执行的任务。因此,gh-ost对迁移过程有更大的控制:可以真正暂停、可以真正地将迁移的写负载与主工作负载分离。
  • 此外,它还提供了许多操作上的好处operational perks,使它更安全、更值得信赖、使用起来更有趣。

gh-ost 首先连接到主库上,根据 alter 语句创建幽灵表,然后作为一个”备库“连接到其中一个真正的备库上,一边在主库上拷贝已有的数据到幽灵表,一边从备库上拉取增量数据的 binlog,然后不断的把 binlog 应用回主库。图中 cut-over 是最后一步,锁住主库的源表,等待 binlog 应用完毕,然后替换 gh-ost 表为源表。gh-ost 在执行中,会在原本的 binlog event 里面增加以下 hint 和心跳包,用来控制整个流程的进度,检测状态等。这种架构带来诸多好处,例如:

  • 整个流程异步执行,对于源表的增量数据操作没有额外的开销,高峰期变更业务对性能影响小。
  • 降低写压力,触发器操作都在一个事务内,gh-ost 应用 binlog 是另外一个连接在做。
  • 可停止,binlog 有位点记录,如果变更过程发现主库性能受影响,可以立刻停止拉binlog,停止应用 binlog,稳定之后继续应用。
  • 可测试,gh-ost 提供了测试功能,可以连接到一个备库上直接做 Online DDL,在备库上观察变更结果是否正确,再对主库操作,心里更有底。

7.工作模式

  • gh-ost 根据参数配置可选三种变更模式
  • 除了直连主库和连接从库以外,还有连接从库做变更测试

7.1.模式1 —— 连上从库,在主库上修改

  • 这是 gh-ost 默认的工作模式,它会查看从库情况,找到集群的主库并且连接上去。修改操作的具体步骤是

    • 在主库上读写行数据;
    • 在从库上读取二进制日志事件,将变更应用到主库上;
    • 在从库上查看表格式、字段、主键、总行数等;
    • 在从库上读取 gh-ost 内部事件日志(比如心跳);
    • 在主库上完成表切换;
  • 如果主库的二进制日志格式是 statement,就可以使用这种模式。但从库就必须配成启用二进制日志(log_bin, log_slave_updates),还要设成 Row 格式(binlog_format=ROW),实际上 gh-ost 会在从库上帮你做这些设置。

  • 事实上,即使把从库改成 Row 格式,这仍然是对主库侵入最少的工作模式。

7.2.模式2 —— 直接在主库上修改

  • 如果没有从库,或者不想在从库上操作,那直接用主库也是可以的。gh-ost 就会在主库上直接做所有的操作。仍然可以在上面查看主从复制延迟。

    • 主库必须产生 Row 格式的二进制日志;
    • 启动 gh-ost 时必须用 --allow-on-master 选项来开启这种模式;

7.3.模式3 —— 在从库上修改和测试

  • 这种模式会在从库上做修改。gh-ost 仍然会连上主库,但所有操作都是在从库上做的,不会对主库产生任何影响。在操作过程中,gh-ost 也会不时地暂停,以便从库的数据可以保持最新。

    • --migrate-on-replica 选项让 gh-ost 直接在从库上修改表。最终的切换过程也是在从库正常复制的状态下完成的。
    • --test-on-replica 表明操作只是为了测试目的。在进行最终的切换操作之前,复制会被停止。原始表和临时表会相互切换,再切换回来,最终相当于原始表没被动过。主从复制暂停的状态下,你可以检查和对比这两张表中的数据。

8.下载

9.参数说明

option meaning default value
--aliyun-rds 是否在阿里云数据库上执行 true
--allow-master-master 是否允许gh-ost运行在双主复制架构中,一般与 --assume-master-host参数一起使用
--allow-nullable-unique-key 允许 gh-ost 在数据迁移依赖的唯一键可以为NULL,默认为不允许为NULL的唯一键。如果数据迁移(migrate)依赖的唯一键允许NULL值,则可能造成数据不正确,请谨慎使用
--allow-on-master 允许gh-ost直接运行在主库上。不加该参数 gh-ost 默认连接的从库
--alter string DDL语句
--approve-renamed-columns ALTER 如果你修改一个列的名字,gh-ost将会识别到并且需要提供重命名列名的原因,默认情况下gh-ost是不继续执行的,除非提供-approve-renamed-columns ALTER
--ask-pass MySQL密码
--assume-master-host 为gh-ost指定一个主库,格式为”ip:port”或者”hostname:port”。在这主主架构里比较有用,或则在gh-ost发现不到主的时候有用
--assume-rbr 确认gh-ost连接的数据库实例的binlog_format=ROW的情况下,可以指定-assume-rbr,这样可以禁止从库上运行stop slave,start slave,执行gh-ost用户也不需要SUPER权限
--check-flag
--chunk-size 在每次迭代中处理的行数量(允许范围:100-100000) 1000
--concurrent-rowcount 该参数如果为True,则进行row-copy之后,估算统计行数(使用explain select count(*)方式),并调整ETA时间,否则,gh-ost首先预估统计行数,然后开始row-copy true
--conf gh-ost的配置文件路径
--critical-load string 一系列逗号分隔的status-name=values组成,当MySQL中status超过对应的values,gh-ost将会退出。-critical-load Threads_connected=20,Connections=1500,指的是当MySQL中的状态值Threads_connected>20,Connections>1500的时候,gh-ost将会由于该数据库严重负载而停止并退出
--critical-load-hibernate-seconds 负载达到critical-load时,gh-ost在指定的时间内进入休眠状态。 它不会读/写任何来自任何服务器的任何内容
--critical-load-interval-millis 当值为0时,当达到-critical-load,gh-ost立即退出。当值不为0时,当达到-critical-load,gh-ost会在-critical-load-interval-millis秒数后,再次进行检查,再次检查依旧达到-critical-load,gh-ost将会退出
--cut-over 选择cut-over类型:atomic/two-step,atomic(默认)类型的cut-over是github的算法,two-step采用的是facebook-OSC的算法
--cut-over-exponential-backoff
--cut-over-lock-timeout-seconds gh-ost在cut-over阶段最大的锁等待时间,当锁超时时,gh-ost的cut-over将重试 3
--database string 数据库名
--debug debug模式
--default-retries 各种操作在panick前重试次数 60
--discard-foreign-keys 该参数针对一个有外键的表,在gh-ost创建ghost表时,并不会为ghost表创建外键。该参数很适合用于删除外键,除此之外,请谨慎使用
--dml-batch-size 在单个事务中应用DML事件的批量大小(范围1-100) 1
--exact-rowcount 准确统计表行数(使用select count(*)的方式),得到更准确的预估时间
--execute 实际执行alter&migrate表,默认为noop,不执行,仅仅做测试并退出,如果想要ALTER TABLE语句真正落实到数据库中去,需要明确指定-execute
--exponential-backoff-max-interval
--force-named-cut-over 如果为true,则unpostpone / cut-over交互式命令必须命名迁移的表
--force-table-names 在临时表上使用的表名前缀
--heartbeat-interval-millis gh-ost心跳频率值 500
--hooks-hint 任意消息通过 GH_OST_HOOKS_HINT 注入到 hook
--hooks-path hook文件存放目录(默认为empty,即禁用hook)。hook会在这个目录下寻找符合约定命名的hook文件来执行
--host MySQL IP/hostname
--initially-drop-ghost-table gh-ost操作之前,检查并删除已经存在的ghost表。该参数不建议使用,请手动处理原来存在的ghost表。默认该参数,gh-ost直接退出操作 不启用
--initially-drop-old-table gh-ost操作之前,检查并删除已经存在的旧表。该参数不建议使用,请手动处理原来存在的ghost表。默认,gh-ost直接退出操作 不启用
--initially-drop-socket-file gh-ost强制删除已经存在的socket文件。该参数不建议使用,可能会删除一个正在运行的gh-ost程序,导致DDL失败
--master-password MySQL 主密码
--master-user MysQL主账号
--max-lag-millis 主从复制最大延迟时间,当主从复制延迟时间超过该值后,gh-ost将采取节流(throttle)措施 1500s
--max-load 逗号分隔状态名称=阈值,如:'Threads_running=100,Threads_connected=500'. When status exceeds threshold, app throttles writes
--migrate-on-replica gh-ost的数据迁移(migrate)运行在从库上,而不是主库上
--nice-ratio 每次chunk时间段的休眠时间,范围[0.0…100.0]。0:每个chunk时间段不休眠,即一个chunk接着一个chunk执行;1:每row-copy 1毫秒,则另外休眠1毫秒;0.7:每row-copy 10毫秒,则另外休眠7毫秒
--ok-to-drop-table gh-ost操作结束后,删除旧表,默认状态是不删除旧表,会存在_tablename_del表
--panic-flag-file 当这个文件被创建,gh-ost将会立即退出
--password MySQL密码
--port MySQL端口,最好用从库
--postpone-cut-over-flag-file 当这个文件存在的时候,gh-ost的cut-over阶段将会被推迟,数据仍然在复制,直到该文件被删除
--quiet 静默模式
--replica-server-id gh-ost的server_id
--replication-lag-query 弃用
--serve-socket-file gh-ost的socket文件绝对路径
--serve-tcp-port gh-ost使用端口,默认为关闭端口
--skip-foreign-key-checks 确定你的表上没有外键时,设置为'true',并且希望跳过gh-ost验证的时间-skip-renamed-columns ALTER
--skip-renamed-columns ALTER 如果你修改一个列的名字(如change column),gh-ost将会识别到并且需要提供重命名列名的原因,默认情况下gh-ost是不继续执行的。该参数告诉gh-ost跳该列的数据迁移,让gh-ost把重命名列作为无关紧要的列。该操作很危险,你会损失该列的所有值
--stack 添加错误堆栈追踪
--switch-to-rbr 让gh-ost自动将从库的binlog_format转换为ROW格式
--table 表名
--test-on-replica 在从库上测试gh-ost,包括在从库上数据迁移(migration),数据迁移完成后stop slave,原表和ghost表立刻交换而后立刻交换回来。继续保持stop slave,使你可以对比两张表
--test-on-replica-skip-replica-stop 当-test-on-replica执行时,该参数表示该过程中不用stop slave
--throttle-additional-flag-file 当该文件被创建后,gh-ost操作立即停止。该参数可以用在多个gh-ost同时操作的时候,创建一个文件,让所有的gh-ost操作停止,或者删除这个文件,让所有的gh-ost操作恢复
--throttle-control-replicas 列出所有需要被检查主从复制延迟的从库
--throttle-flag-file 当该文件被创建后,gh-ost操作立即停止。该参数适合控制单个gh-ost操作。-throttle-additional-flag-file string适合控制多个gh-ost操作
--throttle-http
--throttle-query string 节流查询。每秒钟执行一次。当返回值=0时不需要节流,当返回值>0时,需要执行节流操作。该查询会在数据迁移(migrated)服务器上操作,所以请确保该查询是轻量级的
--timestamp-old-table 在旧表名中使用时间戳。 这会使旧表名称具有唯一且无冲突的交叉迁移
--tungsten 告诉gh-ost你正在运行的是一个tungsten-replication拓扑结构
--user MYSQL用户
--verbose
--version

10.实际操作

  • 使用说明:条件是操作的MySQL上需要的binlog模式是ROW。如果在一个从上测试也必须是ROW模式,还要开启log_slave_updates。根据上面的参数说明按照需求进行调整
  • 环境:主库:192.168.1.101;从库:192.168.1.102

10.1. DDL执行过程

  • 校验阶段:

    • 检查有没有外键和触发器。
    • 检查表的主键信息。
    • 检查是否主库或从库,是否开启 log_slave_updates,以及 binlog 信息
    • 检查 gho 和 del 结尾的临时表是否存在
    • 创建 ghc 结尾的表,存数据迁移的信息,以及 binlog 信息等
  • 初始化 stream 的连接,添加 binlog 的监听
  • 迁移阶段:
    • 创建 gho 结尾的临时表,执行 DDL 在 gho 结尾的临时表上
    • 开启事务,按照主键id把源表数据写入到 gho 结尾的表上,再提交,以及binlog apply
  • cut-over 阶段:
    • lock 源表,rename 表:rename 源表 to 源 _del 表,gho 表 to 源表
    • 清理 ghc 表

10.1.1. 单实例上DDL

  • 单个实例相当于主库,需要开启--allow-on-master参数和ROW模式
  1. gh-ost --user="root" --password="root" --host=192.168.1.101 --database="test" --table="t1"
  2. --alter="ADD COLUMN cc2 varchar(10),add column cc3 int not null default 0 comment 'test' " --allow-on-master --execute

10.1.2. 主从上DDL

  • 有2个选择,一是按照1直接在主上执行同步到从上,另一个连接到从库,在主库做迁移(只要保证从库的binlog为ROW即可,主库不需要保证)
  1. gh-ost --user="root" --password="root" --host=192.168.1.102 --database="test" --table="t" --initially-drop-old-table
  2. --alter="ADD COLUMN y1 varchar(10),add column y2 int not null default 0 comment 'test' " --execute
  • 此时的操作大致是:

    • 行数据在主库上读写
    • 读取从库的二进制日志,将变更应用到主库
    • 在从库收集表格式,字段&索引,行数等信息
    • 在从库上读取内部的变更事件(如心跳事件)
    • 在主库切换表
  • 在执行DDL中,从库会执行一次 stop/start slave,要是确定从的 binlog 是 ROW 的话可以添加参数:--assume-rbr。如果从库的 binlog 不是 ROW,可以用参数 --switch-to-rbr 来转换成 ROW,此时需要注意的是执行完毕之后,binlog 模式不会被转换成原来的值。--assume-rbr 和 --switch-to-rbr 参数不能一起使用。

10.1.3.在从上进行DDL测试

  1. gh-ost --user="root" --password="root" --host=192.168.1.102 --database="test" --table="t"
  2. --alter="ADD COLUMN abc1 varchar(10),add column abc2 int not null default 0 comment 'test' " --test-on-replica --switch-to-rbr --execute
  • 参数--test-on-replica:在从库上测试gh-ost,包括在从库上数据迁移 (migration),数据迁移完成后 stop slave,原表和 ghost 表立刻交换而后立刻交换回来。继续保持 stop slave,使你可以对比两张表。如果不想 stop slave,则可以再添加参数:--test-on-replica-skip-replica-stop

  • 上面三种是 gh-ost 操作模式,上面的操作中,到最后不会清理临时表,需要手动清理,再下次执行之前果然临时表还存在,则会执行失败,可以通过参数进行删除:

    • --initially-drop-ghost-table:gh-ost操作之前,检查并删除已经存在的ghost表。该参数不建议使用,请手动处理原来存在的ghost表。默认不启用该参数,gh-ost直接退出操作。
    • --initially-drop-old-table:gh-ost操作之前,检查并删除已经存在的旧表。该参数不建议使用,请手动处理原来存在的ghost表。默认不启用该参数,gh-ost直接退出操作。
    • --initially-drop-socket-file:gh-ost强制删除已经存在的socket文件。该参数不建议使用,可能会删除一个正在运行的gh-ost程序,导致DDL失败。
    • --ok-to-drop-table:gh-ost操作结束后,删除旧表,默认状态是不删除旧表,会存在_tablename_del表。
  • 还有其他的一些参数,比如:--exact-rowcount、--max-lag-millis、--max-load 等等,可以看上面的说明,具体大部分常用的参数命令如下:

  1. gh-osc --user= --password= --host= --database= --table= --max-load=Threads_running=30, --chunk-size=1000 --serve-socket-file=/tmp/gh-ost.test.sock
  2. --exact-rowcount --allow-on-master/--test-on-replica --initially-drop-ghost-table/--initially-drop-old-table/--initially-drop-socket-file
  3. --max-lag-millis= --max-load='Threads_running=100,Threads_connected=500' --ok-to-drop-table

10.1.4.额外说明:终止、暂停、限速

  1. gh-ost --user="root" --password="root" --host=192.168.1.101 --database="test" --table="t1"
  2. --alter="ADD COLUMN o2 varchar(10),add column o1 int not null default 0 comment 'test' " --exact-rowcount
  3. --serve-socket-file=/tmp/gh-ost.t1.sock --panic-flag-file=/tmp/gh-ost.panic.t1.flag --postpone-cut-over-flag-file=/tmp/ghost.postpone.t1.flag
  4. --allow-on-master --execute
  • 表示文件终止运行--panic-flag-file

    • 创建文件终止运行,例子中创建 /tmp/gh-ost.panic.t1.flag 文件,终止正在运行的 gh-ost,临时文件清理需要手动进行
  • 表示文件禁止cut-over进行,即禁止表名切换,数据复制正常进行。--postpone-cut-over-flag-file
    • 创建文件延迟cut-over进行,即推迟切换操作。例子中创建/tmp/ghost.postpone.t1.flag文件,gh-ost 会完成行复制,但并不会切换表,它会持续的将原表的数据更新操作同步到临时表中。
  • 使用socket监听请求,操作者可以在命令运行后更改相应的参数。--serve-socket-file,--serve-tcp-port(默认关闭)
  • 创建socket文件进行监听,通过接口进行参数调整,当执行操作的过程中发现负载、延迟上升了,不得不终止操作,重新配置参数,如 chunk-size,然后重新执行操作命令,可以通过scoket接口进行动态调整。如:

10.1.4.1.暂停操作:

  1. #暂停
  2. echo throttle | socat - /tmp/gh-ost.test.t1.sock
  3. #恢复
  4. echo no-throttle | socat - /tmp/gh-ost.test.t1.sock

10.1.4.2.修改限速参数:

  1. echo chunk-size=100 | socat - /tmp/gh-ost.t1.sock
  2. echo max-lag-millis=200 | socat - /tmp/gh-ost.t1.sock
  3. echo max-load=Thread_running=3 | socat - /tmp/gh-ost.t1.sock

11.建议

  • Testing above all,尝试 --test-on-replica前几次。更好的是,让它继续运行。我们有多个从库,在这些从库中,我们迭代所有的生产表,逐个迁移它们,检查和结果,验证迁移是好的。
  • 对于每个主库迁移,首先发出一个noop
  • 然后通过——问题的执行

12.更多的小贴士

  • 使用 --exact-rowcount获取精确的提示
  • 使用 --postpone-cut-over-flag-file控制切换时机
  • 熟悉交互式命令interactive commands

13.更多

gh-ost的更多相关文章

  1. Ghost-无损DDL

    目录 一.什么是DDL? 二.表级锁和元数据锁 2.1.什么是表锁? 2.2.什么是MDL? 三.什么是无损DDL? 四.DDL重建表 Mysql5.5之前重建表 Mysql5.6之后重建表 五.gh ...

  2. 打开或导入项目,从脱机 Outlook 数据文件 (.ost)

    打开或导入项目,从脱机 Outlook 数据文件 (.ost) Microsoft Outlook 2010 doesn\rquote t 支持手动打开或导入项目,从一个 脱机 Outlook 数据文 ...

  3. 设置outlook 2013 默认的ost路径

    How To Change Default Data File (.OST) Location in Office 2013 To set the default location of an out ...

  4. QGIS+GH + MapServer

    拒绝描图,如何利用GH+QGIS完爆场地底图?http://www.sohu.com/a/251004986_657084 拒绝描图--爬取OSM数据绘制底图 所用软件 RHINO+GH\QGIS\G ...

  5. 在Outlook中修改脱机文件(.ost)的保存位置

    方法一 少读者所在公司的邮箱客户端都在使用微软 Exchange Server 的“缓存 Exchange 模式”.Outlook会默认将脱机文件(.ost文件)保存在C盘上. 但很多读者不希望Out ...

  6. 英语发音规则---gh

    英语发音规则---gh 一.总结 一句话总结:gh字母组合的读音在中学英语课本中归纳起来主要有"发音"和"不发音"两种情况. gh字词首是发/g/,因为需要开头 ...

  7. Outlook 数据文件(.pst 和 .ost)简介

    使用 Microsoft Outlook 时,电子邮件.日历.任务和其他项目保存在邮件服务器或计算机上,或者同时保存在这两个位置.如果 Outlook 项目保存在计算机上,则它们保存在 Outlook ...

  8. 20180710使用gh

    转自:http://www.ywnds.com/?p=14265 一.背景 GitHub正式宣布以开源的方式发布gh-ost:GitHub的MySQL无触发器在线更改表定义工具!下面是官方给出gh-o ...

  9. 【pic+js+gh】免费高速图床方案

    本文用到的工具或网站 PicGo jsdelivr github 速度对比 Github的速度: jsdelivrCDN的速度: 下载PicGo 首先进入PicGo的下载地址 选择最新版本下载,根据自 ...

  10. OST

    爱情的条件 http://music.163.com/#/album?id=531414 kill me heal me http://music.163.com/#/album?id=3104890

随机推荐

  1. WPF X:Shared概述 - CSDN博客

    原文:WPF X:Shared概述 - CSDN博客 一.含义 X:Shared用于指定请求资源时创建实例的两种方式. X:Shared = "true"(默认):表示所有请求都是 ...

  2. Redis进阶实践之十八 使用管道模式提高Redis查询的速度

    原文:Redis进阶实践之十八 使用管道模式提高Redis查询的速度 一.引言             学习redis 也有一段时间了,该接触的也差不多了.后来有一天,以为同事问我,如何向redis中 ...

  3. 零元学Expression Blend 4 - Chapter 25 以Text相关功能就能简单做出具有设计感的登入画面

    原文:零元学Expression Blend 4 - Chapter 25 以Text相关功能就能简单做出具有设计感的登入画面 本章将交大家如何运用Blend 4 内的Text相关功能做出有设计感的登 ...

  4. C#根据对象的指定字段去除重复值

    PersonInfo类: public class PersonInfo { public int Index; public string Name; public override string ...

  5. 用Delphi开发视频聊天软件

    摘要:目前网上视频聊天软件.视频会议软件.可视IP电话软件随处可见,你是否想自己做一个玩玩?其实这类软件无非是视频加上网络而建成的.如果熟悉视频捕捉和网络传输技术,根本就难不倒你.微软为软件开发人员提 ...

  6. 推荐一个第三方Qt库的集合 good

    https://inqlude.org/ Stable libraries | Development versions | Unreleased | Commercial | All attica ...

  7. SpringMVC核心架构的具体流程

    核心架构的具体流程步骤如下: 1.首先用户发送请求-->DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行 处理,作为统一访问点,进行全局的流程控 ...

  8. DUI-模态对话框的实现

    模态对话框要求自己实现自己的消息循环,当然,建议它还是处于主线程中,所以最好是由它再调用主线程的消息循环函数,此时主线程自身的消息循环函数被阻塞,等待模板对话框的消息循环函数退出 参考代码如下: 1 ...

  9. vs2008在win7系统中安装不问题

    据说是office软件冲突问题. 解决方案是卸载了office软件,不管是2007还是其它版本,先安装vs2008,再安装其它的.

  10. 【canvas】基础练习二 文字

    demo1 fillText strokeText绘制文字 <!DOCTYPE html> <html lang="en"> <head> &l ...