、 结构
一、标记<Html> 建立HTML文档
<Head> 设置网页头部和其它信息
<Body> 设计文件格式及内文所在<Body> 元素的属性
Text 设置页面文字的送顔色 Bgcolor 设置页面背景的顡色
Background 设置页面的背景图像 Link设置页面黙认的顔色
Bgproperties 设置页面的背景图像为固定,不随页面的滚动而滚动
Alink 设置鼠标正在单击时候的链接顔色 Vlink 设置访问过后的链接顔色
Topmargin 设置页面的上边距 Leftmargin 设置页面的左边距
二、头部
标记 <Base> 当前文档的URL全称 <Title>设置显示在浏览器在上方的标题内容
<Isindex> 表明该文档是一个可用于检索的网关脚本
<Meta> 有关文档本身的信息,例如用于查询的关键词,用于获取该文档的有效期等
<Style> 设置CSS层叠样式表的内容
<link> 设置外部文件的链接 <script> 设置页面中程序脚本的内容
<Mate> 标记属性
Http-Equiv 生成一个HTTP标题域,它的取值与另一个属性相同,
例如Http-Equiv=Expires,实际取值由Content确定
Name 如果元数据是以关键字/取值的形式出现的,Name 表示键字,
如Author或ID
Content 关键字/取值的内容
三、文字
文字标记 <HNumber>……<1HNumber> Number=1.2.3.4.5.6
分别指1至6级标题
<Font>文字
文字的修饰标记 <B>/<strong> 粗体 <I>/<Em>/<cite> 斜体
<Sup>上标 <sub>下标 <Big>大字号 <small>小字号
<U>下划线 <S>/<strike>删除线 <Address>地址
<Tt>打字机文字 <Blink>闪烁文字(只适用于Netscape浏览器)
<Code>/<samp>等宽 <kbd>键盘输入文字 <Var>声明变量
<Fant>标记的属性
Face 字体 Size字号 Color顔色
四.列表
列表标记 <Ul>无序列表 <Ol>有序列表 <Dir>回录列表 <Dl>定义列表
<Meru>菜单列表 <Dt>·<Dd>定义列表的标记 <Li>列表项目的标记
<Ul><Ol>标记的属性 Type设置列表类型 start设置列表起始属性
Type的属性值 1 数字 a 小写字母 A 大写字母 i小写罗马数字
I 大写罗马数字 Disc ● Circle ○ square □
五.链接
链接标记 <A> 链接
<A>标记的属性 Href 指定链接地址 Name给链接命名
Title设置链接提示文字 Target指定链接的目标窗口
Target属性值 -parent在上一级窗口中打开。一般使用分帧的框架页会经常使用
-bank在新窗口中打开
-self在同一个帧或窗口中打开.这项一般不用设置
Href属性值 http:// 进入万维网站点 news://启动新闻讨论
ftp:// 进入文件传输服务器 mailto:// 启动新闻讨论组
telnet:// 启动telnet方式 gopher://访问一个gopher服务器
六.图片
图片标记 <Img>图片 <Map>图像映射 <Area>图像映射中定义区域
<lmg>标记的属性 src图像的源文件 Alt提示文字 Width宽度
Height高度 Vspace垂直间距 Hspace水平间距 Align排列 Border边框
Align属性值 Top文字的中间线居于图片上方 Middle文字的中间线居于图片中间
Bottom文字的中间线居于图片底部 Left 图片在文字的左侧
Right图片在文字的右侧 Absbottom文字的底线居于图片底部
Absmiddle文字的底线居于图片中间 Baseline英文文字基线对齐
Texttop英文文字上边线对齐
Shape属性值
Rect矩形区域 Circle椭圆形区域 Poly多边形区域
七.表格
1.表格标记 <Table>…</Table>表格标记 <Tr>…</Tr>行标记
<Td>…</Td>单元格标记 <Th>表头标记
<Table>标记属性 Bordercolor 表格边框色 Borde表格边框的宽度
Bordercolorlight 表格边框亮边框色(左上边框顔色)
Bordercolordark 表格暗边框色(右下边框顔色)
Bordercolor 行的边框顔色 Width表格的宽度 Height表格的高度
Bgcolor表格的背景顔色 Background表格的背图像
<Tr>标记属性 Align行内容的水平对齐 Valign 行内容的垂直对齐
Bgcolor 行的背景顔色 Background 行的背景图像
Bordercolor 行的边框顔色 Bordercolorlight 行的亮边框顔色
Bordercolordark 行的暗边框顔色
<Td>标记属性 Align单元内容的水平对齐 Valign单元格内容的垂直对齐
Bgcolor 单元格的背景顔色 Background 单元格的背景图像
Bordercolor单元格的背景顔色 Bordercorlorlight单元格的亮边框顔色
Brodercolordark 单元格的暗边框顔色 Width 单元格的宽度
Height单元格的高度
<Th>标记属性 Align表头内容的水平对齐 Valign表头内容的垂直对齐
Bgcolor 表头的背景顔色 Background表头的背景图像
Bordercolor表头的边框顔色 Bordercolorlight 表头的亮边框顔色
Bordercolordark 表头的暗边框顔色 Width 表头的宽度 Height 表头的高度
八.表单
1.表单标记 <Form>表单标记 <Input>表单输入标记
<select>菜单和列表标记 <Option>菜单和列表项目标记
2.属性 <Form> Name表单的名称
Method 定义表单结果从浏览器传送到服务器的方法,一般有两种方法:get,post
Action 用来定义表单处理程序(一个Asp,CGI等程序)的位置(相对地址或绝对地址)
<lnput>标记属性 Name 域的名称 Type域的类型
Maxlength 域的最大输入字符数 size域的宽度 Value 域的默认值
<Select>标记属性 Name 菜单和列表的名称 size 显示的选项数目
Multiple 列表中的项目多选 Value 选项值 selected默认选项
<Texrarea>标记属性 Name 文字域的名称 Rows文字域的行数
Cols 文字域的列数 Value 文字域的默认值
Type属性值 Text 文字域 Password 密码域 File 文件域
Checkbox复选框 Redio单选框 Button普通按扭
Submit 提交按钮 Reset重置按钮 Hidden隐藏域Image图像域
九.滚动
滚动标记 <Marquee>
<Marquee>标记属性 Direction 滚动方向 up 文字向上滚动 Left文字向左滚动
Behavior 滚动方式 Scroll 循环往复
Side 只做一次滚动
Alternate 交替进行滚动
ScrollAmount 滚动速度
ScrollDelay 滚动延迟
Trim函数用来剔除首尾空格
十.框架
1.标记 <Frameset> 框架边框标记 <Frame> 框架标记 <Iframe>浮动框架标记
<Frameset>标记属性 Cols列 Rows行
<Frame> 标记属性 src框架中显示页面源文件的路径
FrameBorder 框架边框显标属性 FrameSpacing框架边框宽度属性
Scrolling框架滚动条显示属性 NoResize 框架尺寸调整属性
BorderColor 框架边框顔色属性 MarginWidt 框架边框缘宽度属性
MarginHerght框架边缘高度属性
<1frame> 标记属性 src浮动框架中显示页面源文件的路径
Width 浮动框架的宽度 Height 浮动框架的高度
Name 浮动框架的名称
Align 浮动框架的排列方式 Left表示居左 Center表示居中 Right表示居右
FrameBorder 框架边框显示属性 FrameSpacing 框架宽度属性
Scrolling 框架滚动条显示属性 ( yes显示 No不显示 Auto根据页面的长度自动判断是否晶粒示滚动条
NoResize 框架尺寸调整属性 BorderColor框架的顔色
MarginWidth 框架边缘宽度属性 MarginHeight 框架边缘高度属性
插入刷新
步骤:1.选择"查看/文件头内容"
2.在插入面板上,打开HTML选项卡
优化代码
打开文件窗口,执行"命令、清理HTML"命令
文本换行:Enter 行距较大
Enter + Shift 行距较小
插入水平线设置顔色:单击属性面板中的快捷标签编辑器按钮
在代码中键入"color = #顔色值"
当图像无法显示时将显示这段文字:
图像属性中的替代→输入文字
插入鼠标经过图像:准备两张图像
在文件窗口中,将光标放置于需要翻转图像位置→插入工具栏中单击鼠标经过图像
Ⅱ.使用导航条:
在"常用"对象组中,单击"图像"小三角→导航条
插入图像占位符:图像小三角→图像占位符
Flash动画的背景实现透明 参数wmode 值 transparent
插入 Java Applet
插入表单
插入表单域:对象面板上"表单"→插入表单
插入文本域:单击面板上的插入文本域. 初始值 = 打开时显于的文字
插入密码框:在属性面板上选择密码
插入多行文本域:在类型后选择多行
插入隐藏域:对象面板→插入隐藏域
插入按钮:标签用来设置按钮上显示的文本
插入图像提交按钮=图像域:
插入文件上传按钮=文件域:
插入单选框
插入单选按钮组:Label文字说明 Value 单选按钮的值
插入复选框
菜单/插入列表:列表值→
插入跳转菜单:(
制作网页链接
URL统一资源定位器
目标:_blank在一个新的未命名的浏览器窗口中打开
_parent如果是嵌套的框架,链接会在父框架或窗口中打开,否则=_top
_top在完整的浏览器中打开
创建搜索页
运行中输入:
Inetmgr (IIS
Odbcad32 (odbc
Asp对象
Applicatipn 在给定的应用程序的所有用户间共享信息,并在服务器运行期间持久地保存数据。
集合: Contents
staticObjects
Item(变量值)=设置资料变量的值
Key(变量名称)=设置资料变量的名称
Count(变量资料的数量)=表示
Coutents集合中资料的总数量
方法: Lock
Unlock
事件: Applicatipn_Onstart
Application_OnEnd
Session 存储特定的用户会话所需的信息
属性:CodePage
LCID
SessionID
Timeout
集合:Contents
StaticObjects
方法:Abandon
事件:Session_Onstart
Session_OnEnd
Response 用来控制发送给用户的信息,包括直接发送信息给浏览器,重定位浏览器到另一个URL或设置Cookie值
属性: Buffer
CacheControl
Charset
ContentType
Expires
ExpiresAbsolute
IsClientConnected
PICS
Status
集合: Cookies
方法: AddHeader
AppendToLog
BinaryWrite
Clear
End
Flush
Redirect
Write
Request 访问任何基于HTTP请求传递的信息,常见的有从HTML表单用Post方法或Get方法传递的参数,Cookie或用户认证等。
属性: TotalBytes
集合: ClientCertificate
Cookies
Form
QueryString
ServerVaiables
方法: BinaryRead
Server 提供对服务器方法和属性的访问
属性: ScriptTimeout
集合: 无
方法: CreatObject
HTMLEncode
MapPath
URLEncode
Recordset
MoveNext 将前数据记录移至下一条
MovePrevious 将当前数据记录移至上一条
MoveFirst 将当前数据记录移至第一条
MoveLast 将当前数据记录移至最后一条
AbsolutePosition=N 将当前数据记录移至第N条
EOF 当前数据记录是否移过了最后一条(发生于向下移动时)
BOF 当前数据记录是否移过了第一条 (发生于向上移动时)
VBScript 运算符
算术运算符
指数 取负 乘法 除法 加法 减法 取模 连接 整数除法
∧ - * / ﹢ ﹣ Mod & \
比较运算符
相等 不相等 小于 大于 小于或等于 大于或等于 对象相象
= <> < > <= >= IS
逻辑运算符
逻辑非 逻辑与 逻辑或 异或 逻辑等于 逻辑蕴含
Not And Or Xor Eqv Imp
读
过去十年间,中国经济取得了长足发展,也为其他国家的发展提供了借鉴。这背后有哪些原因?近日,巴西前旅游部部长、现任清华大学教授福鑫(Alessandro Teixeira)做客中国日报《连线》栏目,带来他对中国发展和相关问题的解读。
中国的发展不是威胁
Q:China has achieved many economic milestones over the past decade, but the Western politicians' saying "China is a threat to the world" has followed all the way. What is your opinion on this?
过去十年间,中国经济取得了许多里程碑式的成就。与之相伴,西方政治家就“中国威胁论”喋喋不休。对于这个现象,您怎么看?
A:I think we need to analyze this statement very carefully. When you say "Western", I think it’s too heavy, it's not Western, maybe mainly it's America and some allied European countries. Because if you go to South America, nobody's talking about China being a threat. If you go to Africa, nobody is talking about it as a trap. People who tell you that or people who are vocal about that are from some countries in the Europe, not all of them, and then there's the United States. So the question is, a threat to whom?
我认为这个说法值得仔细分析。当你说“西方”的时候,我认为太广泛了。你所谓的“西方”,我认为不是西方,而主要是美国和其部分欧洲盟友。在南美,没人谈论中国是个威胁。非洲也没人讨论“债务陷阱”。一直拿“中国威胁论”来说事的,是少数几个欧洲国家,不是全部,以及美国。所以问题应该是,中国对谁产生了威胁?
Another question is, why is China a threat? Maybe because the United States doesn't want to compete with anybody else? And China represents, not because China wants to, but represents competition to the US in terms of technology, competition to the US in terms of production. So those are the main elements. I don't see China being a threat to anyone. China's foreign policy, respects sovereignty of every single country. China never invades, never declares war. We are talking about competition in a very narrow field, that is economics.
问题之二在于:为何说中国是一个威胁?或许是因为美国不想和其他国家竞争?不是中国想要去竞争,而是中国在科技、制造的实力使其被美国视为竞争对手。所以这些才是关键元素。我认为中国不会对任何国家产生威胁。中国的外交政策尊重每一个国家的主权。中国从不发起侵略,也从不对外宣战。我们所说的竞争仅限于特定的领域,就是经济领域。
And that's natural because China wants to achieve development. And when to achieve development, you need to have, as President Xi Jinping says, dual circulation, internal market, external market. And if competition is not good, I don't understand, because the United States loves to say that they want to have free competition. So let China compete in the international market, so I don't see a threat in any way. I can see competition, I can see China trying to gain the market.
但这是很自然的事,中国要发展,想要发展,就要如习近平主席所说,实现双循环,在外部和内部的市场有机循环起来。如果竞争不是好事,那让我不明白的是,为什么美国还总是喜欢自我标榜“自由竞争”?所以,让中国在国际市场上竞争,无论如何,我都不认为中国的发展是一种威胁,我看到的是竞争,是中国在努力争取市场。
“一带一路”倡议
不是中国的“马歇尔计划”
Q:The Diplomat compared China's BRI to the US's Marshall Plan in a 2016 article. What is your estimation of BRI?
《外交学者》杂志在一篇2016年的文章中将中国的“一带一路”倡议比作美国的马歇尔计划。您怎么看待“一带一路”倡议?
A:It's completely different. Marshall Plan is a plan for reconstruction and for economic fostering. BRI is not that.
“一带一路”倡议和马歇尔计划完全不同。马歇尔计划旨在战后重建和复苏经济。“一带一路”不是。
Many people would say that the Belt and Road Initiative is a Chinese initiative. Many people say that it’s a way for China to increase trade or increase investment outside. The way I see it is a little different. I see it as a cooperation platform.
许多人认为“一带一路”倡议是中国倡议。也有许多人说它是中国增长贸易、促进外部投资的方式。我的看法稍许不同。我认为“一带一路”倡议是一个合作平台。
So when we have Latin American countries and there's a discussion, how would Latin America take part in it? How could Latin America engage better? And again, the point that I'd like to stress is that Latin America can engage with many other countries other than China. Because China had the idea to create a platform, but China doesn't want to monopolize it and keep the Belt and Road Initiative to itself. No, it wants to spread around the world as a cooperation platform. You want to be part of BRI. That's fine. If you're not, it's okay. It's your option.
所以,当拉丁美洲国家加入了“一带一路”倡议后,当地就开始进行关于拉丁美洲国家如何参与该倡议的讨论,拉丁美洲国家怎样更好地参与进来?我想再次强调一点,这并不是只与中国打交道,因为中国只是创造了一个平台,中国并不希望一家独大,将“一带一路”倡议占为己有。不,中国是想向世界提供一个合作平台。你想要加入,那非常棒。你不想加入,没问题,你有选择的自由。
What I am saying is that if you're part of BRI, you would have enjoyed a club that can invest together, can do trade together, can share different cultural elements together, can participate in discussion of the digital economy, digital transformation, societal transformations. So that's the important point.
我想说的是,如果你是“一带一路”倡议的成员,你就好像加入了一个俱乐部,大家一起投资,一起贸易,一起分享不同文化,一起参与数字经济、数字转型、社会转型的讨论。这点非常重要。
I've heard people say many times, if you're part of the BRI, China will invest in you, will buy from you. No, that's not the case. China never said that. What China always said is that we are creating, we are sharing a vision of the world of humankind where we want development and prosperity. BRI is a tool that can help us to achieve that. China never said that the only tool is our tool. There is no need for these adjectives in the discussion. What we have in the discussion is something that could help the world.
我多次听到别人说,如果你参与共建“一带一路”,那么中国就会向你投资、向你买东西。不,并非如此。中国从来没说过这样的话。中国一直说我们要创建人类命运共同体,共同发展,共同繁荣。“一带一路”倡议就是帮我们实现它的工具。中国从没说过我们的工具是唯一的工具。这些话从没出现在讨论中。我们在讨论一些对世界有益的事情。
中美两国不会脱钩
Q:In the context of globalization, what is your opinion about the so-called China-US decoupling?
在全球化背景下,您如何看待所谓的“中美脱钩”?
A:In my opinion, it's very, very hard to have a decoupling. When you are the first and second economies, there is no possibility of decoupling. Why? Because you are integrated, not fully, in some value chains, in some supply chains, you are completely integrated.
在我看来,中美两国很难脱钩。两者作为世界第一大和第二大经济体,两者不可能做到脱钩。为什么呢?因为中美已经在一些价值链、供应链中相互融合,已经融合在一起。
But of course, if you are two largest economies in the world, there is no possibility of decoupling. So I think what the US Trade Representative says in Singapore is the right thing. You cannot divorce. You can realign, you can restrategize, but you cannot divorce. There is no such thing in decoupling. There is no such thing in decoupling in terms of macro economics. There is no such thing of decoupling in terms of technology. Because they are already integrated.
当然,作为世界上最大的两个经济体,两者不可能做到脱钩。所以,我赞同美国贸易代表戴琪在新加坡所说的话,中美两国不能脱钩。两个国家可能重新调整关系,可能重新部署规划,但是不可能脱钩。不存在脱钩,从宏观经济而言,脱钩不存在,从科技层面而言,脱钩也不存在,因为两国已经紧密结合。
It took a long time, almost two decades, three decades for this integration between the American economy and the Chinese economy. You can not just do it by a presidential order, say "now disappear", it's impossible. People that work with real economics know that. So one thing is the ideological or political use of this term, "decoupling". Another thing is the real economic meaning of decoupling. In the political arena, you can talk about that. But in practical terms, you can reduce but never decouple.
中美经济用了二三十年才达到了今天这种融合程度,现在仅凭一纸总统令就要中止合作,这是不可能的。从事实体经济的人都明白这点。“脱钩”在意识形态或政治上,与在实体经济中,有着不同的含义。在政治方面或许会有这方面的讨论,在实际情况中,融合或许会减少,但脱钩绝不可能发生。
中国发展的四大因素
Q:As former special advisor to the president of Brazil, what do you think of China's development?
作为前巴西总统顾问,你怎么看待中国的发展?
A:I think the root of China's objective, is to achieve development for its people. It's very important. It's not a dream, it's a reality. And I think China can do that because it has its unique system.
我认为中国发展目标的根基在于为人民谋发展。这一点非常重要。这不是梦,这是现实。我认为中国可以做到这点,因为它有独特的体制。
How can China get to that? I always say that there are some important elements. The first element that’s very critical is leadership. When the leadership takes a decision, that's taken seriously by everybody, by private sector, by media, by government. So you know the direction where you need to go.
中国如何实现发展?我一直说有几个重要因素。第一个关键因素是领导力。中国的领导层做出决策时,全民都认真参与其中,私有企业、媒体、政府都包括在内,所以你可以清楚了解国家的发展方向。
The second important element is education. I am doing a research, and I see that at least thirty percent of the income of families go to education. Not only formal education but after school, K12, everything. So that's very important. If you have money, you put money in education and that's different in Western society. Sometimes we take education for granted. We don't think that you need it. Many people say, because the competition in China is huge. But it doesn’t matter if he's in China or outside. You want to prepare. So the second element is education.
第二个因素,是教育。我在做一项调研,我发现中国家庭收入里,至少三成以上都投入到了教育之中。不仅是正规教育,还有课后辅导,基础教育等等。这很重要。中国家庭把钱花在教育上,这和西方社会不一样。西方人往往认为教育是理所当然的,不需要额外投入。很多人会说,这是因为中国的竞争压力很大。但无论在中国还是在国外,人都会面临竞争,人们总是希望有所准备。所以第二个因素是教育。
The third element is the faith that the population has in the government and in the system. The government plays an important role in terms of leadership, but plays a much more important role in terms of governance. So people understand where you want to go.
第三个因素是中国人对政府和体制的信念。政府发挥着重要的领导决策作用,也发挥着重要的治理职能。所以人们能了解政府的方向。
The fourth element I think, it's an important element, is the culture of Chinese people, is how they perceive the world. Not in the short run, but it's a long run.
第四个因素,我认为是很重要的一点,是中国的文化,是中国人民如何看待世界,不是只看眼前,而是长远规划。
I think those four elements are the elements that make China different than any other place around the world.
在我看来,这四个因素让中国不同于世界其他地区。
结语
Unique systems, solid education, firm faith in the government, and long-term vision are the four characteristics of China's path, in Professor Teixeira's observation. With its roots in Chinese soil, the country's path has proved suitable for China's culture and conditions. It has brought the Chinese people peaceful and fulfilled lives, and the Chinese nation lasting prosperity.
独特的体系、扎实的教育、人民对政府的坚定信念以及长远规划,是福鑫教授观察到的中国道路的四大特征。中国道路扎根于中国土壤,实践证明,它适应中国的文化和国情。它给中国百姓带来了安稳幸福的生活,也给国家带来了长富久安。
出品人:王浩
监制:柯荣谊 宋平
制片:张少伟 栾瑞英
记者:沈一鸣 张欣然 史雪凡周星佐 刘源
实习生:吕红梅 钱昕瑀 王博麟刘莹 孙伊茗 张奕杰
中国观察智库
中国日报新媒体中心
联合出品
这是一篇很久之前就想动笔写的文章,最近正好看到群里有小伙伴分享了 Dubbo 连接相关的文章,才又让我想起了这个话题。今天想跟大家聊的便是 Dubbo 中的连接控制这一话题。说到“连接控制”,可能有读者还没反应过来,但你对下面的配置可能不会感到陌生:
<dubbo:reference interface="com.foo.BarService" connections="10" />
如果你还不了解 Dubbo 中连接控制的用法,可以参考官方文档:https://dubbo.apache.org/zh/docs/advanced/config-connections/ ,话说最近 Dubbo 官方文档来了一次大换血,好多熟悉的文档差点都没找到在哪儿 Orz。
众所周知,dubbo 协议通信默认是长连接,连接配置功能用于决定消费者与提供者建立的长连接数。但官方文档只给出了该功能的使用方法,却并没有说明什么时候应该配置连接控制,本文将主要围绕该话题进行探讨。
本文也会涉及长连接相关的一些知识点。
先来看一个 Dubbo 构建的简单 demo,启动一个消费者(192.168.4.226)和一个提供者(192.168.4.224),配置他们的直连。
消费者:
<dubbo:reference id="userService" check="false"
interface="org.apache.dubbo.benchmark.service.UserService"
url="dubbo://192.168.4.224:20880"/>
提供者:
<dubbo:service interface="org.apache.dubbo.benchmark.service.UserService" ref="userService" />
<bean id="userService" class="org.apache.dubbo.benchmark.service.UserServiceServerImpl"/>
长连接是看不见摸不着的东西,我们需要一个观测性工作来”看到“它。启动提供者和消费者之后,可以使用如下的命令查看 tcp 连接情况
提供者:
[root ~]# netstat -ano | grep 20880
tcp6 0 0 192.168.4.224:20880 :::* LISTEN off (0.00/0/0)
tcp6 2502 0 192.168.4.224:20880 192.168.4.226:59100 ESTABLISHED off (0.00/0/0)
消费者:
[root@ ~]# netstat -ano | grep 20880
tcp6 320 720 192.168.4.226:59110 192.168.4.224:20880 ESTABLISHED on (0.00/0/0)
通过上述观察到的现象我们可以发现几个事实。
仅仅是启动了提供者和消费者,上述的 TCP 连接就已经存在了,要知道我并没有触发调用。也就是说,Dubbo 建连的默认策略是在地址发现时,而不是在调用时。当然,你也可以通过延迟加载 lazy="true" 来修改这一行为,这样可以将建联延迟到调用时。
<dubbo:reference id="userService" check="false"
interface="org.apache.dubbo.benchmark.service.UserService"
url="dubbo://192.168.4.224:20880"
lazy="true"/>
除此之外,还可以发现消费者和提供者之间只有一条长连接,20880 是 Dubbo 提供者默认开放的端口,就跟 tomcat 默认开放的 8080 一个地位,而 59110 是消费者随机生成的一个端口。(我之前跟一些朋友交流过,发现很多人不知道消费者也是需要占用一个端口的)
而今天的主角”连接控制“便可以控制长连接的数量,例如我们可以进行如下的配置
<dubbo:reference id="userService" check="false"
interface="org.apache.dubbo.benchmark.service.UserService"
url="dubbo://192.168.4.224:20880"
connections="2" />
再启动一次消费者,观察长连接情况
提供者:
[root@ ~]# netstat -ano | grep 20880
tcp6 0 0 192.168.4.224:20880 :::* LISTEN off (0.00/0/0)
tcp6 2508 96 192.168.4.224:20880 192.168.4.226:59436 ESTABLISHED on (0.00/0/0)
tcp6 5016 256 192.168.4.224:20880 192.168.4.226:59434 ESTABLISHED on (0.00/0/0)
消费者:
[root@ ~]# netstat -ano | grep 20880
tcp6 0 2520 192.168.4.226:59436 192.168.4.224:20880 ESTABLISHED on (0.00/0/0)
tcp6 48 1680 192.168.4.226:59434 192.168.4.224:20880 ESTABLISHED on (0.00/0/0)
可以看到,这里已经变成两条长连接了。
现在我们知道了如何进行连接控制,但什么时候我们应该配置多少条长连接呢?这个时候我可以跟你说,具体视生产情况而定,但你如果你经常看我的公众号,肯定会知道这不是我的风格,我的风格是什么?benchmark!
写作之前,我跟几个同事和网友对这个话题进行了简单的讨论,其实也没有什么定论,无非是对单连接和多连接吞吐量高低不同的论调。参考既往 Dubbo github 中的 issue,例如:https://github.com/apache/dubbo/pull/2457,我也参与了这个 pr 的讨论,讲道理,我是持怀疑态度的,我当时的观点是多连接不一定能够提升服务的吞吐量(还是挺保守的,没有这么绝对)。
那接下来,还是用 benchmark 来说话吧,测试工程还是我们的老朋友,使用 Dubbo 官方提供的 dubbo-benchmark 工程。
测试工程在之前的文章介绍过,这里就不过多赘述了,测试方案也非常简单,两轮 benchmark,分别测试 connections=1 和 connections=2 时,观察测试方法的吞吐量。
说干就干,省略一堆测试步骤,直接给出测试结果。
connections=1
Benchmark Mode Cnt Score Error Units
Client.createUser thrpt 3 22265.286 ± 3060.319 ops/s
Client.existUser thrpt 3 33129.331 ± 1488.404 ops/s
Client.getUser thrpt 3 19916.133 ± 1745.249 ops/s
Client.listUser thrpt 3 3523.905 ± 590.250 ops/s
connections=2
Benchmark Mode Cnt Score Error Units
Client.createUser thrpt 3 31111.698 ± 3039.052 ops/s
Client.existUser thrpt 3 42449.230 ± 2964.239 ops/s
Client.getUser thrpt 3 30647.173 ± 2551.448 ops/s
Client.listUser thrpt 3 6581.876 ± 469.831 ops/s
从测试结果来看,似乎单连接和多连接的差距是非常大的,近乎可以看做是 2 倍!看起来连接控制的效果真是好呀,那么事实真的如此吗?
按照这种方案第一次测试下来之后,我也不太相信这个结果,因为我之前按照其他方式做过多连接的测试,并且我也参加过第三届中间件挑战赛,使得我对长连接的认知是:大多数时候,单连接往往能发挥出最优的性能。即使由于硬件原因,这个差距也不应该是两倍。怀着这样的疑问,我开始研究,是不是我的测试场景出了什么问题呢?
经过和闪电侠的讨论,他的一席话最终让我定位到了问题的所在。
闪电侠的对话
不知道大家看完我和闪电侠的对话,有没有立刻定位到问题所在。
之前测试方案最大的问题便是没有控制好变量,殊不知:在连接数变化的同时,实际使用的 IO 线程数实际也发生了变化。
Dubbo 使用 Netty 来实现长连接通信,提到长连接和 IO 线程的关系,这里就要介绍到 Netty 的连接模型了。一言以蔽之,Netty 的设置 IO worker 线程和 channel 是一对多的绑定关系,即一个 channel 在建连之后,便会完全由一个 IO 线程来负责全部的 IO 操作。再来看看 Dubbo 是如何设置 NettyClient 和 NettyServer 的 worker 线程组的:
客户端 org.apache.dubbo.remoting.transport.netty4.NettyClient:
private static final EventLoopGroup NIO_EVENT_LOOP_GROUP = eventLoopGroup(Constants.DEFAULT_IO_THREADS, "NettyClientWorker");
@Override
protected void doOpen() throws Throwable {
final NettyClientHandler nettyClientHandler = new NettyClientHandler(getUrl(), this);
bootstrap = new Bootstrap();
bootstrap.group(NIO_EVENT_LOOP_GROUP)
.option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
...
}
Constants.DEFAULT_IO_THREADS 在 org.apache.dubbo.remoting.Constants 中被写死了
int DEFAULT_IO_THREADS = Math.min(Runtime.getRuntime().availableProcessors() + 1, 32);
在我的 4c8g 的机器上,默认等于 5。
服务端 org.apache.dubbo.remoting.transport.netty4.NettyServer:
protected void doOpen() throws Throwable {
bootstrap = new ServerBootstrap();
bossGroup = NettyEventLoopFactory.eventLoopGroup(1, "NettyServerBoss");
workerGroup = NettyEventLoopFactory.eventLoopGroup(
getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
"NettyServerWorker");
final NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this);
channels = nettyServerHandler.getChannels();
ServerBootstrap serverBootstrap = bootstrap.group(bossGroup, workerGroup)
.channel(NettyEventLoopFactory.serverSocketChannelClass());
.option(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
.childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
}
服务端倒是可以配置,例如我们可以通过 protocol 来控制服务端的 IO 线程数:
<dubbo:protocol name="dubbo" host="${server.host}" server="netty4" port="${server.port}" iothreads="5"/>
如果不设置,则跟客户端逻辑一致,是 core + 1 个线程。
好了,问题就在这儿,由于我并没有进行任何 IO 线程的设置,所以客户端和服务端都会默认开启 5 个 IO 线程。当 connections=1 时,Netty 会将 channel1 绑定到一个 IO 线程上,而当 connections=2 时,Netty 会将 channel1 和 channel2 按照顺序绑定到 NettyWorkerThread-1和 NettyWorkerThread-2 上,这样就会有两个 IO 线程在工作,这样的测试结果当然是不公平的。
这里需要考虑实际情况,在实际生产中,大多数时候都是分布式场景,连接数一定都是大于 IO 线程数的,所以基本不会出现测试场景中的 channel 数少于 IO 线程数的场景。
解决方案也很简单,我们需要控制变量,让 IO 线程数一致,仅仅观察连接数对吞吐量的影响。针对服务端,可以在 protocol 层配置 iothreads=1;针对客户端,由于源码被写死了,这里我只能通过修改源码的方式,重新本地打了一个包,使得客户端 IO 线程数也可以通过 -D 参数指定。
改造之后的,我们得到了如下的测试结果:
1 IO 线程 1 连接
Benchmark Mode Cnt Score Error Units
Client.createUser thrpt 3 22265.286 ± 3060.319 ops/s
Client.existUser thrpt 3 33129.331 ± 1488.404 ops/s
Client.getUser thrpt 3 19916.133 ± 1745.249 ops/s
Client.listUser thrpt 3 3523.905 ± 590.250 ops/s
1 IO 线程 2 连接
Benchmark Mode Cnt Score Error Units
Client.createUser thrpt 3 21776.436 ± 1888.845 ops/s
Client.existUser thrpt 3 31826.320 ± 1350.434 ops/s
Client.getUser thrpt 3 19354.470 ± 369.486 ops/s
Client.listUser thrpt 3 3506.714 ± 18.924 ops/s
可以发现,单纯提升连接数并不会提升服务的吞吐量,这样的测试结果也更加符合我认知的预期。
从上述测试的结果来看,一些配置参数并不是越大就代表了越好,类似的例子我也在多线程写文件等场景分析过,唯有理论分析+实际测试才能得出值得信服的结论。当然个人的测试,也可能会因为局部性关键信息的遗漏,导致误差,例如,如果我最终没有发现 IO 线程数和连接数之间的隐性关联,很容易就得出连接数和吞吐量成正比的错误结论了。当然,也不一定就代表本文最终的结论是靠谱的,说不定还是不够完善的,也欢迎大家留言,提出意见和建议。
最终回到最初的问题,我们什么时候应该配置 Dubbo 的连接控制呢?按照我个人的经验,大多数时候,生产环境下连接数是非常多的,你可以挑选一台线上的主机,通过 netstat -ano| grep 20880| wc -l 来大概统计下,一般是远超 IO 线程数的,没必要再多配置成倍的连接数,连接数和吞吐量并不是一个线性增长的关系。
Dubbo 框架有这个能力和大家真的需要用这个能力完全是两码事,我相信大多数读者应该已经过了技术新鲜感驱动项目的阶段了吧?如果有一天你需要控制连接数,去达到一定特殊的用途,你就会真心感叹,Dubbo 真是强呀,这个扩展点都有。
Dubbo 的连接控制真的完全没有用吗?也不尽然,我的测试场景还是非常有限的,可能在不同硬件上会跑出不一样的效果,例如我在第三届中间件性能挑战赛中,就是用 2 连接跑出了最好的成绩,并非单连接。
最后,你如果仅仅使用 Dubbo 去维系你们的微服务架构,大部分情况不需要关注到连接控制这个特性,多花点时间搬砖吧,就酱,我也去搬砖了。
*请认真填写需求信息,我们会在24小时内与您取得联系。