0%

一、单个参数:

复制代码

public List<XXBean> getXXBeanList(String xxCode); <select id=“getXXXBeanList” parameterType=“java.lang.String” resultType=“XXBean”> select t.* from tableName t where t.id= #{id} </select> 其中方法名和ID一致,#{}中的参数名与方法中的参数名一直, 我这里采用的是XXXBean是采用的短名字,

select 后的字段列表要和bean中的属性名一致, 如果不一致的可以用 as 来补充。

复制代码

二、多参数:

复制代码

public List<XXXBean> getXXXBeanList(String xxId, String xxCode); <select id=“getXXXBeanList” resultType=“XXBean”> select t.* from tableName where id = #{0} and name = #{1} </select> 由于是多参数那么就不能使用parameterType, 改用#{index}是第几个就用第几个的索引,索引从0开始

复制代码

三、Map封装多参数:

复制代码

public List<XXXBean> getXXXBeanList(HashMap map); <select id=“getXXXBeanList” parameterType=“hashmap” resultType=“XXBean”> select 字段… from XXX where id=#{xxId} code = #{xxCode} </select> 其中hashmap是mybatis自己配置好的直接使用就行。map中key的名字是那个就在#{}使用那个,map如何封装就不用了我说了吧。

复制代码

四、List封装in:

复制代码

public List<XXXBean> getXXXBeanList(List<String> list); <select id=“getXXXBeanList” resultType=“XXBean”> select 字段… from XXX where id in <foreach item=“item” index=“index” collection=“list” open=“(“ separator=“,” close=“)”> #{item} </foreach>
</select> foreach 最后的效果是select 字段… from XXX where id in (‘1’,’2’,’3’,’4’)

复制代码

五、多参数传递之注解方式示:

复制代码

例子:

public AddrInfo getAddrInfo(@Param(“corpId”)int corpId, @Param(“addrId”)int addrId);

xml配置这样写: <select id=“getAddrInfo” resultMap=“com.xxx.xxx.AddrInfo”> SELECT * FROM addr__info
    where addr_id=#{addrId} and corp_id=#{corpId} </select> 以前在<select>语句中要带parameterType的,现在可以不要这样写。

复制代码

六、selectList()只能传递一个参数,但实际所需参数既要包含String类型,又要包含List类型时的处理方法:

将参数放入Map,再取出Map中的List遍历。如下:

复制代码

List list_3 = new ArrayList();
Map<String, Object> map2 = new HashMap<String, Object>();

list.add(“1”);

list.add(“2”);

map2.put(“list”, list); //网址id

map2.put(

“siteTag”, “0”);//网址类型

复制代码

public List getSysInfo(Map<String, Object> map2) { return getSqlSession().selectList(“sysweb.getSysInfo”, map2);
}

复制代码

<select id=“getSysInfo” parameterType=“java.util.Map” resultType=“SysWeb”> select t.sysSiteId, t.siteName, t1.mzNum as siteTagNum, t1.mzName as siteTag, t.url, t.iconPath
from TD_WEB_SYSSITE t
left join TD_MZ_MZDY t1 on t1.mzNum = t.siteTag and t1.mzType = 10
WHERE t.siteTag = #{siteTag }
and t.sysSiteId not in <foreach collection=“list” item=“item” index=“index” open=“(“ close=“)” separator=“,”> #{item} </foreach>
</select>

复制代码

前面的所有语句中你所见到的都是简单参数的例子,实际上参数是 MyBatis 非常强大的元素,对于简单的做法, 90% 的情况参数都很少,比如:

1
2
3
<select id="selectUsers" resultType="User"> select id, username, password
from users
where id = #{id} </select>

上面的这个示例说明了一个非常简单的命名参数映射。参数类型被设置为 int,这样这个参数就可以被设置成任何内容。

原生的类型或简单数据类型(比如整型和字符串)因为没有相关属性,它会完全用参数值来替代。然而,如果传入一个复杂的对象,行为就会有一点不同了。比如:

<insert id=“insertUser” parameterType=“User”> insert into users (id, username, password)
values (#{id}, #{username}, #{password}) </insert>

如果 User 类型的参数对象传递到了语句中,id、username 和 password 属性将会被查找,然后将它们的值传入预处理语句的参数中。

这点对于向语句中传参是比较好的而且又简单,不过参数映射的功能远不止于此。

首先,像 MyBatis 的其他部分一样,参数也可以指定一个特殊的数据类型。

#{property,javaType=int,jdbcType=NUMERIC}

像 MyBatis 的剩余部分一样,javaType 通常可以从参数对象中来去确定,前提是只要对象不是一个 HashMap。那么 javaType 应该被确定来保证使用正确类型处理器。

NOTE 如果 null 被当作值来传递,对于所有可能为空的列,需要设置参数的jdbcType。你可以自己通过阅读预处理语句的 setNull() 方法的 JavaDocs 文档来研究这种情况。

为了以后定制类型处理方式,你也可以指定一个特殊的类型处理器类(或别名),比如:

#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

尽管看起来配置变得越来越繁琐,但实际上是很少去设置它们。

对于数值类型,还有一个小数保留位数的设置,来确定小数点后保留的位数。

#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}

最后,mode 属性允许你指定 IN,OUT 或 INOUT 参数。

如果参数为 OUT 或 INOUT,参数对象属性的真实值将会被改变,就像你在获取输出参数时所期望的那样。如果 mode 为 OUT(或 INOUT),而且 jdbcType 为 CURSOR(也就是 Oracle 的 REFCURSOR),你必须指定一个 resultMap 来映射结果集到参数类型。要注意这里的 javaType 属性是可选的,如果左边的空白是 jdbcType 的 CURSOR 类型,它会自动地被设置为结果集。

#{department, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=departmentResultMap}

MyBatis 也支持很多高级的数据类型,比如结构体,但是当注册 out 参数时你必须告诉它语句类型名称。比如(再次提示,在实际中要像这样不能换行):

#{middleInitial, mode=OUT, jdbcType=STRUCT, jdbcTypeName=MY_TYPE, resultMap=departmentResultMap}

尽管所有这些强大的选项很多时候你只简单指定属性名,其他的事情 MyBatis 会自己去推断,最多你需要为可能为空的列名指定 jdbcType。

#{firstName}
#{middleInitial,jdbcType=VARCHAR}
#{lastName}

默认情况下,使用#{}格式的语法会导致 MyBatis 创建预处理语句属性并安全地设置值(比如?)。这样做更安全,更迅速,通常也是首选做法,不过有时你只是想直接在 SQL 语句中插入一个不改变的字符串。比如,像 ORDER BY,你可以这样来使用:

这里 MyBatis 不会修改或转义字符串。

NOTE 以这种方式接受从用户输出的内容并提供给语句中不变的字符串是不安全的,会导致潜在的 SQL 注入攻击,因此要么不允许用户输入这些字段,要么自行转义并检验。

3.1 #{}与${}

注意以下两个符号的使用:

#{}(ibatis为:##):MyBatis创建预处理语句属性从而设置安全的值(比如?)。常用作查询条件的值,例如:where name=#{value}。
该参数可以指定一个确切的数据类型,例如: #{property,javaType=int,jdbcType=NUMERIC}.
${}(ibatis为:$$): MyBatis不会修改或转义字符串,将会直接在SQL语句中插入一个不改变的字符串,常用于拼凑sql的实体部分,
例如:select * from ${tableName}


如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,让更多的人能够享受到获取知识的快乐!因为本人初入职场,鉴于自身阅历有限,所以本博客内容大部分来源于网络中已有知识的汇总,欢迎各位转载,评论,大家一起学习进步!如有侵权,请及时和我联系,切实维护您的权益!

[root@mysql support-files]# vim my-innodb-heavy-4G.cnf

#BEGIN CONFIG INFO

#DESCR: 4GB RAM, InnoDB only, ACID, few connections, heavy queries

#TYPE: SYSTEM

#END CONFIG INFO

#

# This is a MySQL example config file for systems with 4GB of memory

# running mostly MySQL using InnoDB only tables and performing complex

# queries with few connections.

#

# MySQL programs look for option files in a set of

# locations which depend on the deployment platform.

# You can copy this option file to one of those

# locations. For information about these locations, see:

#

# In this file, you can use all long options that a program supports.

# If you want to know which options a program supports, run the program

# with the "--help" option.

#

# More detailed information about the individual options can also be

# found in the manual.

#

#

# The following options will be read by MySQL client applications.

# Note that only client applications shipped by MySQL are guaranteed

# to read this section. If you want your own MySQL client program to

# honor these values, you need to specify it as an option during the

# MySQL client library initialization.

#

# 以下选项会被MySQL客户端应用读取, 注意只有MySQL附带的客户端应用程序保证可以读取这段内容,如果你想你自己的MySQL应用程序获取这些值,需要在MySQL客户端库初始化的时候指定这些选项

[client]

#password  = [your_password] #mysql客户端连接mysql时的密码

port    = 3306 #mysql客户端连接时的默认端口

socket    = /tmp/mysql.sock #与mysql服务器本地通信所使用的socket文件路径

# *** Application-specific options follow here ***

#

# The MySQL server

#

[mysqld]

# generic configuration options #一般配置选项

port    = 3306 #mysql服务器监听的默认端口

socket    = /tmp/mysql.sock #socket本地通信文件路径

# back_log is the number of connections the operating system can keep in

# the listen queue, before the MySQL connection manager thread has

# processed them. If you have a very high connection rate and experience

# "connection refused" errors, you might need to increase this value.

# Check your OS documentation for the maximum value of this parameter.

# Attempting to set back_log higher than your operating system limit

# will have no effect.

# back_log 是操作系统在监听队列中所能保持的连接数,

# 队列保存了在MySQL连接管理器线程处理之前的连接.

# 如果你有非常高的连接率并且出现“connection refused”报错,

# 你就应该增加此处的值.

# 检查你的操作系统能打开文件数来获取这个变量的最大值.

# 如果将back_log设定到比你操作系统限制更高的值,将会没有效果

back_log = 50

# Don't listen on a TCP/IP port at all. This can be a security

# enhancement, if all processes that need to connect to mysqld run

# on the same host. All interaction with mysqld must be made via Unix

# sockets or named pipes.

# Note that using this option without enabling named pipes on Windows

# (via the "enable-named-pipe" option) will render mysqld useless!

# 不在TCP/IP端口上进行监听.

# 如果所有的进程都是在同一台服务器连接到本地的mysqld,

# 这样设置将是增强安全的方法

# 所有mysqld的连接都是通过Unix sockets 或者命名管道进行的.

# 注意在windows下如果没有打开命名管道选项而只是用此项

# (通过 “enable-named-pipe” 选项) 将会导致mysql服务没有任何作用!

#skip-networking #默认是没有开启的

# The maximum amount of concurrent sessions the MySQL server will

# allow. One of these connections will be reserved for a user with

# SUPER privileges to allow the administrator to login even if the

# connection limit has been reached.

# MySQL 服务器所允许的同时会话数的上限

# 其中一个连接将被SUPER权限保留作为管理员登录.

# 即便已经达到了连接数的上限.

max_connections = 100

# Maximum amount of errors allowed per host. If this limit is reached,

# the host will be blocked from connecting to the MySQL server until

# "FLUSH HOSTS" has been run or the server was restarted. Invalid

# passwords and other errors during the connect phase result in

# increasing this value. See the "Aborted_connects" status variable for

# global counter.

# 每个客户端连接最大的错误允许数量,如果达到了此限制.

# 这个客户端将会被MySQL服务阻止直到执行了”FLUSH HOSTS” 或者服务重启

# 非法的密码以及其他在链接时的错误会增加此值.

# 查看 “Aborted_connects” 状态来获取全局计数器.

max_connect_errors = 10

# The number of open tables for all threads. Increasing this value

# increases the number of file descriptors that mysqld requires.

# Therefore you have to make sure to set the amount of open files

# allowed to at least 4096 in the variable "open-files-limit" in

# section [mysqld_safe]

# 所有线程所打开表的数量.

# 增加此值就增加了mysqld所需要的文件描述符的数量

# 这样你需要确认在[mysqld_safe]中 “open-files-limit” 变量设置打开文件数量允许至少2048

table_open_cache = 2048

# Enable external file level locking. Enabled file locking will have a

# negative impact on performance, so only use it in case you have

# multiple database instances running on the same files (note some

# restrictions still apply!) or if you use other software relying on

# locking MyISAM tables on file level.

# 允许外部文件级别的锁. 打开文件锁会对性能造成负面影响

# 所以只有在你在同样的文件上运行多个数据库实例时才使用此选项(注意仍会有其他约束!)

# 或者你在文件层面上使用了其他一些软件依赖来锁定MyISAM表

#external-locking #默认是没有开启的

# The maximum size of a query packet the server can handle as well as

# maximum query size server can process (Important when working with

# large BLOBs). enlarged dynamically, for each connection.

# 服务所能处理的请求包的最大大小以及服务所能处理的最大的请求大小(当与大的BLOB字段一起工作时相当必要)

# 每个连接独立的大小.大小动态增加

max_allowed_packet = 16M

# The size of the cache to hold the SQL statements for the binary log

# during a transaction. If you often use big, multi-statement

# transactions you can increase this value to get more performance. All

# statements from transactions are buffered in the binary log cache and

# are being written to the binary log at once after the COMMIT. If the

# transaction is larger than this value, temporary file on disk is used

# instead. This buffer is allocated per connection on first update

# statement in transaction

# 在一个事务中binlog为了记录SQL状态所持有的cache大小

# 如果你经常使用大的,多声明的事务,你可以增加此值来获取更大的性能.

# 所有从事务来的状态都将被缓冲在binlog缓冲中然后在提交后一次性写入到binlog中

# 如果事务比此值大, 会使用磁盘上的临时文件来替代.

# 此缓冲在每个连接的事务第一次更新状态时被创建

binlog_cache_size = 1M

# Maximum allowed size for a single HEAP (in memory) table. This option

# is a protection against the accidential creation of a very large HEAP

# table which could otherwise use up all memory resources.

# 独立的内存表所允许的最大容量.

# 此选项为了防止意外创建一个超大的内存表导致永尽所有的内存资源.

max_heap_table_size = 64M

# Size of the buffer used for doing full table scans.

# Allocated per thread, if a full scan is needed.

#MySql读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySql会为它分#配一段内存缓冲区。read_buffer_size变量控制这一缓冲区的大小。如果对表的顺序扫描请求非常频繁,#并且你认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能。

read_buffer_size = 2M

# When reading rows in sorted order after a sort, the rows are read

# through this buffer to avoid disk seeks. You can improve ORDER BY

# performance a lot, if set this to a high value.

# Allocated per thread, when needed.

#是MySql的随机读缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,MySql会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需#要排序大量数据,可适当调高该值。但MySql会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开销过大。

read_rnd_buffer_size = 16M

# Sort buffer is used to perform sorts for some ORDER BY and GROUP BY

# queries. If sorted data does not fit into the sort buffer, a disk

# based merge sort is used instead - See the "Sort_merge_passes"

# status variable. Allocated per thread if sort is needed.

# 排序缓冲被用来处理类似ORDER BY以及GROUP BY队列所引起的排序

# 如果排序后的数据无法放入排序缓冲,

# 一个用来替代的基于磁盘的合并分类会被使用

# 查看 “Sort_merge_passes” 状态变量.

# 在排序发生时由每个线程分配

sort_buffer_size = 8M

# This buffer is used for the optimization of full JOINs (JOINs without

# indexes). Such JOINs are very bad for performance in most cases

# anyway, but setting this variable to a large value reduces the

# performance impact. See the "Select_full_join" status variable for a

# count of full JOINs. Allocated per thread if full join is found

# 此缓冲被使用来优化全联合(full JOINs 不带索引的联合).

# 类似的联合在极大多数情况下有非常糟糕的性能表现,

# 但是将此值设大能够减轻性能影响.

# 通过 “Select_full_join” 状态变量查看全联合的数量

# 当全联合发生时,在每个线程中分配

join_buffer_size = 8M

# How many threads we should keep in a cache for reuse. When a client

# disconnects, the client's threads are put in the cache if there aren't

# more than thread_cache_size threads from before. This greatly reduces

# the amount of thread creations needed if you have a lot of new

# connections. (Normally this doesn't give a notable performance

# improvement if you have a good thread implementation.)

# 我们在cache中保留多少线程用于重用

# 当一个客户端断开连接后,如果cache中的线程还少于thread_cache_size,

# 则客户端线程被放入cache中.

# 这可以在你需要大量新连接的时候极大的减少线程创建的开销

# (一般来说如果你有好的线程模型的话,这不会有明显的性能提升.)

thread_cache_size = 8

# This permits the application to give the threads system a hint for the

# desired number of threads that should be run at the same time. This

# value only makes sense on systems that support the thread_concurrency()

# function call (Sun Solaris, for example).

# You should try [number of CPUs]*(2..4) for thread_concurrency

# 此允许应用程序给予线程系统一个提示在同一时间给予渴望被运行的线程的数量.

# 此值只对于支持 thread_concurrency() 函数的系统有意义( 例如Sun Solaris).

# 你可可以尝试使用 [CPU数量]*(2..4) 来作为thread_concurrency的值

thread_concurrency = 8

# Query cache is used to cache SELECT results and later return them

# without actual executing the same query once again. Having the query

# cache enabled may result in significant speed improvements, if your

# have a lot of identical queries and rarely changing tables. See the

# "Qcache_lowmem_prunes" status variable to check if the current value

# is high enough for your load.

# Note: In case your tables change very often or if your queries are

# textually different every time, the query cache may result in a

# slowdown instead of a performance improvement.

# 查询缓冲常被用来缓冲 SELECT 的结果并且在下一次同样查询的时候不再执行直接返回结果.

# 打开查询缓冲可以极大的提高服务器速度, 如果你有大量的相同的查询并且很少修改表.

# 查看 “Qcache_lowmem_prunes” 状态变量来检查是否当前值对于你的负载来说是否足够高.

# 注意: 在你表经常变化的情况下或者如果你的查询原文每次都不同,

# 查询缓冲也许引起性能下降而不是性能提升.

query_cache_size = 64M

# Only cache result sets that are smaller than this limit. This is to

# protect the query cache of a very large result set overwriting all

# other query results.

# 只有小于此设定值的结果才会被缓冲

# 此设置用来保护查询缓冲,防止一个极大的结果集将其他所有的查询结果都覆盖.

query_cache_limit = 2M

# Minimum word length to be indexed by the full text search index.

# You might wish to decrease it if you need to search for shorter words.

# Note that you need to rebuild your FULLTEXT index, after you have

# modified this value.

# 被全文检索索引的最小的字长.

# 你也许希望减少它,如果你需要搜索更短字的时候.

# 注意在你修改此值之后,

# 你需要重建你的 FULLTEXT 索引

ft_min_word_len = 4

# If your system supports the memlock() function call, you might want to

# enable this option while running MySQL to keep it locked in memory and

# to avoid potential swapping out in case of high memory pressure. Good

# for performance.

# 如果你的系统支持 memlock() 函数,你也许希望打开此选项用以让运行中的mysql在在内存高度紧张的时候,数据在内存中保持锁定并且防止可能被swapping out

# 此选项对于性能有益

#memlock

# Table type which is used by default when creating new tables, if not

# specified differently during the CREATE TABLE statement.

# 当创建新表时作为默认使用的表类型,

# 如果在创建表示没有特别执行表类型,将会使用此值

default-storage-engine = MYISAM

# Thread stack size to use. This amount of memory is always reserved at

# connection time. MySQL itself usually needs no more than 64K of

# memory, while if you use your own stack hungry UDF functions or your

# OS requires more stack for some operations, you might need to set this

# to a higher value.

# 线程使用的堆大小. 此容量的内存在每次连接时被预留.

# MySQL 本身常不会需要超过64K的内存

# 如果你使用你自己的需要大量堆的UDF函数

# 或者你的操作系统对于某些操作需要更多的堆,

# 你也许需要将其设置的更高一点.

thread_stack = 192K

# Set the default transaction isolation level. Levels available are:

# 设定默认的事务隔离级别.可用的级别如下:

# READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE

transaction_isolation = REPEATABLE-READ

# Maximum size for internal (in-memory) temporary tables. If a table

# grows larger than this value, it is automatically converted to disk

# based table This limitation is for a single table. There can be many

# of them.

# 内部(内存中)临时表的最大大小

# 如果一个表增长到比此值更大,将会自动转换为基于磁盘的表.

# 此限制是针对单个表的,而不是总和.

tmp_table_size = 64M

# Enable binary logging. This is required for acting as a MASTER in a

# replication configuration. You also need the binary log if you need

# the ability to do point in time recovery from your latest backup.

# 打开二进制日志功能.

# 在复制(replication)配置中,作为MASTER主服务器必须打开此项

# 如果你需要从你最后的备份中做基于时间点的恢复,你也同样需要二进制日志.

log-bin=mysql-bin

# binary logging format - mixed recommended

#设定记录二进制日志的格式,有三种格式,基于语句 statement、 基于行 row、 混合方式 mixed

binlog_format=mixed

# If you're using replication with chained slaves (A->B->C), you need to

# enable this option on server B. It enables logging of updates done by

# the slave thread into the slave's binary log.

# 如果你在使用链式从服务器结构的复制模式 (A->B->C),

# 你需要在服务器B上打开此项.

# 此选项打开在从线程上重做过的更新的日志,

# 并将其写入从服务器的二进制日志.

#log_slave_updates

# Enable the full query log. Every query (even ones with incorrect

# syntax) that the server receives will be logged. This is useful for

# debugging, it is usually disabled in production use.

# 打开查询日志. 所有的由服务器接收到的查询 (甚至对于一个错误语法的查询)

# 都会被记录下来. 这对于调试非常有用, 在生产环境中常常关闭此项.

#log #默认是没有开启的,会影响服务器性能

# Print warnings to the error log file. If you have any problem with

# MySQL you should enable logging of warnings and examine the error log

# for possible explanations.

# 将警告打印输出到错误log文件. 如果你对于MySQL有任何问题

# 你应该打开警告log并且仔细审查错误日志,查出可能的原因.

#log_warnings

# Log slow queries. Slow queries are queries which take more than the

# amount of time defined in "long_query_time" or which do not use

# indexes well, if log_short_format is not enabled. It is normally good idea

# to have this turned on if you frequently add new queries to the

# system.

# 记录慢速查询. 慢速查询是指消耗了比 “long_query_time” 定义的更多时间的查询.

# 如果 log_long_format 被打开,那些没有使用索引的查询也会被记录.

# 如果你经常增加新查询到已有的系统内的话. 一般来说这是一个好主意

slow_query_log

# All queries taking more than this amount of time (in seconds) will be

# trated as slow. Do not use "1" as a value here, as this will result in

# even very fast queries being logged from time to time (as MySQL

# currently measures time with second accuracy only).

# 所有的使用了比这个时间(以秒为单位)更多的查询会被认为是慢速查询.

# 不要在这里使用”1″, 否则会导致所有的查询,甚至非常快的查询页被记录下来(由于MySQL 目前时间的精确度只能达到秒的级别).

long_query_time = 2

# *** Replication related settings # *** 主从复制相关的设置

# Unique server identification number between 1 and 2^32-1. This value

# is required for both master and slave hosts. It defaults to 1 if

# "master-host" is not set, but will MySQL will not function as a master

# if it is omitted.

# 唯一的服务辨识号,数值位于 1 到 2^32-1之间.

# 此值在master和slave上都需要设置.

# 如果 “master-host” 没有被设置,则默认为1, 但是如果忽略此选项,MySQL不会作为master生效.

server-id = 1

# Replication Slave (comment out master section to use this) #复制的Slave (去掉master段的注释来使其生效)

#

# To configure this host as a replication slave, you can choose between

# two methods : #为了配置此主机作为复制的slave服务器,你可以选择两种方法:

#

# 1) Use the CHANGE MASTER TO command (fully described in our manual) -

#  the syntax is: #使用 CHANGE MASTER TO 命令 (在我们的手册中有完整描述) -

# 语法如下:

#

#  CHANGE MASTER TO MASTER_HOST=<host>, MASTER_PORT=<port>,

#  MASTER_USER=<user>, MASTER_PASSWORD=<password> ;

#

#  where you replace <host>, <user>, <password> by quoted strings and

#  <port> by the master's port number (3306 by default).

#  你需要替换掉 , , 等被尖括号包围的字段以及使用master的端口号替换 (默认3306).

#  Example: 案例

#

#  CHANGE MASTER TO MASTER_HOST='125.564.12.1', MASTER_PORT=3306,

#  MASTER_USER='joe', MASTER_PASSWORD='secret';

#

# OR 或者

#

# 2) Set the variables below. However, in case you choose this method, then

#  start replication for the first time (even unsuccessfully, for example

#  if you mistyped the password in master-password and the slave fails to

#  connect), the slave will create a master.info file, and any later

#  changes in this file to the variable values below will be ignored and

#  overridden by the content of the master.info file, unless you shutdown

#  the slave server, delete master.info and restart the slaver server.

#  For that reason, you may want to leave the lines below untouched

#  (commented) and instead use CHANGE MASTER TO (see above)

#

#设置以下的变量. 不论如何, 在你选择这种方法的情况下, 然后第一次启动复制(甚至不成功的情况下,

# 例如如果你输入错密码在master-password字段并且slave无法连接),

# slave会创建一个 master.info 文件,并且之后任何对于包含在此文件内的参数的变化都会被忽略

# 并且由 master.info 文件内的内容覆盖, 除非你关闭slave服务, 删除 master.info 并且重启slave 服务.

# 由于这个原因,你也许不想碰一下的配置(注释掉的) 并且使用 CHANGE MASTER TO (查看上面) 来代替

# required unique id between 2 and 2^32 - 1

# (and different from the master)

# defaults to 2 if master-host is set

# but will not function as a slave if omitted

# 所需要的唯一id号位于 2 和 2^32 – 1之间

# (并且和master不同)

# 如果master-host被设置了.则默认值是2

# 但是如果省略,则不会生效

#server-id = 2

#

# The replication master for this slave – required

# 复制结构中的master – 必须

#master-host = <hostname>

#

# The username the slave will use for authentication when connecting

# to the master – required

# 当连接到master上时slave所用来认证的用户名 – 必须

#master-user = <username>

#

# The password the slave will authenticate with when connecting to

# the master – required

# 当连接到master上时slave所用来认证的密码 – 必须

#master-password = <password>

#

# The port the master is listening on.

# optional - defaults to 3306

# master监听的端口.

# 可选 – 默认是3306

#master-port = <port>

# Make the slave read-only. Only users with the SUPER privilege and the

# replication slave thread will be able to modify data on it. You can

# use this to ensure that no applications will accidently modify data on

# the slave instead of the master

# 使得slave只读.只有用户拥有SUPER权限和在上面的slave线程能够修改数据.

# 你可以使用此项去保证没有应用程序会意外的修改slave而不是master上的数据

#read_only

#*** MyISAM Specific options

#*** MyISAM 相关选项

# Size of the Key Buffer, used to cache index blocks for MyISAM tables.

# Do not set it larger than 30% of your available memory, as some memory

# is also required by the OS to cache rows. Even if you're not using

# MyISAM tables, you should still set it to 8-64M as it will also be

# used for internal temporary disk tables.

# 关键词缓冲的大小, 一般用来缓冲MyISAM表的索引块.

# 不要将其设置大于你可用内存的30%,

# 因为一部分内存同样被OS用来缓冲行数据

# 甚至在你并不使用MyISAM 表的情况下, 你也需要仍旧设置起 8-64M 内存由于它同样会被内部临时磁盘表使用.

key_buffer_size = 32M

# MyISAM uses special tree-like cache to make bulk inserts (that is,

# INSERT ... SELECT, INSERT ... VALUES (...), (...), ..., and LOAD DATA

# INFILE) faster. This variable limits the size of the cache tree in

# bytes per thread. Setting it to 0 will disable this optimisation. Do

# not set it larger than "key_buffer_size" for optimal performance.

# This buffer is allocated when a bulk insert is detected.

# MyISAM 使用特殊的类似树的cache来使得突发插入

# (这些插入是,INSERT … SELECT, INSERT … VALUES (…), (…), …, 以及 LOAD DATA

# INFILE) 更快. 此变量限制每个进程中缓冲树的字节数.

# 设置为 0 会关闭此优化.

# 为了最优化不要将此值设置大于 “key_buffer_size”.

# 当突发插入被检测到时此缓冲将被分配.

bulk_insert_buffer_size = 64M

# This buffer is allocated when MySQL needs to rebuild the index in

# REPAIR, OPTIMIZE, ALTER table statements as well as in LOAD DATA INFILE

# into an empty table. It is allocated per thread so be careful with

# large settings.

# 此缓冲当MySQL需要在 REPAIR, OPTIMIZE, ALTER 以及 LOAD DATA INFILE 到一个空表中引起重建索引时被分配.

# 这在每个线程中被分配.所以在设置大值时需要小心.

myisam_sort_buffer_size = 128M

# The maximum size of the temporary file MySQL is allowed to use while

# recreating the index (during REPAIR, ALTER TABLE or LOAD DATA INFILE.

# If the file-size would be bigger than this, the index will be created

# through the key cache (which is slower).

# MySQL重建索引时所允许的最大临时文件的大小 (当 REPAIR, ALTER TABLE 或者 LOAD DATA INFILE).

# 如果文件大小比此值更大,索引会通过键值缓冲创建(更慢)

myisam_max_sort_file_size = 10G

# If a table has more than one index, MyISAM can use more than one

# thread to repair them by sorting in parallel. This makes sense if you

# have multiple CPUs and plenty of memory.

# 如果一个表拥有超过一个索引, MyISAM 可以通过并行排序使用超过一个线程去修复他们.

# 这对于拥有多个CPU以及大量内存情况的用户,是一个很好的选择.

myisam_repair_threads = 1

# Automatically check and repair not properly closed MyISAM tables.

# 自动检查和修复没有适当关闭的 MyISAM 表.

myisam_recover

# *** INNODB Specific options ***

# *** INNODB 相关选项 ***

# Use this option if you have a MySQL server with InnoDB support enabled

# but you do not plan to use it. This will save memory and disk space

# and speed up some things.

# 如果你的MySQL服务包含InnoDB支持但是并不打算使用的话,

# 使用此选项会节省内存以及磁盘空间,并且加速某些部分

#skip-innodb

# Additional memory pool that is used by InnoDB to store metadata

# information. If InnoDB requires more memory for this purpose it will

# start to allocate it from the OS. As this is fast enough on most

# recent operating systems, you normally do not need to change this

# value. SHOW INNODB STATUS will display the current amount used.

# 附加的内存池被InnoDB用来保存 metadata 信息

# 如果InnoDB为此目的需要更多的内存,它会开始从OS这里申请内存.

# 由于这个操作在大多数现代操作系统上已经足够快, 你一般不需要修改此值.

# SHOW INNODB STATUS 命令会显示当先使用的数量.

innodb_additional_mem_pool_size = 16M

# InnoDB, unlike MyISAM, uses a buffer pool to cache both indexes and

# row data. The bigger you set this the less disk I/O is needed to

# access data in tables. On a dedicated database server you may set this

# parameter up to 80% of the machine physical memory size. Do not set it

# too large, though, because competition of the physical memory may

# cause paging in the operating system. Note that on 32bit systems you

# might be limited to 2-3.5G of user level memory per process, so do not

# set it too high.

# InnoDB使用一个缓冲池来保存索引和原始数据, 不像 MyISAM.

# 这里你设置越大,你在存取表里面数据时所需要的磁盘I/O越少.

# 在一个独立使用的数据库服务器上,你可以设置这个变量到服务器物理内存大小的80%

# 不要设置过大,否则,由于物理内存的竞争可能导致操作系统的换页颠簸.

# 注意在32位系统上你每个进程可能被限制在 2-3.5G 用户层面内存限制,

# 所以不要设置的太高.

innodb_buffer_pool_size = 2G

# InnoDB stores data in one or more data files forming the tablespace.

# If you have a single logical drive for your data, a single

# autoextending file would be good enough. In other cases, a single file

# per device is often a good choice. You can configure InnoDB to use raw

# disk partitions as well - please refer to the manual for more info

# about this.

# InnoDB 将数据保存在一个或者多个数据文件中成为表空间.

# 如果你只有单个逻辑驱动保存你的数据,一个单个的自增文件就足够好了.

# 其他情况下.每个设备一个文件一般都是个好的选择.

# 你也可以配置InnoDB来使用裸盘分区 – 请参考手册来获取更多相关内容

innodb_data_file_path = ibdata1:10M:autoextend

# Set this option if you would like the InnoDB tablespace files to be

# stored in another location. By default this is the MySQL datadir.

# 设置此选项如果你希望InnoDB表空间文件被保存在其他分区.

# 默认保存在MySQL的datadir中.

#innodb_data_home_dir = <directory>

# Number of IO threads to use for async IO operations. This value is

# hardcoded to 8 on Unix, but on Windows disk I/O may benefit from a

# larger number.

# 用来同步IO操作的IO线程的数量. This value is

# 此值在Unix下被硬编码为8,但是在Windows磁盘I/O可能在一个大数值下表现的更好.

innodb_write_io_threads = 8

innodb_read_io_threads = 8

# If you run into InnoDB tablespace corruption, setting this to a nonzero

# value will likely help you to dump your tables. Start from value 1 and

# increase it until you're able to dump the table successfully.

# 如果你发现InnoDB表空间损坏, 设置此值为一个非零值可能帮助你导出你的表.

# 从1开始并且增加此值知道你能够成功的导出表.

#innodb_force_recovery=1

# Number of threads allowed inside the InnoDB kernel. The optimal value

# depends highly on the application, hardware as well as the OS

# scheduler properties. A too high value may lead to thread thrashing.

# 在InnoDb核心内的允许线程数量.

# 最优值依赖于应用程序,硬件以及操作系统的调度方式.

# 过高的值可能导致线程的互斥颠簸.

innodb_thread_concurrency = 16

# If set to 1, InnoDB will flush (fsync) the transaction logs to the

# disk at each commit, which offers full ACID behavior. If you are

# willing to compromise this safety, and you are running small

# transactions, you may set this to 0 or 2 to reduce disk I/O to the

# logs. Value 0 means that the log is only written to the log file and

# the log file flushed to disk approximately once per second. Value 2

# means the log is written to the log file at each commit, but the log

# file is only flushed to disk approximately once per second.

# 如果设置为1 ,InnoDB会在每次提交后刷新(fsync)事务日志到磁盘上,

# 这提供了完整的ACID行为.

# 如果你愿意对事务安全折衷, 并且你正在运行一个小的食物, 你可以设置此值到0或者2来减少由事务日志引起的磁盘I/O

# 0代表日志只大约每秒写入日志文件并且日志文件刷新到磁盘.

# 2代表日志写入日志文件在每次提交后,但是日志文件只有大约每秒才会刷新到磁盘上.

innodb_flush_log_at_trx_commit = 1

# Speed up InnoDB shutdown. This will disable InnoDB to do a full purge

# and insert buffer merge on shutdown. It may increase shutdown time a

# lot, but InnoDB will have to do it on the next startup instead.

# 加速InnoDB的关闭. 这会阻止InnoDB在关闭时做全清除以及插入缓冲合并.

# 这可能极大增加关机时间, 但是取而代之的是InnoDB可能在下次启动时做这些操作.

#innodb_fast_shutdown

# The size of the buffer InnoDB uses for buffering log data. As soon as

# it is full, InnoDB will have to flush it to disk. As it is flushed

# once per second anyway, it does not make sense to have it very large

# (even with long transactions).

# 用来缓冲日志数据的缓冲区的大小.

# 当此值快满时, InnoDB将必须刷新数据到磁盘上.

# 由于基本上每秒都会刷新一次,所以没有必要将此值设置的太大(甚至对于长事务而言)

innodb_log_buffer_size = 8M

# Size of each log file in a log group. You should set the combined size

# of log files to about 25%-100% of your buffer pool size to avoid

# unneeded buffer pool flush activity on log file overwrite. However,

# note that a larger logfile size will increase the time needed for the

# recovery process.

# 在日志组中每个日志文件的大小.

# 你应该设置日志文件总合大小到你缓冲池大小的25%~100%

# 来避免在日志文件覆写上不必要的缓冲池刷新行为.

# 不论如何, 请注意一个大的日志文件大小会增加恢复进程所需要的时间.

innodb_log_file_size = 256M

# Total number of files in the log group. A value of 2-3 is usually good

# enough.

# 在日志组中的文件总数.

# 通常来说2~3是比较好的.

innodb_log_files_in_group = 3

# Location of the InnoDB log files. Default is the MySQL datadir. You

# may wish to point it to a dedicated hard drive or a RAID1 volume for

# improved performance

# InnoDB的日志文件所在位置. 默认是MySQL的datadir.

# 你可以将其指定到一个独立的硬盘上或者一个RAID1卷上来提高其性能

#innodb_log_group_home_dir

# Maximum allowed percentage of dirty pages in the InnoDB buffer pool.

# If it is reached, InnoDB will start flushing them out agressively to

# not run out of clean pages at all. This is a soft limit, not

# guaranteed to be held.

# 在InnoDB缓冲池中最大允许的脏页面的比例.

# 如果达到限额, InnoDB会开始刷新他们防止他们妨碍到干净数据页面.

# 这是一个软限制,不被保证绝对执行.

innodb_max_dirty_pages_pct = 90

# The flush method InnoDB will use for Log. The tablespace always uses

# doublewrite flush logic. The default value is "fdatasync", another

# option is "O_DSYNC".

# InnoDB用来刷新日志的方法.

# 表空间总是使用双重写入刷新方法

# 默认值是 “fdatasync”, 另一个是 “O_DSYNC”.

#innodb_flush_method=O_DSYNC

# How long an InnoDB transaction should wait for a lock to be granted

# before being rolled back. InnoDB automatically detects transaction

# deadlocks in its own lock table and rolls back the transaction. If you

# use the LOCK TABLES command, or other transaction-safe storage engines

# than InnoDB in the same transaction, then a deadlock may arise which

# InnoDB cannot notice. In cases like this the timeout is useful to

# resolve the situation.

# 在被回滚前,一个InnoDB的事务应该等待一个锁被批准多久.

# InnoDB在其拥有的锁表中自动检测事务死锁并且回滚事务.

# 如果你使用 LOCK TABLES 指令, 或者在同样事务中使用除了InnoDB以外的其他事务安全的存储引擎

# 那么一个死锁可能发生而InnoDB无法注意到.

# 这种情况下这个timeout值对于解决这种问题就非常有帮助.

innodb_lock_wait_timeout = 120

[mysqldump]

# Do not buffer the whole result set in memory before writing it to

# file. Required for dumping very large tables

# 不要在将内存中的整个结果写入磁盘之前缓存. 在导出非常巨大的表时需要此项

quick

max_allowed_packet = 16M

[mysql]

no-auto-rehash

# Only allow UPDATEs and DELETEs that use keys.

# 仅仅允许使用键值的 UPDATEs 和 DELETEs .

#safe-updates

[myisamchk]

key_buffer_size = 512M

sort_buffer_size = 512M

read_buffer = 8M

write_buffer = 8M

[mysqlhotcopy]

interactive-timeout

[mysqld_safe]

# Increase the amount of open files allowed per process. Warning: Make

# sure you have set the global system limit high enough! The high value

# is required for a large number of opened tables

# 增加每个进程的可打开文件数量.

# 警告: 确认你已经将全系统限制设定的足够高!

# 打开大量表需要将此值设大

open-files-limit = 8192

下载MySQL

1、解压后在根目录下新建my.ini文件,内容如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

[mysql]

# 设置mysql客户端默认字符集

default``-character-``set``=utf8

[mysqld]

# 设置3306端口

port = 3306

# 设置mysql的安装目录

basedir=D:\Tool\mysql-8.0.16-winx64

# 设置 mysql数据库的数据的存放目录,MySQL 8+ 不需要以下配置,系统自己生成即可,否则有可能报错

# datadir=C:\\web\\sqldata

# 允许最大连接数

max_connections=20

# 服务端使用的字符集默认为8比特编码的latin1字符集

character-``set``-server=utf8

# 创建新表时将使用的默认存储引擎

default``-storage-engine=INNODB

2、使用管理员打开cmd 

1

2

--初始化数据库

mysqld --initialize --console

注意:这里个人建议配置MySQL的环境变量,这样也方便以后的操作。

执行完成后,输出root用户初始化默认密码。 默认密码是 root@localhost 后面的那一串含有字母数字下滑线的字符

3、安装MySQL

4、启动MySQL

5、登录

6、修改初始化密码

1

2

3

--修改初始化密码.

--使用 root 账户登录后。

alter user root@localhost identified by '123'``;

MySQL-5.5.32是Mysql5.5系列中最后一个版本,也是最后一个有配置文件的版本,为什么这么说呢,用过5.6的博友都知道,在mysql5.6中已经不提供配置文件选择,只有一个默认的配置文件,好了,我们今天说的是5.5.32这个版,就不和大家说5.6了,下面我们来具体说一下,mysql5.5.32中,提供可选的几个配置文件,

  • my-small.cnf
  • my-medium.cnf
  • my-large.cnf
  • my-huge.cnf
  • my-innodb-heavy-4G.cnf

1.my-small.cnf

1
2
3
4
5
[root@mysql support-files]




这是my-small.cnf配置文件中开头的简介,它说明了,这个配置文件是在内存小于等于64M时使用的,小型数据库系统,目的是不占更多的系统资源!

2.my-medium.cnf

1
2
3
4
5
[root@mysql support-files]




这个配置文件是中型数据系统使用,内存在128M左右!

3.my-large.cnf

1
2
3
4
[root@mysql support-files]



这个配置文件是大型数据库系统使用,内存在512M左右!

4.my-huge.cnf

1
2
3
4
[root@mysql support-files]



这个配置文件是巨型数据库系统使用,内存在1G-2G左右!

5.my-innodb-heavy-4G.cnf

1
2
3
4
5
6
7
8
[root@mysql support-files]







这个配置文件主要作用是,支持4G内存,支持InnoDB引擎,支持事务(ACID)等特性所使用!
说明:ACID,指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)!

6.总结

从上面的说明我们可以出,基本是通过内存大小来选择mysql的配置文件的,那有博友会说了,现在的服务器动不动就是32G内存或者64G内存,甚至更大的内存,你那个配置文件最大只支持4G内存是不是有点小了,确认会有这样的问题,从mysql5.6以后,为了更大的发挥mysql的性能,已经去除了配置文件选择,只有一个默认的配置文件,里面只有一些基本配置,所有设置管理员都可以根据自己实际的需求进行自行设置,好了说了这么多,我们就来说一说,在企业的用的最多的my-innodb-heavy-4G.cnf配置文件!

1.详细说明

注:下面是my-innodb-heavy-4G.cnf默认配置我没有做任何修改,下面我们就来详细的说一说!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
[root@mysql support-files]






























注意只有MySQL附带的客户端应用程序保证可以读取这段内容,如果你想你自己的MySQL应用程序获取这些值,需要在MySQL客户端库初始化的时候指定这些选项
[client]

port = 3306
socket = /tmp/mysql.sock




[mysqld]

port = 3306
socket = /tmp/mysql.sock













back_log = 50




















max_connections = 100










max_connect_errors = 10








table_open_cache = 2048














max_allowed_packet = 16M













binlog_cache_size = 1M





max_heap_table_size = 64M



read_buffer_size = 2M





read_rnd_buffer_size = 16M









sort_buffer_size = 8M










join_buffer_size = 8M











thread_cache_size = 8








thread_concurrency = 8














query_cache_size = 64M





query_cache_limit = 2M








ft_min_word_len = 4











default-storage-engine = MYISAM










thread_stack = 192K



transaction_isolation = REPEATABLE-READ







tmp_table_size = 64M






log-bin=mysql-bin


binlog_format=mixed




























slow_query_log






long_query_time = 2








server-id = 1




















































































key_buffer_size = 32M












bulk_insert_buffer_size = 64M






myisam_sort_buffer_size = 128M






myisam_max_sort_file_size = 10G





myisam_repair_threads = 1


myisam_recover


















innodb_additional_mem_pool_size = 16M














innodb_buffer_pool_size = 2G










innodb_data_file_path = ibdata1:10M:autoextend










innodb_write_io_threads = 8
innodb_read_io_threads = 8












innodb_thread_concurrency = 16













innodb_flush_log_at_trx_commit = 1













innodb_log_buffer_size = 8M









innodb_log_file_size = 256M




innodb_log_files_in_group = 3













innodb_max_dirty_pages_pct = 90



















innodb_lock_wait_timeout = 120
[mysqldump]



quick
max_allowed_packet = 16M
[mysql]
no-auto-rehash



[myisamchk]
key_buffer_size = 512M
sort_buffer_size = 512M
read_buffer = 8M
write_buffer = 8M
[mysqlhotcopy]
interactive-timeout
[mysqld_safe]






open-files-limit = 8192

三、配置文件优化(根据实际情况优化)

说明,上文中我对my-innodb-heavy-4G.cnf中默认的所有选项进行了说明,下面我就根据我们公司的实际情况进行优化!

1.服务器的运行环境

  • 硬件服务器:Dell R710,双至强E5620 CPU、16G内存、6*500G硬盘
  • 操作系统:CentOS5.5 X86_64 系统
  • MySQL版本:MySQL 5.5.32
  • 适用于:日IP 100-200W ,日PV 200-500W 的站点

2.具体优化配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
[client] 
port = 3306
socket = /tmp/mysql.sock
default-character-set = utf8
[mysqld]

port = 3306
socket = /tmp/mysql.sock

character-set-server = utf8


back_log = 512

max_connections = 3000
max_connect_errors = 30
table_open_cache = 4096

max_allowed_packet = 32M
max_heap_table_size = 128M


read_buffer_size = 8M
read_rnd_buffer_size = 64M
sort_buffer_size = 16M
join_buffer_size = 16M


thread_cache_size = 16
thread_concurrency = 8
thread_stack = 512K


query_cache_size = 128M
query_cache_limit = 4M


ft_min_word_len = 8


default-storage-engine = INNODB
transaction_isolation = REPEATABLE-READ


tmp_table_size = 64M


log-bin=mysql-bin
binlog_cache_size = 4M
binlog_format=mixed


log_warnings


slow_query_log
long_query_time = 10

server-id = 1







key_buffer_size = 128M
bulk_insert_buffer_size = 256M
myisam_sort_buffer_size = 256M
myisam_max_sort_file_size = 10G
myisam_repair_threads = 1
myisam_recover



innodb_additional_mem_pool_size = 64M
innodb_buffer_pool_size = 6G
innodb_data_file_path = ibdata1:10M:autoextend

innodb_write_io_threads = 8
innodb_read_io_threads = 8

innodb_thread_concurrency = 16
innodb_flush_log_at_trx_commit = 2


innodb_log_buffer_size = 16M
innodb_log_file_size = 512M
innodb_log_files_in_group = 3

innodb_max_dirty_pages_pct = 90

innodb_lock_wait_timeout = 120
[mysqldump]
quick
max_allowed_packet = 32M
[mysql]
no-auto-rehash
[myisamchk]
key_buffer_size = 2048M
sort_buffer_size = 2048M
read_buffer = 32M
write_buffer = 32M
[mysqlhotcopy]
interactive-timeout
[mysqld_safe]
open-files-limit = 10240

3.总结

MySQL 配置文件的优化是根据线上环境的实际需要进行优化,不能随便没有根据的进行优化

4.MySQL状态查看的常用命令

  • mysql> show status; #显示状态信息
  • mysql> show variables; #显示系统变量
  • mysql> show engines; #查看所有引擎
  • mysql> show engine innodb status; #显示InnoDB存储引擎的状态

MySQL基于左右值编码的树形数据库表结构设计

在关系型数据库中设计树形的数据结构一直是一个十分考验开发者能力的,最常用的方案有主从表方案和继承关系(parent_id)方案。主从表方案的最大缺点是树形结构的深度扩展困难,一般来说都是固定的,适合深度固定的需求。继承关系方案设计和实现自然而然,非常直观和方便。缺点当然也是非常的突出:由于直接地记录了节点之间的继承关系,因此对Tree的任何 CRUD操作都将是低效的,这主要归根于频繁的“递归”操作,递归过程不断地访问数据库,每次数据库IO都会有时间开销。因此这种方案适合Tree规模相对较小的情况,我们可以借助于缓存机制来做优化,将Tree的信息载入内存进行处理,避免直接对数据库IO操作的性能开销。

理想中树形结构应该具备如下特征:检索遍历过程简单高效;节点增删改查CRUD操作高效;数据存储冗余度小、直观性强。笔者在查阅网上相关资料之后整理了一个基于左右值编码的树形结构的数据库表结构设计方案,并在MySQL数据库中实现。

首先我们记住以下这张图

图一 左右值属性结构

采用深度优先遍历给树中的每个节点分配两个值,一个左值和一个右值。节点左边的值比该节点的所有子孙节点值都要小,节点右边的值比该节点的所有子孙节点值都要大。例如:

B左边的值为2,其比Hell Mayes的所有子孙节点的值都要小(D[3,4]、E[5,10]、I[6,7]、J[8,9]、F[11,12])

B右边的值为13,其比Hell Mayes的所有子孙节点的值都要大(D[3,4]、E[5,10]、I[6,7]、J[8,9]、F[11,12])

有了这个规则整棵树的结构通过左值和右值存储了下来。

接下来我们在MySQL中建表,并实现整棵树的CURD方法

创建表结构

CREATE TABLE `tree` (

`node_id` int(11) NOT NULL AUTO_INCREMENT,

`name` varchar(45) DEFAULT NULL,

`lft` int(11) DEFAULT NULL,

`rgt` int(11) DEFAULT NULL,

PRIMARY KEY (`node_id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

插入数据

INSERT INTO `tree` VALUES

(1,’A’,1,20),

(2,’B’,2,13),

(3,’C’,14,19),

(4,’D’,3,4),

(5,’E’,5,10),

(6,’F’,11,12),

(7,’G’,15,16),

(8,’H’,17,18),

(9,’I’,6,7),

(10,’J’,8,9);

准备工作就绪。

1)获取某个节点的子孙节点

以B为例:

SELECT* FROM Tree WHERE Lft BETWEEN 2 AND 13 ORDER BY Lft ASC

图二 B的子孙节点

某个节点到底有多少的子孙节点呢?通过该节点的左、右值我们可以将其子孙节点圈进来,则子孙总数 = (右值 – 左值– 1) / 2,以B为例,其子孙总数为:(13–2 – 1) / 2 = 5。同时,为了更为直观地展现树形结构,我们需要知道节点在树中所处的层次,通过左、右值的SQL查询即可实现。以B为例:

SELECT COUNT(*) FROM Tree WHERE Lft <= 2 AND Rgt >=13

结果为2,表明B处于该树的第二层。为了方便描述,我们可以为Tree建立一个视图,添加一个层次字段,该字段值可以写一个自定义函数来计算,函数定义如下:

定义计算指定节点所在层的函数CountLayer

CREATE DEFINER=`root`@`localhost` FUNCTION `CountLayer`(p_node_id int) RETURNS int(11)

BEGIN

declare p_result,p_lft,p_rgt int default 0;

if exists (select 1 from tree where node_id=p_node_id) then

begin

select lft, rgt into p_lft, p_rgt from tree where node_id=p_node_id;

select count(*) into p_result from tree where lft <= p_lft and rgt >= p_rgt;

end;

return p_result;

end if;

RETURN 0;

END

函数名称为CountLayer,需传入指定节点的id。此时我们可以基于刚刚定义的层计算函数来创建一个包含层次字段的试图。

定义层次试图Tree_View

CREATE

ALGORITHM = UNDEFINED

DEFINER = `root`@`localhost`

SQL SECURITY DEFINER

VIEW `tree_view` AS

SELECT

`tree`.`node_id` AS `node_id`,

`tree`.`name` AS `name`,

`tree`.`lft` AS `lft`,

`tree`.`rgt` AS `rgt`,

COUNTLAYER(`tree`.`node_id`) AS `layer`

FROM

`tree`

ORDER BY `tree`.`lft`

图三 各节点所处的层次

此时我们来创建一个存储过程,用来获取给定节点的所有子孙节点和每个节点所在的层。

获取所有子孙节点的存储过程GetChildrenNodeList

CREATE DEFINER=`root`@`localhost` PROCEDURE `GetChildrenNodeList`(in p_node_id int)

BEGIN

declare p_lft,p_rgt int default 0;

if exists (select node_id from tree where node_id=p_node_id) then

begin

select lft,rgt into p_lft,p_rgt from tree where node_id=p_node_id;

select * from Tree_View where lft between p_lft and p_rgt order by layer, lft;

end;

end if;

END

查询B的所有子孙节点

call GetChildrenNodeList(2);

可以得到

图四 B的所有子孙节点及相应的层

可以计算其子孙节点,当让也可以计算其节点。

创建获取所有父节点的存储过程GetParentNodePath

CREATE DEFINER=`root`@`localhost` PROCEDURE `GetParentNodePath`(in p_node_id int)

BEGIN

declare p_lft,p_rgt int default 0;

if exists (select node_id from tree where node_id=p_node_id) then

begin

select lft,rgt into p_lft,p_rgt from tree where node_id=p_node_id;

select * from Tree_View where lft<p_lft and rgt>p_rgt order by layer,lft asc;

end;

end if;

END

以E节点为例:

call GetParentNodePath(5);

可以得到

图五 E的所有父节点

2)在某个节点下插入一个子节点。

仔细观察图一,我们以在H下添加一个节点K为例。K节点的左值为H节点的右值,K节点的右值为其左值+1,其他所有右值大于等于K的左值的节点的右值须+2,所有左值大于等于K的左值的节点的左值须+2。图示如下:

图六 新增节点

我们将其定义为存储过程:

添加节点的存储过程AddSubNode

CREATE DEFINER=`root`@`localhost` PROCEDURE `AddSubNode`(in p_node_id int,in p_node_name varchar(50))

BEGIN

declare p_rgt int default 0;

if exists(select node_id from tree where node_id=p_node_id) then

begin

SET AUTOCOMMIT=0;

START TRANSACTION;

select rgt into p_rgt from tree where node_id=p_node_id;

update tree set rgt=rgt+2 where rgt>=p_rgt;

update tree set lft=lft+2 where lft>=p_rgt;

insert into tree(name,lft,rgt) values(p_node_name,p_rgt,p_rgt+1);

COMMIT;

end;

end if;

END

调用AddSubNode存储过程

call AddSubNode(8,’K’);

图七 K节点成功插入

3)删除节点

删除节点是新增节点的逆向过程。

创建删除节点存储过程DelNode

CREATE DEFINER=`root`@`localhost` PROCEDURE `DelNode`(in p_node_id int)

BEGIN

declare p_lft,p_rgt int default 0;

if exists(select p_node_id from tree where node_id =p_node_id) then

START TRANSACTION;

select lft,rgt into p_lft,p_rgt from tree where node_id=p_node_id;

delete from tree where lft>=p_lft and rgt<=p_rgt;

update tree set lft=lft-(p_rgt - p_lft + 1) where lft > p_lft;

update tree set rgt=rgt-(p_rgt - p_lft + 1) where rgt > p_rgt;

COMMIT;

end if;

END

以删除C节点为例

call DelNode(3);

再次查询tree结果为:

图八 C及其所有的子节点都被删除

到此我们已将基于左右值编码的树形数据库表结构设计的基本原理介绍完了。当然,对于节点的操作还远不止这些,感兴趣的朋友可以自己动手实现。

诚然,这个方案也有其不足之处:节点的添加、删除及修改代价较大,将会涉及到表中多方面数据的改动。但是,在消除了递归操作的前提下实现了无限分组,而且查询条件是基于整形数字的比较,效率很高。所以,该方案比较实用与查询较多,变更不大的场景。

前言: Orleans 提供了构建大型分布式运算的应用程序框架,而不需要学习那些复杂的并发或者可拓展的模式。 它由微软研究院创建和维护,并且它已被一些微软产品组广泛应用于微软的Azure,以及其他一些公司。

Orleans 在2015年一月微软将其源代码开源,迅速得到开发者的认可,借助于活跃的社区和开发团队的贡献,框架不断的被完善和新功能的增加,微软研究院也将一直为该项目投资下去。

背景:云应用程序和服务本质上是并行的和分布式的。 他们也互动性和动态性,往往需要近实时的云实体之间的直接相互作用。 对于今天的程序构建来说这样的应用是非常困难的。 随着工作量的增长,通常需要昂贵的设计和架构的迭代,开发过程需要专家级的程序员。

今天大多数高性能应用程序是通过标准的SOA构建的,比如,亚马逊、google或者Facebook 一个简单页面的渲染展示,是通过数以百计的复杂的SOA服务协作和管理。 事实上,这样一个复杂的服务是很难通过一个服务来构建完成的。

SOA的模块化服务化、大数据、高并发已经服务动态分配和不间断的运行,不停的挑战程序员处理这些问题的能力,但是现有提供的这些工具或者框架不足以解决这些问题。

无状态的多层模型到存储层划分问题。 它经常需要在无状态层中进行缓存以获得可接受的性能,增加了复杂性,并引入了缓存一致性问题。

Actors: Actor 模型对细粒度的单个Actor对象的支持很好,每个Actor对象之间彼此孤立并且都是轻量级的,可以保证这些Actor独立建模。 他们通过异步消息传递,从而使Actor彼此直接沟通。

值得注意的是,一个Actor是在逻辑意义的单线程上执行,同时Actor的状态的封装和其他Actor之间的隔离,这大大的简化了Actor代码层面的复杂性,开发者使用的Actor不必担心临界区、互斥锁,锁的水准,和其他复杂的难以预测的问题,这些与实际应用程序逻辑是无关的,Actor是在可用的硬件资源池内动态创建的。 这使得Actors模型在负载均衡上比SOA的模块化分割更容易维护和拓展。

在过去的十年里,Erlang 一直是传统Actor模式的最流行的实现,面对上述SOA的挑战,业内重新审视Actor 模式,这促使出现了新的解决方案:Scala actors,Akka,DCell

Virtual Actors:

Orleans 是一种改进的Actors模式,大量借鉴了Erlang和分布式对象系统中的实现,添加静态类型,消息indirection 和Actors的虚拟化,将它们暴露在一个集成的编程模型中。

而Erlang是一个纯粹的函数式语言有其自己特定的虚拟机,Orleans 的编程模型,直接利用.NET 和面向对象的能力,它提供了一个框架,使复杂的分布式应用程序的开发更容易,并使所得到的应用程序的可扩展性更强。

不像其他系统如Erlang或Akka 的Actors , Orleans Grains 的Actors 是虚拟Actors。 他们通过异步消息传递,这大大不同于同步方法调用。

在Orleans 框架里 grains 的管理和激活类似于操作系统的虚拟内存管理,grain 的激活是通过创建一个服务端的copy ,如果后续它不再使用的时就自动变为未激活状态。

如果一个消息被发送到grain且在任何服务器上都没有激活状态的grain时,运行时管理器将自动创建一个新的grain,因为grains是虚拟的,所以他们永远不会失败,即使目前主机所有服务器激活失败。

这使得没必要测试是否有grain存在的必要性,以及故障跟踪;Orleans 运行时做这一切都是自动的。

更多的内容细节请阅读如下连接

Read the MSR Technical Report on Orleans

优点:

Orleans的优点有 1,提高开发人员的开发效率,即使不是专业开发人员。

2,不需要做太多的工作,默认支持很强的可拓展性。

下面详细讲解这些优点

开发人员的生产率

Orleans 的编程模型提供了以下关键的抽象,提出了专家和非专家的程序员的生产率,保证系统服务。

1.遵循面向对象的规范:Actor是实现声明的.net类,与Actors接口的异步方法,因此,开发人员可以把Actor的方法作为远程对象的方法直接调用。 透明地调用Actor的方法和故障的处理。

2.单线程执行:确保Actor只在一个线程上执行,与其他Actor的隔离,保证不用担心并发的问题,也不会担心使用数据共享而必须使用锁机制等问题,对于非专家程序员开发分布式程序变得更容易。

3.透明激活:只有当需要处理一个消息时,运行时才激活一个Actor,区分开了通过代码控制创建Actor引用 和通过物理内存激活Actor 的概念,这中机制在应用程序中是透明的,开发人员不需要关系一个Actor是如何创建的。 很多适合一个Actor的激活或者销毁,是由虚拟内存决定的。 应用程序不断轮训所有的“内存空间”的逻辑上创建的Actors,无论他们是在物理内存在任何特定的点。 Actor的生命周期是应用管理,此功能明显改善了传统Actor模型。

4.位置透明:通过Actor的对象引用来调用其他机器上的包含业务逻辑的Actor,在Orleans 运行时,这两个Actor之间是相互透明的。

如果应用程序找不到一个Actor,这有可能是当前这个Actor被垃圾回收了或者是还没有被激活。

5.透明集成持久化存储:Orleans 允许发布持久化到内存中的Actor的状态的映射,它同步更新确保成功持久化到内存中后可以获得一个正确的结果。

可以直接拓展或者更改现有持久化机制。

6.错误自动传播:运行时调用链上分布式的try/catch将未处理的错误与异常自动处理。 因此,错误不会在应用程序中丢失。 这允许开发人员在适当的地方放置错误处理逻辑,而无需在每个级别手动传播错误。

默认的透明的可扩展性

实践证明Orleans 编程模型 提供一个较低级别的系统功能就可以很轻易的实现开发人员的程序拓展和服务器拓展,下面详解在性能和拓展点上的关键点:

1.应用状态的细粒度的分割:

通过使用Actor作为直接寻址实体,程序员隐式地打破了他们的应用程序的整体状态,虽然orleans 没有明确指出如何划分一个大或者小的Actor模型,但是在大多数情况下,每一个自然程序实体代表一个Actor来多划分出更多的Actor来说是有好处的,比如一个用户账户、一个订单等等。 随着Actor被单独寻址,它们的物理逻辑在运行时被抽象出来了

2.自适应资源管理:假设在负载均衡和通信的请求不失败的情况下因为Actor位置的透明或者运行时的管理动态调整了硬件资源的配置 决定迁移整个计算集群的Actors,而相互通信的Actor之间没有彼此的位置,可以根据吞吐量的需要动态创建一个或多个运行时的演员特定的Actor副本,而无需对应用程序代码进行任何更改。

3.多路转换通信:在Orleans Actors的逻辑终结点(endpoints)和消息,他们之间是复用在一组固定的所有Tcp连接(TCP sockets),这使得主机一组数量庞大的Actors组的寻址不会影响到系统的性能,另外actors的激活和停用不会影响物理终结点的注册/注销的性能成本, 如TCP端口或HTTP URL,甚至关闭TCP连接。

4.高效的调度:大量单线程Actors的运行时的调度执行运行在每个处理器核心的的自定义线程池中,和用非阻断连续Actor的代码(在Orleans 的编程模型必须的)在一个高效协作多线程方式运行应用程序代码没有竞争。 这使得系统能够达到高吞吐量和大大提高了中央处理器的利用率(高达90%),具有极高的稳定性。

事实上,在系统中的Actor的数量的增长和负载不会导致额外的线程或其他操作系统有助于单个节点和整个系统的可扩展性。

5.显式同步:Orleans 的编程模式明确指导开发人员使用异步执行编写异步非阻塞代码的分布式应用程序,

Orleans 的编程模型使分布式应用程序的异步性和指导程序员编写的非阻塞异步代码,结合异步消息传递和高效调度,这使一个大程度的分布式并行性和整体吞吐量,没有明确的使用多线程。

Grains:

分布式的单位Grains(Actors)

并发是分布式应用程序固有的特点,这使得增加了它的复杂性,而Actor模型的特殊性和具有创造性的特点,使这样的事情变得简单了。

Actor以两种方式做到这一点:

1.通过提供单个线程访问一个Actor实例的内部状态。

2.除通过消息传递外,不在Actor实例之间共享数据。

Grains 是Orleans 应用程序的构建块,它们是彼此孤立的原子单位,分布的,持久的。 一个典型的grain是有状态和行为的一个单实例。

执行单元:单线程执行模型背后的原理是Actor(remote)轮流调用其方法。 如,从Actor A 到 Actor B的消息将被放置在一个队列中 ,当所有优先级比较高的服务处理完成才去调用队列相关的处理程序。 这使我们能够避免所有使用锁来保护Actor的状态,因为它本质上是保护,防止数据竞争。 然而,它也可能会出现一些问题,消息的循环传递。 如:如果A发送消息给B从它的一个方法,并等待它的完成,和B发送一个消息,也等待其完成,应用程序就将会出现死锁的问题。

Grains 激活-grain运行时实例

当运行一个grain的时候,Orleans 确保在一个Orleans silos 有一个grain的一个实例,当发现任何的silo中都没有一个grain的一个实例时,运行时就会创建一个,这个过程被称为激活。

如果使用的是一个已经持久化了的grain,运行时就自动去后台读取并激活,Orleans 控制着整个激活或者停用的过程,当编码一个grain时,开发人员假定所有的grain都是被激活的。

grain激活在块中执行工作,并在它移动到下一个之前完成每一个块。 大块的工作包括响应来自其他grain或外部客户请求的方法调用,并止于前一块完成关闭。 对应于一个工作块的基本的执行单元被称为一个turn。

在并行期间orleans 执行很多属于不同的激活的turn,每个激活是允许同时执行它的turns,这意味着没必要使用锁或者其他同步的方法去阻止数据的争夺和多线程的危险,如上所述,无论如何,预定关闭的truns的不可预测的交错,可能会导致grain的状态与计划关闭时时不同的,所以开发人员仍然需要注意交错错误。

激活模式

Orleans 支持两种模式:

1.单激活模式(默认):单激活模式(默认),创建每一个grain的同时激活。

2.无边界工作模式:创建自主激活的grain,以提高吞吐量。 “自主”意味着有相同grain不同的激活之间状态不一致。 因此,这种模式适合于无本地状态保留grain,或grain的本地状态是不变的,比如作为持久态的高速缓存grain

Silos:

Orleans silo 是一个主机服务,用来执行Orleans grains,它监听一个端口,用来监听从silo到silo的消息或者从其他客户端到silo的消息的,典型的silo就是,每台机器运行一个silo。

cluster:

大量的silos 同时在一起工作就形成了orleans的集群,orleans运行完全自动化的集群管理。

所有silo都使用一个动态更新的共享成员存储库,并有助于协调集群管理,通过阅读共享存储库了解对方的位置,在任何时候,一个silo可以通过注册在共享存储中连接到一个集群。

这种方式的集群可以在运行时动态扩展。 Orleans 提供弹性和可用性从群集中删除无效的silos。

对于Orleans 管理集群深入详细的文档,请阅读集群管理。

接下来我们看看Orleans框架客户端的使用 。

Clients:

Orleans 和客户端代码

Orleans 包括两个不同的部分:Orleans 基础部分(grains) 和客户端部分

Orleans 的一部分是由应用程序的运行时服务称silos grains 组成,在调度限制下的运行时执行的Grain代码和确保内部在Orleans 编程模型。

客户端部分通常是一个web前端,通过少量的Orleans 客户端库连接到Orleans 部分,使得客户端代码可以通过引用服务端的一个grain的引用进行通讯。

例如:一个ASP.NET web应用程序运行在服务端的部分可以是Orleans 的客户端。 客户端部分运行在.net 应用程序池的主线程中,和不受调度的限制和Orleans 运行时的保证。

下一步,我们将看看一个grains如何接收异步消息,或推送数据。

客户端观察者

有一种情况,其中一个简单的消息/响应模式是不够的,客户端需要接收异步通知。 例如,一个用户可能希望在一个新的即时消息发布的时候被一个朋友通知。

客户端观察者是一允许异步通知客户端的一种机制。 观察者是一个继承自IGrainObserver的单向异步接口,它的所有方法都的返回值必须是void。 grain 给这个观察者发送一个通知是通过调用这个接口的一个方法,除了它没有返回值,因此grain不需要依赖于结果,Orleans运行时将确保单项通知,grain 发布了这样的一个通知同时也提供了相应的add observers或者remove observers的 API。

另外,通常它也提供了一些使用的用来取消这些订阅的方法,Grain 开发者可以使用Orleans 的这个ObserverSubscriptionManager泛型类简化observed 的grain类型的开发。

订阅一个通知,客户端必须先创建一个实现了观察者接口的C#本地类的对象,它调用观察者工厂的方法(CreateObjectReference()),重定向到C#对象进入grain对象引用,然后可以将其传递给通知grain的订阅方法。

该模型也可以被其他grains用于接收异步通知。 不像在客户端订阅的情况,订阅grain只是实现Observer接口的一个面,并通过自身的引用(如:this. AsReference)

代码示例

假设我们有一个周期性发送信息给客户的grain,为简单起见,在我们的例子中的消息将是一个字符串。 我们首先定义客户端接收消息的的接口。

该接口将看起来像这样

1
2
3
4
public interface IChat : IGrainObserver
{
void ReceiveMessage(string message);
}
1
2
3
4
5
6
7
public class Chat : IChat
{
public void ReceiveMessage(string message)
{
Console.WriteLine(message);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class HelloGrain : Grain, IHello
{
private ObserverSubscriptionManager<IChat> _subsManager;

public override async Task OnActivateAsync()
{

_subsManager = new ObserverSubscriptionManager<IChat>();
await base.OnActivateAsync();
}


public async Task Subscribe(IChat observer)
{
_subsManager.Subscribe(observer);
}


public async Task UnSubscribe(IChat observer)
{
_SubsManager.Unsubscribe(observer);
}
}
1
2
3
4
5
public Task SendUpdateMessage(string message)
{
_SubsManager.Notify(s => s.ReceiveMessage(message));
return TaskDone.Done;
}
1
2
3
4
5
6
7
8

var friend = GrainClient.GrainFactory.GetGrain<IHello>(0);
Chat c = new Chat();


var obj = await GrainClient.GrainFactory.CreateObjectReference<IChat>(c);

await friend.Subscribe(obj);

常见问题:

微软是否支持orleans?

orleans的源代码已经在GitHub上的MIT许可下发布。 微软将继续投资在orleans和接受社区的代码贡献。

可以获的一个“启动”的License?

License 已经放在源代码releases 下

Orleans 适用于生产环境吗?

答案是肯定的

什么时候使用Grain 什么时候使用一个普通对象?

有两种方法来回答这个问题,运行时和建模的角度。

从运行时角度看:grain内创建的对象是不能远程调用,Grain 的位置透明在系统的任何位置都可以访问,这样他们就可以被自动放置或部署任何服务器,和当他们寄宿的服务器故障时可以重启。

从建模的角度看:在你的 Orleans-based应用程序中有四种基本的组件,通信接口、消息载体、grains和grains的数据保存,对象用户承载grains的数据,通信接口是一些有一定限制的常规接口。

仍然存在一些问题就是,在一个给定的系统中的实体应被建模为grain吗?

一般来说,你应该使用一个grain来模拟一个独立的实体,它有一个公开的通信接口与系统的其他组件,并有自己的生命周期,即,它可以独立存在于其他组件中。 例如,在社会网络中的一个用户是一个grain,而它的名字不是。 用户的新闻墙可能是一个grain,而它所接收到的消息的列表不是(因为墙是由其他用户访问,而列表的消息是一个私人数据)。 希望这个网站上的样本将有助于你识别一些模式,并看到你自己的场景的相似之处。

如何提高Grain 的高访问?

一个grain的吞吐量是有限的,它是运行在一个单线程中,因此,最好是避免设计一个单一的grain来接收不成比例的请求。

有各种各样的模式,有助于防止单一grain的超载,即使在逻辑上它是一个通信的中心点。

例如:如果grain是 一个 大量grains的 统计或者计数的聚合器,一个行之有效的方法是增加一个控制数量的中间聚合grains和分配每个报告的grains(使用module在key或hashcode)到中间聚合器,使负载或多或少均匀地分布在所有中间聚合器的grains,在他们的定期部分聚集到中央聚合器grains

如何取消或者是取消激活grain?

一般不需要强制一个grain失活,作为orleans运行时自动检测并关闭闲置激活的grain并回收系统资源。 在特殊的情况下,当你认为你需要立即使grain失活时,可以通过调用基类方法base. DeactivateOnIdle()。

我可以告诉orleans,在哪里激活grain吗?

它可以通过限制策略( restrictive placement strategies)来实现,但我们一般认为这是一个反模式,所以不建议。 如果你发现自己需要指定激活特定的silo grain,应该让你的系统来处理,这样就可以充分利用orleans框架。

通过解决这样的问题,表明应用程序承担了资源管理器的负担,而不一定有足够的信息系统的全局状态多的好。

可以多个数据中心独立部署吗?

orleans部署目前仅限于一个单一的数据中心。

我可以热部署grain添加或更新他们吗?

目前是不可以。

如何升级grains的版本?

orleans目前不支持即时更新grain代码。 要升级到新版本的grain代码,您需要提供并启动一个新的部署,切换过来,然后关闭旧部署。

云缓存服务中可以保存grain的状态吗?

它可以通过云存储,但是默认没有提供,你可以自己创建一个。

我可以从公共网络连接到orleans 的 slios?

orleans是托管服务的后端部分,你应该创建一个前端服务器的客户端连接到你的服务端。 它可以基于Web API项目,HTTP,Socket服务器,一个signalr服务器或其他东西。 你真的可以从Internet连接到orleans,但从安全的角度考虑,不是一个好的实践。

如果调用一个grain返回之前slio失败,会发生什么?

您将收到一个异常,您可以捕获和重试或做任何其他在您的应用程序逻辑中有意义的。 原文如下,

你会收到一个异常,您可以捕获和重试或做任何事情在你的应用程序逻辑中有意义的。奥尔良运行时没有立即重新创建从一个失败的筒仓谷物因为他们很多人可能并不需要立即或在所有。相反,运行时单独再现这种谷物,只有当一个新的请求到达特定的粮食。为每一粒它选择其中一个可用的筒仓作为一个新的主机。这种方法的好处是,只能对谷物的实际使用执行恢复过程,它传播的时空,跨越所有可用筒仓,从而提高了系统的响应和恢复的速度。还要注意是筒仓失败时的时间之间有延迟和奥尔良群集时检测到故障。延迟时间是检测的可配置速度和误报的可能性之间的折衷。在此过渡期间对粮食的所有调用会都失败,但后失败的检测粮食将会创建后一个新的呼吁,另一个筒仓,, 所以才会最终可用。可以找到更多的信息在这里

如果一个grain调用需要太多的时间来执行,会发生什么?

由于奥尔良使用合作多任务模型,它将不会自动抢占一粒执行但奥尔良为生成警告长执行粮食调用以便您可以检测到它们。合作多任务中有很多更好的吞吐量相比,抢占式多任务。你应该牢记那粒电话不应该执行任何长时间运行的任务,像 IO 同步和不应阻止对要完成的其他任务。所有的等待,应该是使用异步等待关键字或其他异步等待机制。谷物应该尽快返回,让其他谷物执行的最大吞吐量。

什么情况下分割用例(同时在多个silos中激活的同一个grain)?

这可以永远不会发生在正常操作过程中,每一粒会有且仅有一个实例每 id。唯一的一次发生这种情况是当筒仓崩溃时或如果被杀了不允许正确关机。在这种情况下,还有一粒可以存在多个筒仓中就有一个的窗口 30-60 秒 (根据配置) 是从系统中删除。从粮食 Id 到其激活 (实例) 地址的映射存储在分布式目录 (采用 DHT) 和每个筒仓拥有此目录分区。当会员各两个筒仓持有不同意见时,都可以请求创建的实例和作为一个结果。两个实例的粮食可能并存。一旦群集筒仓达成会员,其中一个实例将被停用,只有一个激活会生存。你可以了解更多有关如何奥尔良管理集群在群集管理页面。此外你可以看看奥尔良的更详细的信息,但是你不需要了解它完全能够编写您的应用程序代码。你只被需要考虑的在编写您的应用程序时有两个实例的演员罕见的可能性。

先决条件

Orleans 是一个.net 类库集,为了使用它,你需要.net 4.5.1 或者更高版本,开发工具集需要visual studio 2015 或者更高版本或者其他支持的开发工具,不支持Visual Studio的简化版本或者拓展包,但是你可以直接引用Orleans ,通过NuGet.

在生产环境中,Orleans 需要持久化存储,目前只支持一下技术产品之一:

Azure 就不多说了微软的云平台产品,当然就是要花钱买微软的云平台、云数据库了

SQL Server 

Zookeeper 这又是个什么东东呢,说起它那就得提到在大数据存储、大数据运算下大名鼎鼎的Hadoop 了,它是属于Hadoop项目下的一个子项目,用来存储数据的,具体详细你就问度娘吧。

MySQL 一个数据库

Consul 这是什么,不会吧,我孤陋寡闻了,从来没听说过这么高达上的东西,好吧,问度娘:

Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案,Consul的方案更”一站式”,内置了服务注册与发现框 架、分布一致性协议实现、健康检查、Key/Value存储、多数据中心方案,不再需要依赖其他工具(比如ZooKeeper等)。使用起来也较 为简单。Consul用Golang实现,因此具有天然可移植性(支持Linux、windows和Mac OS X);安装包仅包含一个可执行文件,方便部署,与Docker等轻量级容器可无缝配合。

注意:以上产品使用我们会在后续章节中用示例的方式给大家展示,就期待吧。

Orleans Tools for Visual Studio

说起来也多亏visual studio 这个集大成的开发工具,做的那么贴心,犹如毒品,难以戒掉:

正如一如既往的vs Orleans 也给我们提供了模版化的项目创建,我们只需要安装这个vs 插件,然后就可以在vs 中看到Orleans的项目模版了,

下载地址 Orleans Tools for Visual Studio

然后就是安装了,如果成功安装好了,启动vs 就可以看到如下结构

如上图所示:1 是安装好后Orleans 的一个模版集节点,选中后左边面板中会有三个项目模版。

2 是我们项目中一个服务的承载项目,这里是用来测试用的,所以是一个控制台应用程序,同时也将host所需的类库nuget进来了。

针对你项目的需要,可以是一个windows 服务,一个控制台应用,一个Windows forms 的程序,或者也可以寄宿到iis的web中。

3 是grain的实现 ,我们大部分时间就是与里面的东西打交道,它里面是一些实现了grain借口,或者业务类的一系列类集合。

4 是grain 接口定义处,为何要孤立出来呢,因为将来这些接口是要暴露出来让其他需要的地方调用吗。

好了,就介绍到这里吧,你可以去试试。

ETG.Orleans.Templates.VSIX

这个也是vs 插件,就不多啰嗦了,直接下载安装就ok

Orleans NuGet Packages

orleans(1.2.2) 包

在大多数情况下,有4个关键的NuGet包你需要使用:

Microsoft.Orleans.OrleansCodeGenerator.Build

1
PM> Install-Package Microsoft.Orleans.OrleansCodeGenerator.Build 

Microsoft.Orleans.Core

1
PM> Install-Package Microsoft.Orleans.Core

Microsoft.Orleans.Server

1
PM> Install-Package Microsoft.Orleans.Server

Microsoft.Orleans.Client

1
PM> Install-Package Microsoft.Orleans.Client

Microsoft.Orleans.OrleansServiceBus

1
PM> Install-Package Microsoft.Orleans.OrleansServiceBus

Microsoft.Orleans.OrleansHost

1
PM> Install-Package Microsoft.Orleans.OrleansHost

Microsoft.Orleans.OrleansAzureUtils

1
PM> Install-Package Microsoft.Orleans.OrleansAzureUtils

Microsoft.Orleans.OrleansProviders

1
PM> Install-Package Microsoft.Orleans.OrleansProviders

Microsoft.Orleans.CounterControl

1
PM> Install-Package Microsoft.Orleans.CounterControl

microsoft.orleans.server。

Microsoft.Orleans.OrleansManager

1
PM> Install-Package Microsoft.Orleans.OrleansManager

Microsoft.Orleans.OrleansConsulUtils

1
PM> Install-Package Microsoft.Orleans.OrleansConsulUtils

Microsoft.Orleans.OrleansZooKeeperUtils

1
PM> Install-Package Microsoft.Orleans.OrleansZooKeeperUtils

使用ZooKeeper为集群成员数据存储提供的一个插件

Microsoft.Orleans.TestingHost

1
PM> Install-Package Microsoft.Orleans.TestingHost

Microsoft.Orleans.OrleansCodeGenerator

1
PM> Install-Package Microsoft.Orleans.OrleansCodeGenerator

Microsoft.Orleans.OrleansTelemetryConsumers.AI

1
PM> Install-Package Microsoft.Orleans.OrleansTelemetryConsumers.AI

Microsoft.Orleans.OrleansTelemetryConsumers.NewRelic

1
PM> Install-Package Microsoft.Orleans.OrleansTelemetryConsumers.NewRelic

Microsoft.Orleans.Serialization.Bond

1
PM> Install-Package Microsoft.Orleans.Serialization.Bond

Bond 是一个扩展框架,用来处理系统化数据,特别适合用来处理与大数据存储和处理服务的通讯。

Bond 定义了一个丰富的类型系统和 schema 版本化规则,允许向前向后兼容。核心特性包括高性能序列化和反序列化,非常强大的通用数据传输机制。该框架是高可扩展性的,通过可插入式的序列化协议、数据流和用户定义的类型别名等。

此外 Bond 是语言和平台独立的,当前支持 C++、C# 和 Python 语言。

namespace Examples

{

using Bond;

using Bond.Protocols;

using Bond.IO.Safe;

class Program

{

static void Main()

{

var src = new Example

{

Name = "FooBar"``,

Constants = { 3.14, 6.28 }

};

var output = new OutputBuffer();

var writer = new CompactBinaryWriter<OutputBuffer>(output);

Serialize.To(writer, src);

var input = new InputBuffer(output.Data);

var reader = new CompactBinaryReader<InputBuffer>(input);

var dst = Deserialize<Example>.From(reader);

}

}

}

开发一个Grain

在开发Grain之前请先阅读Grains 这篇文章

Grain 接口

Grains通过调用各自定义在接口中的方法相互作用,一个grain实现了事先定义好的一个或多个接口,grain接口中的方法必须返回Task(如果没有返回值) 或者Task(如果有类型返回值)

如下事例样本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

public interface IPlayerGrain : IGrainWithGuidKey
{
Task<IGameGrain> GetCurrentGame();
Task JoinGame(IGameGrain game);
Task LeaveGame(IGameGrain game);
}


public class PlayerGrain : Grain, IPlayerGrain
{
private IGameGrain currentGame;


public Task<IGameGrain> GetCurrentGame()
{
return Task.FromResult(currentGame);
}


public Task JoinGame(IGameGrain game)
{
currentGame = game;
Console.WriteLine("Player {0} joined game {1}", this.GetPrimaryKey(), game.GetPrimaryKey());
return TaskDone.Done;
}


public Task LeaveGame(IGameGrain game)
{
currentGame = null;
Console.WriteLine("Player {0} left game {1}", this.GetPrimaryKey(), game.GetPrimaryKey());
return TaskDone.Done;
}
}
1
2
  
IPlayerGrain player = GrainClient.GrainFactory.GetGrain<IPlayerGrain>(playerId);
1
2
 
IPlayerGrain player = GrainFactory.GetGrain<IPlayerGrain>(playerId);
1
2
3
4
5
6

Task joinGameTask = player.JoinGame(this);

await joinGameTask;

players.Add(playerId);
1
2
3
4
5
6
7
8
List<Task> tasks = new List<Task>();
ChirperMessage chirp = CreateNewChirpMessage(text);
foreach (IChirperSubscriber subscriber in Followers.Values)
{
tasks.Add(subscriber.NewChirpAsync(chirp));
}
Task joinedTask = Task.WhenAll(tasks);
await joinedTask;

TaskDone.Done Utility Property

有没有一个标准的方式返回一个void的返回值呢,答案是肯定的,Orleans 为我们定义一个助手类:TaskDone.Done

客户端开发

一旦我们定义好一个grain的接口并且有相应的实现类,我们就可以开始编写我们的客户端代码,引入相应的dll

  • Orleans.dll
  • OrleansRuntimeInterfaces.dll

几乎任何一个客户端都会涉及到grain 工厂方法的使用,使用这个方法通过一个特殊的Id来引用,正如已经提到的grain不能被显式创建或者销毁。

1
2
3
4
5
6
7
8
9
10
GrainClient.Initialize();


Guid playerId = new Guid("{2349992C-860A-4EDA-9590-000000000006}");
IPlayerGrain player = GrainClient.GrainFactory.GetGrain<IPlayerGrain>(playerId);

IGameGrain game = player.CurrentGame.Result;
var watcher = new GameObserver();
var observer = GrainClient.GrainFactory.CreateObjectReference<IGameObserver>(watcher);
await game.SubscribeForGameUpdates();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
namespace PlayerWatcher
{
class Program
{





static void Main(string[] args)
{
try
{
GrainClient.Initialize();


Guid playerId = new Guid("{2349992C-860A-4EDA-9590-000000000006}");
IPlayerGrain player = GrainClient.GrainFactory.GetGrain<IPlayerGrain>(playerId);
IGameGrain game = null;

while (game == null)
{
Console.WriteLine("Getting current game for player {0}...", playerId);

try
{
game = player.CurrentGame.Result;
if (game == null)
Thread.Sleep(5000);
}
catch (Exception exc)
{
Console.WriteLine("Exception: ", exc.GetBaseException());
}
}

Console.WriteLine("Subscribing to updates for game {0}...", game.GetPrimaryKey());


var watcher = new GameObserver();
game.SubscribeForGameUpdates(GrainClient.GrainFactory.CreateObjectReference<IGameObserver>(watcher)).Wait();



Console.WriteLine("Subscribed successfully. Press <Enter> to stop.");
Console.ReadLine();
}
catch (Exception exc)
{
Console.WriteLine("Unexpected Error: {0}", exc.GetBaseException());
}
}





private class GameObserver : IGameObserver
{

public void UpdateGameScore(string score)
{
Console.WriteLine("New game score: {0}", score);
}
}
}
}

运行应用程序
配置连接到Orleans
允许应用程序与外界交互的orleans grains,框架包括客户端库。此客户端程序库可能由桌面或移动应用程序使用,或由呈现交互式网页或公开Web服务接口的前端服务器使用。
客户端库提供了一个API编写异步客户端于orleans交互。一旦客户端库连接到orleans的网关,客户端可以发送邮件到grains,接收响应,通过观察者得到grain异步通知。

连接网关
建立一个连接,客户端通过调用GrainClient.Initialize(),他将连接到silo在配置文件(ClientConfiguration.xml )中指定的ip和端口,这个文件必须和
Orleans.dll放在同一个目录下,作为一种替代,你也可以通过编程的方式加载一个配置文件然后通过GrainClient.Initialize() 初始化来使用。
配置客户端
在客户端配置文件中(ClientConfiguration.xml),指定网关端点的ip和端口,它需要去匹配silo中配置文件(OrleansConfiguration.xml )中指定的网关

1
2
3
<ClientConfiguration xmlns="urn:orleans">
<Gateway Address="<IP address or host name of silo>" Port="30000" />
</ClientConfiguration>
1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<OrleansConfiguration xmlns="urn:orleans">
<Defaults>
<Networking Address="" Port="11111" />
<ProxyingGateway Address="" Port="30000" />
</Defaults>
</OrleansConfiguration>

grain 持久化
grain持久化目标
1.允许不同的grain类型使用不同的存储类型providers(一个用Azure 表,一个用SQL Azure )相同类型的存储提供程序,但具有不同的配置(两个使用Azure表,但一个使用存储帐户)。
2.允许存储提供程序实例配置可交换(例如,开发-测试-产品)只是配置文件的变化。
3.允许额外的存储供应商被写入后提供了一个框架,由orleans团队或其他人。
4.提供一个最小的生产级存储提供程序。
5.存储提供程序完全控制了在持久化支持存储中的数据状态数据的存储方式。
推论:Orleans没有提供一个全面的ORM的存储解决方案,但允在必要的时候许自定义存储提供程序支持指定一个ORM的要求。
grain 持久化API
Grain类型可以用两种方式中的一种声明:
1.拓展Grain 如果他们没有任何持久的状态,或如果他们将处理所有自己的持久状态,或者
2.Extend Grain<T> 如果他们有一些持久态,他们希望Orleans良运行时处理。 另外,通过拓展Grain grain类型自动选择Orleans框架的系统管理的持久化。

对于本节的其他部分,我们只会考虑选择 #2 / Grain<T> ,因为条件限制。Grain 状态存储
从Grain继承的grain类(其中T是从GrainState自动导出的存储数据类型)将从指定的存储中自动加载它们的状态。

Grain将标有[StorageProvider]特性指定用于读/写Grain状态的数据存储提供程序实例的命名。

1
2
3
4
5
[StorageProvider(ProviderName="store1")]
public class MyGrain<MyGrainState> ...
{
...
}
1
2
3
4
5
6
7
8
9
<OrleansConfiguration xmlns="urn:orleans">
<Globals>
<StorageProviders>
<Provider Type="Orleans.Storage.MemoryStorage" Name="DevStore" />
<Provider Type="Orleans.Storage.AzureTableStorage" Name="store1"
DataConnectionString="DefaultEndpointsProtocol=https;AccountName=data1;AccountKey=SOMETHING1" />
<Provider Type="Orleans.Storage.AzureBlobStorage" Name="store2"
DataConnectionString="DefaultEndpointsProtocol=https;AccountName=data2;AccountKey=SOMETHING2" />
</StorageProviders>

配置存储providers

AzureTableStorage

1
2
<Provider Type="Orleans.Storage.AzureTableStorage" Name="TableStore"
DataConnectionString="UseDevelopmentStorage=true" />
  • DataConnectionString="..." (强制) - Azure 存储连接字符串。
  • TableName="OrleansGrainState" (可选) - 表存储中使用的表名称,默认OrleansGrainState
  • DeleteStateOnClear="false" (可选) - 如果是true,当清除grain时记录被删除,否则将写入一个空记录,默认为false
  • UseJsonFormat="false" (可选) - 如果为true, 使用json序列化, 使用Orleans的二进制序列化, 默认 false
  • UseFullAssemblyNames="false" (可选) - (如果 UseJsonFormat="true") 如果为true则使用程序集全名,否则使用简单名, 默认为 false
  • IndentJSON="false" (可选) - (如果 UseJsonFormat="true") 如果为true压缩json序列化, 默认false

注:表存储限制,state不应该超过64kb

AzureBlobStorage

1
2
<Provider Type="Orleans.Storage.AzureTableStorage" Name="BlobStore"
DataConnectionString="UseDevelopmentStorage=true" />
  • DataConnectionString="..." (强制) - Azure 存储连接字符串。
  • ContainerName="grainstate" (可选) - 使用blob 存储容器, 默认 grainstate
  • UseFullAssemblyNames="false" (可选) - (如果 UseJsonFormat="true") 如果为true则使用程序集全名,否则使用简单名, 默认为 false
  • IndentJSON="false" (可选) - 如果为true压缩json序列化, 默认false

MemoryStorage

1
<Provider Type="Orleans.Storage.MemoryStorage" Name="MemoryStorage"  />
  • NumStorageGrains="10" (可选) -用于存储”状态“的grain数, 默认 10

ShardedStorageProvider

1
2
3
4
5
<Provider Type="Orleans.Storage.ShardedStorageProvider" Name="ShardedStorage">
<Provider />
<Provider />
<Provider />
</Provider>

任何写操作期间Orleans运行时将以grain状态数据对象的深层副本供自己使用。在重写的情况下,运行时可以使用优化规则和启发式,以避免在某些情况下,在某些情况下执行一些或所有的深拷贝,提供预期的逻辑隔离语义被保留。

Grain状态的读写操作的示例代码

为了加入Orleans的grain状态持久性机制,必须拓展Grain类。
上述定义中的T将被此grain的特定应用程序特定的grain状态类所取代;见下面的示例。
grain类也应该有一个[ storageprovider ]特性告诉运行时存储provider(实例)使用这种类型的grain。

1
2
3
4
5
6
7
8
9
10
11
public interface MyGrainState : GrainState
{
public int Field1 { get; set; }
public string Field2 { get; set; }
}

[StorageProvider(ProviderName="store1")]
public class MyPersistenceGrain : Grain<MyGrainState>, IMyPersistenceGrain
{
...
}

Grain State Read

在grain的OnActivateAsync()方法调用之前,grain 的读取状态将会自动发生,没有应用程序代码使使这种情况发生是必需的。要查看这个状态,可以通过grain 类的Grain.State属性。

Grain State Write

在对grain的内存状态作出适当的改变,grain应该调用base.writestateasync()方法将更改写入持久存储,通过定义在存储provider的grain。此方法是异步的,并返回一个Task。

1
2
3
4
5
public Task DoWrite(int val)
{
State.Field1 = val;
return base.WriteStateAsync();
}

Grain State Refresh

如果一个grain希望显式地重新从provider读取这个grain的最新状态,grain 应该调用base.ReadStateAsync() 方法,这将重新加载grain的状态从持久存储里,通过定义的存储provider的grain类型,在grain状态存储器复制以往任何将被覆盖和取代base.readstateasync()任务完成时。

1
2
3
4
5
public async Task<int> DoRead()
{
await base.ReadStateAsync();
return State.Field1;
}

Storage Provider Framework

有编写额外的持久化provider的服务提供程序接口 – IStorageProvider。持久性提供程序API包括读和写操作grainstate数据。

1
2
3
4
5
6
7
8
9
public interface IStorageProvider
{
Logger Log { get; }
Task Init();
Task Close();

Task ReadStateAsync(string grainType, GrainId grainId, GrainState grainState);
Task WriteStateAsync(string grainType, GrainId grainId, GrainState grainState);
}

Storage Provider Semantics

任何试图执行写操作时,存储provider检测ETag违反约束导致写的Task被终端,就使用Orleans.InconsistentStateException包装底层存储异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class InconsistentStateException : AggregateException
{

public string StoredEtag { get; private set; }

public string CurrentEtag { get; private set; }

public InconsistentStateException(
string errorMsg,
string storedEtag,
string currentEtag,
Exception storageException
) : base(errorMsg, storageException)
{
this.StoredEtag = storedEtag;
this.CurrentEtag = currentEtag;
}

public InconsistentStateException(string storedEtag, string currentEtag, Exception storageException)
: this(storageException.Message, storedEtag, currentEtag, storageException)
{ }
}

Data Mapping

个人存储provider必须决定如何最好地储存grain的状态–BLOB(各种格式/序列化格式)或列每场是显而易见的选择。

对于table的基本存储provider编码状态数据字段到使用orlenas二进制序列化单表列。

Application Bootstrapping within a Silo

当silos上线在应用程序需要运行一些“自动执行”功能的几种情况。

我们现在已经增加了支持这种自动运行功能通过配置“orleans silo provider”。例如:

1
2
3
4
5
6
7
8
<OrleansConfiguration xmlns="urn:orleans">
<Globals>
<BootstrapProviders>
<Provider Type="My.App.BootstrapClass1" Name="bootstrap1" />
<Provider Type="My.App.BootstrapClass2" Name="bootstrap2" />
</BootstrapProviders>
</Globals>
</OrleansConfiguration>
1
2
3
public void RegisterBootstrapProvider(string providerTypeFullName, string providerName, IDictionary<string, string> properties = null)

public void RegisterBootstrapProvider<T>(string providerName, IDictionary<string, string> properties = null) where T : IBootstrapProvider
1
2
3
4
Task Init(
string name,
IProviderRuntime providerRuntime,
IProviderConfiguration config)

Timers

描述:定时器是用来创建周期性grain的行为,不需要跨多个激活的grain实例。它本质上是一组.NET System.Threading.Timer 类,另外它是受单线程执行保护的grain激活。

每个激活可能有与它相关联的零或更多的计时器,运行时在激活的运行时上下文中执行每个定时程序。

用法:开始一个定时器,要使用 Grain.RegisterTimer 方法, 返回一个实现 IDisposable 引用的实例

1
protected IDisposable RegisterTimer(Func<object, Task> asyncCallback, object state, TimeSpan dueTime, TimeSpan period)
1
state  当执行
  • When activation collection is enabled, the execution of a timer callback does not change the activation’s state from idle to in use. This means that a timer cannot be used to postpone deactivation of otherwise idle activations.
  • The period passed to Grain.RegisterTimer is the amount of time that passes from the moment the Task returned by asyncCallback is resolved to the moment that the next invocation of asyncCallback should occur. This not only makes it impossible for successive calls to asyncCallback to overlap but also makes it so that the length of time asyncCallback takes to complete affects the frequency at whichasyncCallback is invoked. This is an important deviation from the semantics of System.Threading.Timer.
  • Each invocation of asyncCallback is delivered to an activation on a separate turn and will never run concurrently with other turns on the same activation. Note however, asyncCallback invocations are not delivered as messages and are thus not subject to message interleaving semantics. This means that invocations of asyncCallback should be considered to behave as if running on a reentrant grain with respect to other messages to that grain.

Reminders

提醒类似于定时器,但是有几个重要的区别

描述:

使用:

  • 提醒持续存在,并将继续触发在所有情况下(包括部分或全部集群重新启动)除非明确取消。
  • 提醒与一个grain,没有任何特定的激活.
  • If a grain has no activation associated with it and a reminder ticks, one will be created. e.g.: If an activation becomes idle and is deactivated, a reminder associated with the same grain will reactivate the grain when it ticks next.
  • Reminders are delivered by message and are subject to the same interleaving semantics as all other grain methods.
  • 提醒不应该被用于高频定时器,它们的周期应该在几分钟,几小时或几天内测量。

Configuration

 提醒,是持久的,依赖于存储到功能。您必须指定在提醒子系统功能之前使用的存储支持。提醒功能是通过在服务器端配置的systemstore元控制。它与Azure Table 或 SQL Server 存储一起协作。

1
2
<SystemStore SystemStoreType="AzureTable" /> OR
<SystemStore SystemStoreType="SqlServer" />
1
<ReminderService ReminderServiceType="ReminderTableGrain"/>
1
2
3
4
5
Task IRemindable.ReceiveReminder(string reminderName, TickStatus status)
{
Console.WriteLine("Thanks for reminding me-- I almost forgot!");
return TaskDone.Done;
}
1
protected Task<IOrleansReminder> RegisterOrUpdateReminder(string reminderName, TimeSpan dueTime, TimeSpan period)
  • reminderName 是一个唯一的标识,在grain上下文范围内。
  • dueTime 指定第一次提醒多久开始执行。
  • period 指定执行间隔。

由于激活的生命周期就是grain唯一的生命周期,所以你必须明确的取消,使用Grain.UnregisterReminder:

1
protected Task UnregisterReminder(IOrleansReminder reminder)
1
protected Task<IOrleansReminder> GetReminder(string reminderName)
  • It doesn’t matter (or is desirable) that the timer ceases to function if the activation is deactivated or failures occur.
  • If the resolution of the timer is small (e.g. reasonably expressible in seconds or minutes).
  • The timer callback can be started from Grain.OnActivateAsync or when a grain method is invoked.

2.这几种情况下使用提醒功能

  • When the periodic behavior needs to survive the activation and any failures.
  • To perform infrequent tasks (e.g. reasonably expressible in minutes, hours, or days).

组合提醒和定时器
You might consider using a combination of reminders and timers to accomplish your goal.
For example, if you need a timer with a small resolution that needs to survive across activations,
you can use a reminder that runs every five minutes, whose purpose is to wake up
a grain that restarts a local timer that may have been lost due to a deactivation.

Orleans Streams

Orleans v.1.0.0添加流扩展的编程模型支持,流扩展提供了一组抽象接口api,使它的流更简单和更强大的,流扩展允许开发人员以结构化的方式写操作在一系列事件上的应用程序。

流provider的可扩展性模型使得在广泛的现有的队列技术的编程模型兼容和方便,例如: Event Hubs,ServiceBusAzure Queues, 和 Apache Kafka. 而不必要写特殊代码或运行专用程序与这样的队列进行交互。

我为什么要关心?

如果你已经了解了一些关于流处理的技术如:Event HubsKafka,Azure Stream AnalyticsApache StormApache Spark Streaming, 和Reactive Extensions (Rx)

你可能会问你为什么要关心,为什么我们需要另一个流处理系统和Actor是如何相关的流?“Why Orleans Streams?”可以回答你的问题

编程模型

下面是一些Orleans 流编程模型原则:

  1. 在Orleans 的体系里 Orleans virtual actors, Orleans 流是虚拟的,也就是说,一个流总是存在的。它不是显式创建或销毁,它永远不会失败。
  2. 流的身份ID识别,这只是逻辑名称由GUID字符串表示。
  3. Orleans 流数据的生成将允许从时间和空间上减弱它们的依赖性。这意味着流的生产者和流的消费者可能会在不同的服务器上,在不同的时间,并将承受失败。
  4. Orleans 的流是轻量级和动态的,Orleans 流运行时的设计是处理高速大数据。
  5. Orleans 流是动态绑定的,Orleans 流运行时的设计处理的情况下,grain连接和断开流在一个较高的速度。
  6. Orleans 流运行时透明地管理流消费的生命周期。当应用程序订阅一个流,然后它将接收流的事件,即使是在出现故障。
  7. Orleans 流均匀分布在grain和 工作的客户端。

编程APIs

应用程序流访问APIs类似于众所周知的 Reactive Extensions (Rx) in .NET,通过使用 Orleans.Streams.IAsyncStream<T> 实现了Orleans.Streams.IAsyncObserver<T> 和 Orleans.Streams.IAsyncObservable<T> 的接口。
在下面的一个典型例子产生的一些数据,这是一个HTTP请求的服务在云中运行的请求。Orleans客户端运行在前端服务器接收HTTP调用和发布数据流匹配装置:

1
2
3
4
5
6
7
public async Task OnHttpCall(DeviceEvent deviceEvent)
{

IStreamProvider streamProvider = GrainClient.GetStreamProvider("myStreamProvider");
IAsyncStream<DeviceEventData> deviceStream = streamProvider.GetStream<DeviceEventData>(deviceEvent.DeviceId);
await chatStream.OnNextAsync(deviceEvent.Data);
}
1
2
3
4
5
6
7
8
9
public class ChatUser: Grain
{
public async Task JoinChat(string chatGroupName)
{
IStreamProvider streamProvider = base.GetStreamProvider("myStreamProvider");
IAsyncStream<string> chatStream = streamProvider.GetStream<string>(chatGroupName);
await chatStream.SubscribeAsync((string chatEvent) => Console.Out.Write(chatEvent));
}
}

Stream Providers

流可以通过各种形状和形式的物理信道,可以有不同的语义。

Orleans 流的设计是支持多种Stream Providers的概念,这是系统中的一个可拓展点,Orleans 目前提供两种Stream providers。

基本的Tcp 通信Simple Message Stream Provider和云队列Azure Queue Stream Provider,你可以在这里(Stream Providers)找到更消息的介绍

Stream 意义

Stream Subsription Semantics: Orleans Streams guarantee Sequential Consistency for Stream Subsription operations. Specificaly, when consumer subscribes to a stream, once the Task representing the subsription operation was successfuly resolved, the consumer will see all events that were generated after it has subscribed. In addition, Rewindable streams allow to subscribe from an arbitrary point in time in the past by using StreamSequenceToken (more details can be found here).

Individual Stream Events Delivery Guarantees: Individual event delivery guarantees depend on individual stream providers. Some provide only best-effort at-most-once delivery (such as Simple Message Streams), while others provide at-least-once delivery (such as Azure Queue Streams). It is even possible to build a stream provider that will guarantee exactly-once delivery (we don’t have such a provider yet, but it is possible to build one with the extensability model).

Events Delivery Order: Event order also depends on a particular stream provider. In SMS streams, the producer explicitelly controls the order of events seen by the consumer by controlling the way it publishes them. Azure Queue streams do not guarantee FIFO order, since the underlaying Azure Queues do not guarantee order in failure cases. Applications can also control their own stream delivery ordering, by usingStreamSequenceToken.

流实施

 Orleans Streams Implementation提供了一个高层次的内部实施概述。

Streams 的可拓展性

Orleans Streams Extensibility 描述如何用新的功能扩展流。

Code Samples

更多的例子:here.
更多的资料:

调试符号

在开发期间Orleans调试比较简单,直接附加进程,但是对于在生产环境来说,就无法断点调试了,采用跟踪是最好的办法。

标记(Symbols):

Symbols for Orleans binaries are published to https://nuget.smbsrc.net symbols server. Add it to the list of symbols server in the Visual Studio options under Debugging/Symbols for debugging Orleans code. Make sure there is traling slash in the URL. Visual Studio 2015 has a bug with parsing it.

Orleans之Hello World

接触Orleans 有一段时间了,之前也翻译了一系列官网文档,今天我们就来一个实际的例子,来看看到底如何用这个东西来开发项目,当然经典的也是醉人的,我们就从HelloWorld开始吧。

通过前面的知识准备我们知道Orleans 项目需要n个服务端(就是silohost),n个客户端(就是调用方),然后就是提供的actors(在Orleans 中成为grain),废话少说。

首先建立一个解决方案,叫做OrleansSamples

然后,增加一个模块解决方案,叫做HelloWorlds,在解决方案下增加两个类库Sample.Interfaces,Sample.Implements,其中Sample.Implements引用Sample.Interfaces,

这两个项目中引用Orleans的核心库,你可以手动一个一个引用进来,但还是老老实实的用nuget吧。

nuget的引用两种方式一种,通过图形化的方式,另一种通过命令的方式,命令:Install-Package Microsoft.Orleans.Core (注:在这里可以找到所需的包http://dotnet.github.io/orleans/NuGets)

记得引用完后如果在nuget里有更新就更新一下,对于新版本,可能里面有些库会没有进来,否则就会报错,反正我是这么做,做完这一切,项目结构如下:

在Sample.Interfaces中增加一个接口IUserService,并且继承接口IGrainWithIntegerKey(关于这个接口有姊妹接口,关于这些接口后续会陆续讲到)

代码如下:

复制代码

复制代码

namespace Sample.Interfaces
{
  public interface IUserService:IGrainWithIntegerKey
  {
    Task Exist(string mobileNumber);
  }
}

复制代码

复制代码

在Sample.Implements项目中增加实现类UserService,并且继承Grain(Grain这个基类同时也提供了相应的泛型实现Grain<>,关于他们的不同点,以及功能,后续会讲到),且实现IUserService接口

代码如下:

复制代码

复制代码

namespace Sample.Implements
{
  public class UserService : Grain, IUserService
  {
    public Task Exist(string mobileNumber)
    {
      return Task.FromResult(mobileNumber==”18612478956”);
    }
  }
}

复制代码

复制代码

好了到此为止,我们已经开发好actor虽然简单,接下来我们接着增加服务启动寄宿项(关于寄宿项,可以是控制台、windows服务、winfrom、asp.net ),这里我们采用控制台,下面我们创建一个服务控制台应用程序(Server)

引用上面创建两个项目:Sample.Implements、Sample.Interfaces。(注:其实这两个项目不一定要引用进来,只要在生成项目的目录下存在他们的编译好的dll即可,silo用来自动加载启动这个他们)

引用orleans项目中服务端的类库(使用nuget命令:Install-Package Microsoft.Orleans.Server

项目结构如下:

代码如下:

复制代码

复制代码

namespace Server
{
  class Program
  {
    static void Main(string[] args)
    {
      using (var host = new SiloHost(“Default”))
      {
        host.InitializeOrleansSilo();
        host.StartOrleansSilo();
        Console.WriteLine(“启动成功!”);
        Console.ReadLine();
        host.StopOrleansSilo();
      }
    }
  }
}

复制代码

复制代码

好一切准备就绪,我们F5吧,

当你看到这得时候是不是觉得成功了,真的成功了吗,不一定吧!

哦对了怎么没看到日志呢,好我们在项目目录下看看日志:

果然有日志文件,一看文件名称,直接告诉我们发生错误了,好让我们打开看看吧。

从发生的异常看出,好像少了一个配置文件,在orleans 服务启动时,需要一个配置文件,这个配置文件可以是OrleansConfiguration.xml或者orleans.config或者orleans.config.xml

好知道原因了,知道该怎么做了吧,在server根目录下创建一个xml文件OrleansConfiguration.xml,将该文件的属性“复制到输出目录”值更改为”如果较新则复制”

该文件中填充配置内容,如下(详细配置请看配置一节,此处不解释)

复制代码

复制代码

View Code

再次启动F5,当看到启动成功的输出时,我们再次看看生成的日志:

这次发现比之前生成的东西多了,但是当我们继续往下浏览的时候发现有个异常:

Exc level 0: System.IO.FileNotFoundException: 未能加载文件或程序集“Microsoft.Extensions.DependencyInjection.Abstractions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60”或它的某一个依赖项。系统找不到指定的文件。
在 Orleans.Runtime.Startup.ConfigureStartupBuilder.ConfigureStartup(String startupTypeName)
在 Orleans.Runtime.Startup.ConfigureStartupBuilder.Orleans.Runtime.Startup.IStartupBuilder.ConfigureStartup(String startupTypeName)
在 Orleans.Runtime.Silo..ctor(String name, SiloType siloType, ClusterConfiguration config, ILocalDataStore keyStore)

原来是少了程序集:Microsoft.Extensions.DependencyInjection

知道原因了,我们通过nuget来引用这个类库,引用成功,再次运行,然后查看日志,异常消失,但是有个问题,每次打开日志文件要看,是否有错误,或者一些关于服务的监控内容,这样是不是很麻烦,其实我们可以更改一下配置信息,让它输出到控制台,这样在开发过程中就方便多了,可以时时看到动态信息,如下:

打开OrleansConfiguration.xml 文件找到<Tracing DefaultTraceLevel=”Info” TraceToConsole=”false” TraceToFile=”{0}-{1}.log” 这个节点,将TraceToConsole的值更改为true保存,再次运行,如下:

好了一切都完美了,接下来我们在继续开发客户端。

在解决方案下创建一个控制台应用程序Client,引用客户端相关类库:Install-Package Microsoft.Orleans.Client

引用项目:Sample.Interfaces

代码如下:

复制代码

namespace Client
{
class Program
{
static void Main(string[] args)
{
System.Threading.Thread.Sleep(15000);
GrainClient.Initialize();

        while (true)
        {
            Console.WriteLine("请输入用户手机号:");
            var mobileNumber = Console.ReadLine();
            //这里由于我们采用的grain继承的是IGrainWithIntegerKey ,所以我们采用调用数值类型的key=10来创建这个grain,
            //可能有人会问key是干嘛的,他是唯一标识这个grain的,当你指定一个key的时候,Orleans 会创建一个,它首先到
            //你的存储介质中找(如果你配置了的话,默认采用内存存储,这种方式适合开发期,生产环境需要保持状态的,所以需要配置到能持久化存储的地方去,比如sqlserver等)
            //如果找到了就直接返回,如果没找到就根据你指定的这个key然后创建一个,这个就是grain的激活,具体详细的,可以看官方问的关于Grain一章。
            var userService = GrainClient.GrainFactory.GetGrain<IUserService>(10);
            //C#的一种新的表达式语法,这样就方便多了,省的我们拼接字符串。
            Console.WriteLine($"用户{mobileNumber},{(userService.Exist(mobileNumber).Result?"已经存在":"不存在")}");
        }

    }
}

}

复制代码

View Code

在client项目下记得要创建配置文件,文件名称叫做ClientConfiguration.xml

内容如下:

复制代码

复制代码

View Code

注:要记得更改文件属性哦

一切准备就绪,下来让改一下启动方式为多项目启动,然后就F5等待飞吧!

终于看到胜利的果实了,哈哈!接下来我们接着说说另外一种开发方式以及发布方式。

上面的这种开发方式为了说明开发的那些具体步骤,需要引用那些类库,以及客户端如何去调用,步骤比较麻烦,尤其是服务端的开发、引用类库,也没有相应的单元测试,接下来我们看看另外一种服务端的开发方式。

跟上面的大体步骤一样

1.创建接口类库

2.创建实现类库

3.开发测试服务寄宿程序

在开始之前首先要确认一下你是否安装了Orleans的vs模版插件,如果安装了那么如下图:

如果没有安装,赶紧去下载一个吧地址在:http://dotnet.github.io/orleans/NuGets

找到这一节,如下图:

点开里面有你想要的插件,然后安装重启vs

1.创建接口类库

2.创建实现类库

 

3.创建服务寄宿程序

服务创建完之后,发现下面有自动生成的一个类OrleansHostWrapper,并且在Program下自动生成了很多代码,代码的大体意思就是,将服务端启动程序的逻辑封装在OrleansHostWrapper,然后启动是单独创建一个应用程序域,增加一些测试例子代码,方便多了吧,我们不需要写任何服务端的服务启动代码,在实际开发过程中我们只需要关心业务模块

即接口创建,接口实现,方便多了吧。

将相应的代码贴入进去,还记得上面出现的那个异常吗,记得要将Microsoft.Extensions.DependencyInjection类库引用进来哦,F5吧。

一切如预期所料,成功!

接下来我们创建一个单元测试程序库,方便服务端的程序单元测试Sample.Test

引用项目Sample.Implements、Sample.Interfaces

1
引用Orleans测试包 PM> Install-Package Microsoft.Orleans.TestingHost

复制代码

[ClassCleanup]
public static void ClassCleanup()
{
// Optional.
// By default, the next test class which uses TestignSiloHost will
// cause a fresh Orleans silo environment to be created.
StopAllSilosIfRunning();
}

复制代码

View Code

测试代码如下:

复制代码

namespace Sample.Test
{
[TestClass]
public class UserServiceTest: TestingSiloHost
{
[ClassCleanup]
public static void ClassCleanup()
{
// Optional.
// By default, the next test class which uses TestignSiloHost will
// cause a fresh Orleans silo environment to be created.
StopAllSilosIfRunning();
}

    \[TestMethod\]
    public async void TestExist()
    {
        var grain = GrainFactory.GetGrain<IUserService>(10);
        bool bo = await grain.Exist("18612478956");
        Assert.IsTrue(bo);
    }
}

}

复制代码

View Code

记得增加两个配置文件,

ClientConfigurationForTesting.xml

复制代码

复制代码

View Code

OrleansConfigurationForTesting.xml

复制代码

复制代码

View Code

更改xml文件属性为:如果较新则复制

测试项目结构大体如下:

好,测试编写完成,如何操作你懂得,这里就不废话了。

 接下来说一下部署,部署吧,各有各的妙招,控制台、winform、windows服务等等,这里我说一个框架自带的一个部署控制台怎么用

记得Orleans 里面有这么一个程序OrleansHost.exe,他是干什么用的呢,对了就是用来部署的。

我们来看看他的源码,弄清楚他到底是做了一件什么事情

如下图:

打开这个文件,可以发现这个文件跟上面我们通过模版创建的server中的文件OrleansHostWrapper很相似,对了,这个就是为了保持开发部署的一致性,所以这个就可以用来直接部署了

我们在server的Debug下找到相应的程序,将程序复制到某个盘符比如D:\demo下面

如下图:

然后将配置文件拷贝进来OrleansConfiguration.xml

一切准备就绪,我们运行把,双击StartOrleans.cmd服务启动

运行成功.
你会发现这个服务部署于我们的开发互不影响,当我们开发好一个grain的时候,直接编译丢到这个部署目录下,别的地方就可以访问了,可以让我们重点关注业务逻辑,而不需要关心那些复杂的配置或者服务的开启关闭等等。

实例代码

 Orleans 之 监控工具的使用

这一节,我们来说说orleans 中的几个实用工具,OrleansHost、OrleansCounterControl、OrleansManager、ClientGenerator。

1.OrleansHost

这个工具是一个主机寄宿或者部署的一个控制台应用程序,下面我们看一下他的用法。

从那里获取呢,直接点的办法就是在源码包里找到这个项目然后编译后得到的就是你需要的。

另外一种就是当你创建服务端然后安装了Microsoft.Orleans.Server包的时候,编译这个项目也会在编译包下生成出来。

我是直接编译源码包得到,如下:

一些dll,值得注意的是那个Configuration包,里面有个文件OrleansConfiguration.xsd,这个就是服务端文件配置所需的xsd验证文件,如果我们不知道配置文件需要那些节点的时候

可以查看该文件,可以将其复制到你的vs安装目录的xml环境中,就可以获得智能提示了,如下:

C:\Program Files (x86)\Microsoft Visual Studio 14.0\Xml\Schemas

我的安装目录,如果你的安装目录有变,你可以灵活调整了

看图

然后我们在OrleansHost.exe所在目录下创建OrleansConfiguration.xml文件用vs打开

添加根节点OrleansConfiguration,然后增加xmlns=”urn:orleans”,我们就可以得到智能提示了,如下图

接下来,我们配置一个基本的配置文件,内容如下

复制代码

复制代码

View Code

好我们来运行一下这个看看,双击StartOrleans.cmd,程序跑完,有日志文件生成,大概浏览一遍,不太顺畅,有一些错误,少了一些dll的引用,少了OrleansCodeGenerator.dll,OrleansDependencyInjection.dll,再到源码包中直接生成该项目,然后将其生成产物拷贝到StartOrleans目录下,再次运行,一切如预料的那样,成功:

这里我整理的一个OrleansHost的部署包:OrleansHost

如有需要的可以直接下载使用。

再来看看他的一些使用的参数:

该工具有如下参数:/? 、/help、-?、-help、/debug、deploymentid=[value]、deploymentgroup=[value]。

这次我们先冲控制台进入该程序所在目录:

cmd-> d: -> cd D:\demo\OrleansHost  ,如下:

如果我们什么参数都不带,改程序就直接启动

如果下面我们带上如上参数看看效果:OrleansHost /? 这个是寻求帮助的一个命令

 OrleansHost /debug   这个是以调试环境启动

OrleansHost  deploymentid=[value] 这个是给部署的当前silo起一个部署时的名称然后启动(这里的value将来是设置为siloname的)

OrleansHost  deploymentgroup=[value]这个值暂时还没有启用,说不定后续版本会有用处

有个了这个工具我们直接将开发好的grain编译好的程序发布到该程序目录下就可以了,然后重启,不信你可以试一试,哈哈!

2.OrleansCounterControl

在于OrleansHost相同的目录下还有一个exe,就是OrleansCounterControl

如下图:

我们先用cmd进入该程序所在目录下

cd C:\Demo

接下来,我们先看看OrleansCounterControl有哪些参数

OrleansCounterControl /r,/register、/u、/unregister、/f、/force、/pause、/?、/help,我们来看看这些参数命令。

以管理员运行,如果OrleansCounterControl不带任何参数的时候,将运行服务端的一些序列化初始化,并输出一些控制台日志,且注册windows计数器

/r  或/register windows计数器注册

/u 或/unregister 取消windows计数器

/f 或 /force 删除计数器

/pause  是否有退出时提示

/? 或/help 帮助提示.

这些命令可以组合使用,如下图:OrleansCounterControl  /r  /pause

OrleansCounterControl  /r  /?

总结:这个工具用来进行管理程序的windows计数器管理工具.

3.OrleansManager

命令行定位到该程序目录下(此工具主要是用来在客户端,或者别的地方查看服务端上silo或者grain的一些状态信息。)

接下来看看命令参数:

OrleansManager [ ] [/?] [-?] 执行这个命令时会有一些帮助提示

OrleansManager grainstats [silo1,silo2,…] 用来查看统计查看silo的address、激活的数量、grain类型等。

             fullgrainstats [silo1,silo2,…] 查看全部的grain的状态

         collect  [silo1,silo2,…]  

        unregister [silo1,silo2,…] 取消注册

         lookup  [silo1,silo2,…]

        grainreport [silo1,silo2,…] 

具体就不再这里讲解了,大家在开发过程中可以去探索。

4.ClientGenerator

先来看看工具传入的参数

参数要用【””】 来包装字符串,字符串内的参数可以用多个用【;】来分割,每一段代表一个路径,绝对路径,或者网络服务地址。

具体参数使用如下:

/r:[path];[path];[path];[path]
/reference:[path];[path];[path];[path]    这个可以使用的是一个目录或者是一个文本文件内指定多个文件。

/in:[path] 如果是单个文件使用,如a.cs,或者b.cs 。

/bootstrap  
/boot

/sources:
/src:

就说到这里吧。

Module Zero学习目录 - tkbSimplest - 博客园

Excerpt

Module Zero是实现了ASP.NET Boilerplate框架抽象概念的模块,对于企业web应用也添加了一些有用的东西: 实现了ASP.NET Identity框架的用户和角色管理。 提供了基于授权(authorization)系统的角色和权限管理。 提供了开发多租户(multi tena


Module-Zero是实现了ASP.NET Boilerplate框架抽象概念的模块,对于企业web应用也添加了一些有用的东西:

  • 实现了ASP.NET Identity框架的用户和角色管理。
  • 提供了基于授权(authorization)系统的角色和权限管理。
  • 提供了开发多租户(multi-tenant)应用的基础设施。
  • 实现了ABP在数据库中存储租户,应用和用户水平设置的设置系统。
  • 实现了审计日志。
  • 实现了Session管理。

学习目录如下##

概览

安装###

启动模板

租户管理###

版本管理###

用户管理###

角色管理###

组织单元管理|【2016/1/24 13:50:16 新增】

权限管理###

语言管理###

Nuget安装包###

更改日志和发布


学习如何实践ABP框架,请移步至**《一步一步使用ABP框架搭建正式项目系列教程》**

ABP理论基础学习,请移步至**ABP框架理论研究总结(典藏版)**

翻译自:**点击查看**

如果您认为这篇文章还不错或者有所收获,您可以通过右边的“打赏”功能** 打赏我一杯咖啡【物质支持】,也可以点击右下角的【好文要顶】按钮【精神支持】,因为这两种支持都是我继续写作,分享的最大动力!**

**

声明:原创博客请在转载时保留原文链接或者在文章开头加上本人博客地址,如发现错误,欢迎批评指正。凡是转载于本人的文章,不能设置打赏功能,如有特殊需求请与本人联系!

**

**


已将所有赞助者统一放到单独页面!签名处只保留最近10条赞助记录!查看赞助者列表

衷心感谢打赏者的厚爱与支持!也感谢点赞和评论的园友的支持!
打赏者
微信:匿名
微信:匿名
微信:匿名
支付宝:一个名字499***@qq.com
微信:匿名
支付宝:向京刘
微信:匿名
微信:匿名
支付宝:lll20001155
支付宝:她是一个弱女子

**

MoreWindows博客目录(微软最有价值专家,原创技术文章152篇)_morewindows csdn-CSDN博客

Excerpt

文章浏览阅读5.3w次,点赞110次,收藏266次。为了方便大家查找和学习,现将本人博客中所有博客文章列出目录。一.白话经典算法,目前有17篇,分为七大排序和经典面试题讲解两大类。二.多线程,有15篇,内容全面。三.C++ STL,主要从源码角度分析。四.Windows编程,共有130多篇,主要有Windows界面编程,MoreWindows工作笔记,进程通信等等。五.OpenCV入门指南13篇。六.PHP/HTML/JavaScript,有12篇,推荐作为动态网页入门级读物。_morewindows csdn


为了方便大家查找和学习,现将本人博客中所有博客文章列出目录。

一.      白话经典算法

目前有17篇,分为七大排序和经典面试题讲解两大类

1.      《白话经典算法系列之一 冒泡排序的三种实现

2.      《白话经典算法系列之二 直接插入排序的三种实现

3.      《白话经典算法系列之三 希尔排序的实现

4.      《白话经典算法系列之四 直接选择排序及交换二个数据的正确实现

5.      《白话经典算法系列之五 归并排序的实现

6.      《白话经典算法系列之六 快速排序 快速搞定

7.      《白话经典算法系列之七 堆与堆排序

8.      《白话经典算法系列之八 MoreWindows白话经典算法之七大排序总结篇

9.      《白话经典算法系列之九 从归并排序到数列的逆序数对(微软笔试题)

10.   《白话经典算法系列之十 一道有趣的GOOGLE面试题

11.   《【白话经典算法系列之十一】一道有趣的GOOGLE面试题 –【解法2】

12.   《【白话经典算法系列之十二】数组中只出现1次的两个数字(百度面试题)

13.   《【白话经典算法系列之十三】随机生成和为S的N个正整数——投影法

14.   《【白话经典算法系列之十四】腾讯2012年实习生笔试加分题

15.   《【白话经典算法系列之十五】“一步千里”之数组找数

16.   《【白话经典算法系列之十六】“基数排序”之数组中缺失的数字

17.   《【白话经典算法系列之十七】 数组中只出现一次的数

二.      多线程

目前有15篇,本系列先示范如何使用多线程,再详细分析多线程的重点难点必考点——多线程同步互斥问题。各文章讲解生动细致,针对性强。必定也能助你在面试中秒杀所有多线程面试题。

1.《秒杀多线程第一篇 多线程笔试面试题汇总

2.《秒杀多线程第二篇 多线程第一次亲密接触 CreateThread与_beginthreadex本质区别

3.《秒杀多线程第三篇 原子操作 Interlocked系列函数

4.《秒杀多线程第四篇 一个经典多线程同步问题

5.《秒杀多线程第五篇 经典线程同步关键段CS

6.《秒杀多线程第六篇 经典线程同步事件Event

7.《秒杀多线程第七篇 经典线程同步互斥量Mutex

8.《秒杀多线程第八篇 经典线程同步信号量Semaphore

9.《秒杀多线程第九篇 经典线程同步总结关键段事件互斥量信号量

10.《秒杀多线程第十篇 生产者消费者问题

11.《秒杀多线程第十一篇 读者写者问题

12.《秒杀多线程第十二篇 多线程同步内功心法——PV操作上

13.《秒杀多线程第十四篇 读者写者问题继读写锁SRWLock

14.《秒杀多线程第十五篇 关键段,事件,互斥量,信号量的“遗弃”问题

15.  《秒杀多线程第十六篇 多线程十大经典案例之一双线程读写队列数据

三.     C++ STL

目前有11篇,主要从源码角度上分析C++ STL的数据结构和算法。

1.  《STL系列之一 deque双向队列

2. 《STL系列之二 stack栈

3.  《STL系列之三 queue 单向队列

4.  《STL系列之四 heap 堆

5.   《STL系列之五 priority_queue 优先级队列

6.  《STL系列之六 set与hash_set

7.  《STL系列之七 快速计算x的n次幂 power()的实现

8.  《STL系列之八 slist单链表

9.  《STL系列之九 探索hash_set

10.《STL系列之十 全排列(百度迅雷笔试题)

11.《STL系列十一 随机三趣题——随机重排,文件中随机取一行,生成N个随机数

四.Windows编程

这个数量比较多,分下类:

4.1. Windows界面编程

主要有半透明、异形窗口,动画启动效果,文件拖拽,listbox彩色及隔行变色。后面还有5篇位图特效显示的文章。

1.       《Windows界面编程第一篇 位图背景与位图画刷

2.       《Windows界面编程第二篇 半透明窗体

3.       《Windows界面编程第三篇 异形窗体 普通版

4.       《Windows界面编程第四篇 异形窗体 高富帅版

5.       《Windows界面编程第五篇 静态控件背景透明化

6.       《Windows界面编程第六篇 动画启动效果(动画效果显示及隐藏窗口)

7.       《Windows界面编程第七篇 文件拖拽(文件拖放)

8.       《Windows界面编程第八篇 listbox彩色显示隔行变色

9.       《Windows界面编程第九篇 位图显示特效 交错效果

10.    《Windows界面编程第十篇 位图显示特效 百叶窗效果

11.    《Windows界面编程第十一篇 位图显示特效 随机积木效果

12.    《Windows界面编程第十二篇 位图显示特效 飞入效果与伸展效果

13.    《Windows界面编程第十三篇 位图显示特效合集

4.2 MoreWindow工作笔记

对工作中的一些编程技巧进行总结。有的时候自己完成一个功能可能要花费不少时间,但Windows系统却提供了这方面的API函数,善加使用,不仅可以与Windows系统保持一致,也能提高工作效率。

1.       《【MoreWindows工作笔记1】 C/C++ 输出宽字符 printf + %ls or wcout

2.       《【MoreWindows工作笔记2】查看当前系统使用的字符集 GetSystemDefaultLocaleName

3.       《【MoreWindows工作笔记3】使用cout/pintf输出16进制,8进制,2进制数据

4.       《【MoreWindows工作笔记4】获取文件图标,类型名称,属性 SHGetFileInfo

5.       《【MoreWindows工作笔记5】StrFormatByteSize64 高端大气的显示文件大小

6.       《【MoreWindows工作笔记6】PathCommonPrefix 路径公共前缀

7.       《【MoreWindows工作笔记7】PathIsPrefix 判断路径的包含关系

8.       《【MoreWindows工作笔记8】PathFindSuffixArrayW 路径是否有给定的后缀

4.3 进程通信

1.       《VC 利用DLL共享区间在进程间共享数据及进程间广播消息

2.       《进程通信之一 使用WM_COPYDATA C++及C#实现

3.       《进程通信之二 管道技术第一篇输入输出的重定向

4.       《进程通信之二 管道技术第二篇匿名管道

5.       《进程通信之二 管道技术第三篇命名管道

6.       《进程通信之三 父进程传参数与子进程返回值

4.4 C/C++方面

1.       《如何在C/C++中动态分配二维数组

2.       《C++ 类的静态成员详细讲解

3.       《C/C++变量在内存中的分布

4.       《C,C++中使用可变参数

5.       《C,C++宏中#与##的讲解

6.       《C/C++ 在控制台下显示进度

4.5 位操作

1.       《位操作基础篇之位操作全面总结

2.       《strtok源码剖析位操作与空间压缩

3.       《两个常见位操作面试题不用加减乘除运算符计算两数之和及a=b*3

4.6 Base64编码与解码

1.       《Base64系列第一篇 Base64介绍

2.       《Base64系列第二篇 python中使用Base64编码解码

3.       《Base64系列第三篇 C/C++中使用Base64编码解码(使用boost库)》

4.       《Base64系列第四篇 C/C++中使用Base64编码解码(从chromium库中抽取)

4.7 屏幕大小 包括像素大小和物理大小

1.       《VC++获取屏幕大小第一篇 像素大小GetSystemMetrics

2.       《VC++获取屏幕大小第二篇 物理大小GetDeviceCaps 上

3.       《VC++获取屏幕大小第三篇 物理大小GetDeviceCaps 下

4.8 其它推荐文章

1.       《热门智力题过桥问题和倒水问题

2.       《Windows 各种计时函数总结

五.OpenCV

适合图像处理的初学者

1.       《【OpenCV入门指南】第一篇安装OpenCV

2.       《【OpenCV入门指南】第二篇缩放图像

3.       《【OpenCV入门指南】第三篇Canny边缘检测

4.       《【OpenCV入门指南】第四篇图像的二值化

5.       《【OpenCV入门指南】第五篇轮廓检测上

6.       《【OpenCV入门指南】第六篇轮廓检测下

7.       《【OpenCV入门指南】第七篇线段检测与圆检测

8.       《【OpenCV入门指南】第八篇灰度直方图

9.       《【OpenCV入门指南】第九篇灰度直方图均衡化

10.    《【OpenCV入门指南】第十篇彩色直方图均衡化

11.    《【OpenCV入门指南】第十一篇鼠标绘图

12.    《【OpenCV入门指南】第十二篇在Windows平台下分享OpenCV程序

13.    《【OpenCV入门指南】第十三篇人脸检测

六.PHP/HTML/JavaScript

1.       《jquery 表格的增加删除和修改及设置奇偶行颜色

2.       《javascript 得到文件后缀名

3.       《PHP 缩放图片

4.       《PHP访问MySql数据库初级篇

5.       《PHP访问MySql数据库中级篇 Smarty技术

6.       《PHP访问MySql数据库高级篇 AJAX技术

7.       《JSON进阶第一篇在PHP与javascript 中使用JSON

8.       《JSON进阶第二篇 AJAX方式传递JSON数据

9.       《JSON进阶第三篇 apache多域名及JSON的跨域问题(JSONP)

10.    《PHP读写XML文件

11.    《PHP画图基础

12.    《PHP 画图应用验证码柱状图

 后面会陆续添加的,欢迎大家多交流交流。

MoreWindows博客目录(微软最有价值专家,原创技术文章152篇)_morewindows csdn-CSDN博客

Excerpt

文章浏览阅读5.3w次,点赞110次,收藏266次。为了方便大家查找和学习,现将本人博客中所有博客文章列出目录。一.白话经典算法,目前有17篇,分为七大排序和经典面试题讲解两大类。二.多线程,有15篇,内容全面。三.C++ STL,主要从源码角度分析。四.Windows编程,共有130多篇,主要有Windows界面编程,MoreWindows工作笔记,进程通信等等。五.OpenCV入门指南13篇。六.PHP/HTML/JavaScript,有12篇,推荐作为动态网页入门级读物。_morewindows csdn


为了方便大家查找和学习,现将本人博客中所有博客文章列出目录。

一.      白话经典算法

目前有17篇,分为七大排序和经典面试题讲解两大类

1.      《白话经典算法系列之一 冒泡排序的三种实现

2.      《白话经典算法系列之二 直接插入排序的三种实现

3.      《白话经典算法系列之三 希尔排序的实现

4.      《白话经典算法系列之四 直接选择排序及交换二个数据的正确实现

5.      《白话经典算法系列之五 归并排序的实现

6.      《白话经典算法系列之六 快速排序 快速搞定

7.      《白话经典算法系列之七 堆与堆排序

8.      《白话经典算法系列之八 MoreWindows白话经典算法之七大排序总结篇

9.      《白话经典算法系列之九 从归并排序到数列的逆序数对(微软笔试题)

10.   《白话经典算法系列之十 一道有趣的GOOGLE面试题

11.   《【白话经典算法系列之十一】一道有趣的GOOGLE面试题 –【解法2】

12.   《【白话经典算法系列之十二】数组中只出现1次的两个数字(百度面试题)

13.   《【白话经典算法系列之十三】随机生成和为S的N个正整数——投影法

14.   《【白话经典算法系列之十四】腾讯2012年实习生笔试加分题

15.   《【白话经典算法系列之十五】“一步千里”之数组找数

16.   《【白话经典算法系列之十六】“基数排序”之数组中缺失的数字

17.   《【白话经典算法系列之十七】 数组中只出现一次的数

二.      多线程

目前有15篇,本系列先示范如何使用多线程,再详细分析多线程的重点难点必考点——多线程同步互斥问题。各文章讲解生动细致,针对性强。必定也能助你在面试中秒杀所有多线程面试题。

1.《秒杀多线程第一篇 多线程笔试面试题汇总

2.《秒杀多线程第二篇 多线程第一次亲密接触 CreateThread与_beginthreadex本质区别

3.《秒杀多线程第三篇 原子操作 Interlocked系列函数

4.《秒杀多线程第四篇 一个经典多线程同步问题

5.《秒杀多线程第五篇 经典线程同步关键段CS

6.《秒杀多线程第六篇 经典线程同步事件Event

7.《秒杀多线程第七篇 经典线程同步互斥量Mutex

8.《秒杀多线程第八篇 经典线程同步信号量Semaphore

9.《秒杀多线程第九篇 经典线程同步总结关键段事件互斥量信号量

10.《秒杀多线程第十篇 生产者消费者问题

11.《秒杀多线程第十一篇 读者写者问题

12.《秒杀多线程第十二篇 多线程同步内功心法——PV操作上

13.《秒杀多线程第十四篇 读者写者问题继读写锁SRWLock

14.《秒杀多线程第十五篇 关键段,事件,互斥量,信号量的“遗弃”问题

15.  《秒杀多线程第十六篇 多线程十大经典案例之一双线程读写队列数据

三.     C++ STL

目前有11篇,主要从源码角度上分析C++ STL的数据结构和算法。

1.  《STL系列之一 deque双向队列

2. 《STL系列之二 stack栈

3.  《STL系列之三 queue 单向队列

4.  《STL系列之四 heap 堆

5.   《STL系列之五 priority_queue 优先级队列

6.  《STL系列之六 set与hash_set

7.  《STL系列之七 快速计算x的n次幂 power()的实现

8.  《STL系列之八 slist单链表

9.  《STL系列之九 探索hash_set

10.《STL系列之十 全排列(百度迅雷笔试题)

11.《STL系列十一 随机三趣题——随机重排,文件中随机取一行,生成N个随机数

四.Windows编程

这个数量比较多,分下类:

4.1. Windows界面编程

主要有半透明、异形窗口,动画启动效果,文件拖拽,listbox彩色及隔行变色。后面还有5篇位图特效显示的文章。

1.       《Windows界面编程第一篇 位图背景与位图画刷

2.       《Windows界面编程第二篇 半透明窗体

3.       《Windows界面编程第三篇 异形窗体 普通版

4.       《Windows界面编程第四篇 异形窗体 高富帅版

5.       《Windows界面编程第五篇 静态控件背景透明化

6.       《Windows界面编程第六篇 动画启动效果(动画效果显示及隐藏窗口)

7.       《Windows界面编程第七篇 文件拖拽(文件拖放)

8.       《Windows界面编程第八篇 listbox彩色显示隔行变色

9.       《Windows界面编程第九篇 位图显示特效 交错效果

10.    《Windows界面编程第十篇 位图显示特效 百叶窗效果

11.    《Windows界面编程第十一篇 位图显示特效 随机积木效果

12.    《Windows界面编程第十二篇 位图显示特效 飞入效果与伸展效果

13.    《Windows界面编程第十三篇 位图显示特效合集

4.2 MoreWindow工作笔记

对工作中的一些编程技巧进行总结。有的时候自己完成一个功能可能要花费不少时间,但Windows系统却提供了这方面的API函数,善加使用,不仅可以与Windows系统保持一致,也能提高工作效率。

1.       《【MoreWindows工作笔记1】 C/C++ 输出宽字符 printf + %ls or wcout

2.       《【MoreWindows工作笔记2】查看当前系统使用的字符集 GetSystemDefaultLocaleName

3.       《【MoreWindows工作笔记3】使用cout/pintf输出16进制,8进制,2进制数据

4.       《【MoreWindows工作笔记4】获取文件图标,类型名称,属性 SHGetFileInfo

5.       《【MoreWindows工作笔记5】StrFormatByteSize64 高端大气的显示文件大小

6.       《【MoreWindows工作笔记6】PathCommonPrefix 路径公共前缀

7.       《【MoreWindows工作笔记7】PathIsPrefix 判断路径的包含关系

8.       《【MoreWindows工作笔记8】PathFindSuffixArrayW 路径是否有给定的后缀

4.3 进程通信

1.       《VC 利用DLL共享区间在进程间共享数据及进程间广播消息

2.       《进程通信之一 使用WM_COPYDATA C++及C#实现

3.       《进程通信之二 管道技术第一篇输入输出的重定向

4.       《进程通信之二 管道技术第二篇匿名管道

5.       《进程通信之二 管道技术第三篇命名管道

6.       《进程通信之三 父进程传参数与子进程返回值

4.4 C/C++方面

1.       《如何在C/C++中动态分配二维数组

2.       《C++ 类的静态成员详细讲解

3.       《C/C++变量在内存中的分布

4.       《C,C++中使用可变参数

5.       《C,C++宏中#与##的讲解

6.       《C/C++ 在控制台下显示进度

4.5 位操作

1.       《位操作基础篇之位操作全面总结

2.       《strtok源码剖析位操作与空间压缩

3.       《两个常见位操作面试题不用加减乘除运算符计算两数之和及a=b*3

4.6 Base64编码与解码

1.       《Base64系列第一篇 Base64介绍

2.       《Base64系列第二篇 python中使用Base64编码解码

3.       《Base64系列第三篇 C/C++中使用Base64编码解码(使用boost库)》

4.       《Base64系列第四篇 C/C++中使用Base64编码解码(从chromium库中抽取)

4.7 屏幕大小 包括像素大小和物理大小

1.       《VC++获取屏幕大小第一篇 像素大小GetSystemMetrics

2.       《VC++获取屏幕大小第二篇 物理大小GetDeviceCaps 上

3.       《VC++获取屏幕大小第三篇 物理大小GetDeviceCaps 下

4.8 其它推荐文章

1.       《热门智力题过桥问题和倒水问题

2.       《Windows 各种计时函数总结

五.OpenCV

适合图像处理的初学者

1.       《【OpenCV入门指南】第一篇安装OpenCV

2.       《【OpenCV入门指南】第二篇缩放图像

3.       《【OpenCV入门指南】第三篇Canny边缘检测

4.       《【OpenCV入门指南】第四篇图像的二值化

5.       《【OpenCV入门指南】第五篇轮廓检测上

6.       《【OpenCV入门指南】第六篇轮廓检测下

7.       《【OpenCV入门指南】第七篇线段检测与圆检测

8.       《【OpenCV入门指南】第八篇灰度直方图

9.       《【OpenCV入门指南】第九篇灰度直方图均衡化

10.    《【OpenCV入门指南】第十篇彩色直方图均衡化

11.    《【OpenCV入门指南】第十一篇鼠标绘图

12.    《【OpenCV入门指南】第十二篇在Windows平台下分享OpenCV程序

13.    《【OpenCV入门指南】第十三篇人脸检测

六.PHP/HTML/JavaScript

1.       《jquery 表格的增加删除和修改及设置奇偶行颜色

2.       《javascript 得到文件后缀名

3.       《PHP 缩放图片

4.       《PHP访问MySql数据库初级篇

5.       《PHP访问MySql数据库中级篇 Smarty技术

6.       《PHP访问MySql数据库高级篇 AJAX技术

7.       《JSON进阶第一篇在PHP与javascript 中使用JSON

8.       《JSON进阶第二篇 AJAX方式传递JSON数据

9.       《JSON进阶第三篇 apache多域名及JSON的跨域问题(JSONP)

10.    《PHP读写XML文件

11.    《PHP画图基础

12.    《PHP 画图应用验证码柱状图

 后面会陆续添加的,欢迎大家多交流交流。