標籤: 電動車

  • 日本國土百萬年的惡夢 每日數百噸的福島輻射污染水

    文:宋瑞文(媽媽監督核電廠聯盟特約撰述)

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※教你寫出一流的銷售文案?

  • 一口氣投80億人民幣 比亞迪建長沙、青島兩個新能源車生產基地

    比亞迪汽車於5月18日與湖南省長沙市雨花區經開區簽署合作備忘錄,比亞迪將投資50億元人民幣(下同),在長沙比亞迪汽車城二期興建電動卡車及專用車生產基地,計畫年內投產。   長沙比亞迪專案將由電動轎車、電動客車和電動卡車及專用車三部分組成。電動卡車及專用車專案,現已動工建設,是比亞迪電動卡車及專用車全球製造中心,含整車及相應配套零部件,目標向全中國工廠提供電動底盤、車橋等核心部件。比亞迪預計2016年將達產2500輛,規劃至2020年達5000輛年產能,2025年擴建到10000輛年產能。   此外,比亞迪在青島市城陽區投資30億元的新能源汽車專案一期目前已開工建設,這是青島城陽首個新能源汽車產業專案,也是建區以來引進的最大工業專案。根據規劃分三期建設完成,預計2017年全部建成。專案全部建成後,將年產電動汽車5000輛,年可實現銷售收入105億元。   此專案位於棘洪灘軌道交通裝備製造產業園內,規劃佔地1000畝,主要生產純電動轎車、中巴、小巴、物流車等產品,以及從事車輛電池、電機、電控等核心零部件的研發和製造。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※教你寫出一流的銷售文案?

  • 用Visual C++創建WPF項目的三種主要方法

    用Visual C++創建WPF項目的三種主要方法

    用Visual C++創建WPF項目的三種主要方法

    The problem with using XAML from C++

    Because C++ doesn’t support partial class definitions, it isn’t possible to directly support XAML in VC++ projects using this mechanism. That isn’t, however, the core reason why VC++ doesn’t directly support XAML. In addition to using the x:Class attribute, you can also use the x:Subclass attribute so that the XAML gets compiled into the class specified by the x:Class attribute, and the code behind will define the class specified by x:Subclass, which will be derived from the x:Class type. Thus, the lack of partial classes isn’t that big of a block. The main issue is that, right now, no 100-percent CodeDOM support is available to convert

    the XAML to C++, and that is the single biggest reason why VC++ doesn’t support XAML intrinsically. I don’t know this for sure, but it’s possible that on a later date, the Visual C++ team may work on their CodeDOM support and provide a fully functional XAML-to-C++ converter. Once that’s available, XAML support can be integrated into VC++ projects. As of today, however, that isn’t an option.

    NOTE: CodeDOM is a term used to represent a bunch of types available in the System.

    CodeDom namespace that lets you abstract code into an object model. Source code is represented using the CodeDOM tree and can be converted into source code for a specific language using the CodeDOM code generator for that specific language.

    Still, the fact that you can’t directly use XAML in a Visual C++ project doesn’t mean that WPF applications can’t be written with Visual C++.

    Three ways to write WPF apps using VC++

    You can use three different approaches to write WPF applications using Visual C++. Each has its pros and cons, and we’ll cover each of these approaches in the next section:

    • Use procedural code.

    For one thing, you can directly use procedural code to

    write Avalon-based applications and avoid using XAML. Of course, if you

    do that, you automatically give up the advantages of declarative programming

    that XAML brings in, but for certain scenarios, procedural code often

    serves the purpose well.

    • Dynamically load XAML.

    Alternatively, you can dynamically load XAML during runtime to create your Avalon windows, although the disadvantage is that you’d be distributing a bunch of XAML files with your application.

    • Derive from a class in a C# DLL

    A third technique uses a C# project to create your XAML-based Avalon controls and have a class (or classes) in your C++ project that derives from the classes in the C#-based Avalon DLL. With that mechanism, the UI is created using XAML in the C# project, and the business logic is kept in the C++ project.

    When you’re developing WPF applications with C++, you can use one or more of these approaches to achieve whatever functionality you want. In the next section, you’ll see how to write a simple WPF app with C++/CLI using each of the three techniques mentioned here.

    7.2 Using C++/CLI to write a WPF application

    If Visual C++ doesn’t have support for XAML, and there are no project templates for building an Avalon application (as of the June 2006 CTP), how much extra effort does it take to write Avalon applications using C++? In this section, you’ll find out. You’ll put the three different techniques I described at the end of section

    7.1.2 into action. All three mechanisms have their advantages and disadvantages; you can decide which is most suitable for your specific scenario. First, though, let’s briefly go over how to create a new C++/CLI project for Avalon.

    7.2.1 Creating a new C++/CLI Avalon project

    Avalon is a managed framework, and as such any Visual C++ project that needs to access and use Avalon needs to have the /clr compilation mode turned on.

    Creating a new C++/CLI project with support for Avalon is fortunately not a difficult task. Table 7.1 lists the few simple steps you need to follow each time you create an application (or library, as the case might be) that uses Avalon.

    Table 7.1 Steps to create a C++/CLI Avalon project

    Step Action How To
    1 Generate a new project Using the application wizard, specify the CLR Empty Project template.
    2 Set the SubSystem to /SUBSYSTEM:WINDOWS Apply this change in the Project properties, Linker settings, System sub-setting.
    3 Set the Entry Point to main From Project properties, choose Linker settings and then the Advanced sub-setting.
    4 Add references to the following assemblies: System PresentationCore PresentationFramework WindowsBase Note: Except for System, the other three are required for Avalon.

    At this point, your empty project is ready for writing Avalon code. Of course, you don’t have any code yet to compile, but you’ll fix that soon.

    7.2.2 Using procedural code

    You’ll now write your first Avalon application using C++/CLI, and you’ll do so entirely using procedural code. Think of it as analogous to an instruction book for putting together a table that contains only textual instructions (analogous to the procedural code) and no pictures (analogous to the XAML).

    Create a new CLR project using the steps outlined in the previous section, and add an App.cpp file to it (you can call it whatever you want). Listing 7.2 shows the code for the simplest Avalon application that shows a window onscreen.

    Listing 7.2 A simple Avalon app in procedural code

    If you compile and run the application, you’ll see a window onscreen that can be moved, resized, minimized, maximized, and closed. Avalon requires you to set the COM threading model to single threaded apartment (STA). You do so using the STAThread attribute on the main function . You then create a new instance of the Application object (using gcnew) and invoke the Run method on that instance, passing in a new instance of a Window object (again using gcnew) . The Application class represents an Avalon application and provides the core functionality for running the application. It has a Run method that is called to initiate the application’s main thread. The Run method has an overload that accepts a Window object, which you use in the code. This overload launches the application and uses the specified Window as the main application window. The Window class represents the core functionality of a window and by default provides you with basic windowing functionality such as moving, resizing, and so on, which you verified when you ran the application and saw a fully functional window onscreen.

    Note: Those of you who have an MFC background may see a faint similarity between this model and MFC, where the CWinApp class is analogous to the Application class, and the CFrameWnd class is analogous to the Window

    class. CWinApp has a Run method that provides the default message loop, and Application::Run does something similar. Of course, you shouldn’t infer too much from these minor similarities because they’re totally different UI programming models, but it’s possible that a similar design model was used by the architects of Avalon.

    This little program doesn’t have a lot of functionality; it just uses the default Window object to create and show a window onscreen. Let’s write a more refined application with its own Application-derived object as well as a window with some controls. Figure 7.4 shows a screenshot of what the enhanced application

    will look like.

    The main steps involved would be to derive two classes-one from the Window class, and the other from the Application class. You’ll start with the Window-derived class.

    Figure 7.4

    Enhanced WPF app in C++ (procedural code)

    Writing the Window-derived class

    The first thing you’ll do is add a new class called FirstWindow to your project, which will be derived from the Window class. You’ll also add some member variables for the various controls and set some of the window properties in the constructor. Listing 7.3 shows the code once you’ve done that.

    Listing 7.3 A more functional Avalon app in procedural code

    using namespace System;
    
    using namespace System::Windows;
    
    using namespace System::Windows::Controls;
    

    It’s much like Windows Forms programming, except that the controls you declare ①. are from the System::Windows::Controls namespace (which contains various WPF controls). You set properties like Title, Width, Height, and so on on the window object in the constructor ②. There’s also a call to a method called InitControls ③, where you initialize the child controls (I put it into a separate method to improve the code’s readability). Listing 7.4 shows the InitControls method. Basically, you instantiate each of the child controls, instantiate a container control, add the child controls to the container controls, and finally set the container control as the main Content of the parent window.

    Listing 7.4 Function to initialize the Avalon controls

    void InitControls(void)
    
    {
          listbox = gcnew ListBox();
          listbox->Width = 180;
    
          listbox->Height = 350;
    
          Canvas::SetTop(listbox, 10);
    
          Canvas::SetLeft(listbox, 10);
    
          textbox = gcnew TextBox();
    
          textbox->Width = 180;
    
          textbox->Height = 25;
        
          Canvas::SetTop(textbox, 10);
    
          Canvas::SetLeft(textbox, 200);
    
          addbutton = gcnew Button();
    
          addbutton->Width = 80;
    
          addbutton->Height = 25;
    
          addbutton->Content = "Add";
    
          Canvas::SetTop(addbutton, 45);
    
          Canvas::SetLeft(addbutton, 200);
    
          addbutton->Click += gcnew RoutedEventHandler(this, &FirstWindow::OnAddButtonClick);
    
          maincanvas = gcnew Canvas();
    
          maincanvas->Children->Add(listbox);
    
          maincanvas->Children->Add(textbox);
    
          maincanvas->Children->Add(addbutton);
    
          Content = maincanvas;
    }
    

    Again, you probably notice the similarity with Windows Forms programming.

    You instantiate the child controls ①, ②, and ③, and set various properties like Width and Height, and you also use the Canvas::SetTop and Canvas::SetLeft methods to position them on their container. For the button control, you also add an event handler for the Click event ④. Then, you instantiate the Canvas control (which is a container control for other child controls) and add the child controls as its children ⑤. Finally, you set the Content property of the window to this Canvas control ⑥.

    Now, you need to add the Click event handler for the button control, where you add the text entered into the TextBox to the ListBox:

    void OnAddButtonClick(Object^ sender, RoutedEventArgs^ e)
    {
    ​	listbox->Items->Add(textbox->Text);
    ​	textbox->Text = "";
    ​	textbox->Focus();
    }
    

    Notice that you set the text of the TextBox to an empty string once you’ve added it to the ListBox. You also call the Focus() method so that the user can continue

    adding more entries into the ListBox. The Window-derived class is ready. Let’s now write the Application-derived class.

    Writing the Application-derived class

    You derive a class called FirstApp from Application and add an override for the OnStartup method where you create and show the main window:

    #include "FirstWindow.h"
    
    ref class FirstApp : Application
    {
    public:
    FirstApp(void){}
    
    protected:
          virtual void OnStartup(StartupEventArgs^ e) override
          {
              Application::OnStartup(e);
              FirstWindow^ mainwnd = gcnew FirstWindow();
              mainwnd->Show();
          }
    };
    

    The OnStartup method is called, not surprisingly, when the application has just started. You override that function so that you can instantiate and show the window.

    The base function is responsible for invoking any event handlers associated with the Startup event, and thus you need to call the base method in the override.

    Now, all that’s left is to modify the main function to use the custom Application object instead of the default, as shown here:

    #include "FirstApp.h"
    
    [STAThread]
    
    int main(array<String^>^ args)
    {
    	return (gcnew FirstApp())->Run();
    }
    

    Notice that you don’t specify a window object to the Run method, because the window object is created in the OnStartup override of your Application-derived class.

    Compile and run the application, and try entering some text into the TextBox and clicking the Add button. You should see the text being entered into the ListBox.

    When you use procedural code with Avalon, it’s much like using Windows Forms, where you derive classes from the default controls, set some properties, add some event handlers, and are done. Procedural code is all right to develop WPF applications for simple user interfaces, but sometimes it makes better sense

    to take advantage of XAML and declarative programming. As I’ve mentioned a few times already, XAML isn’t directly supported in VC++, so you’ll have to look at alternate options to make use of XAML. One such option is to dynamically load the XAML at runtime.

    7.2.3 Dynamically loading XAML

    In this section, you’ll rewrite the application you wrote in the previous section, using dynamically loaded XAML. This way, you get to leverage the power of XAML and declarative programming (which you couldn’t in the procedural code technique you used in the previous section). Continuing the instruction-book analogy, this will be like one that has textual instructions that refer to pictures (which describe the various steps needed) and are loosely distributed along with the book but not directly printed in the book. You’ll define the UI using XAML instead of procedural code. When you’re done, you’ll have an identical application

    to the one you previously created.

    Create a new C++/CLI Avalon project using the steps mentioned in the introduction to section 7.2, and call it FirstAvalonDynamic (or whatever you want to call it). The first thing you’ll do is write the XAML (MainWindow.xaml) that represents the UI; see listing 7.5.

    Listing 7.5 XAML for the main window

    <Window
    
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    
         Title="First Avalon App (dynamically load XAML)"
    
         Height="400" Width="400"
    
         ResizeMode="NoResize"
    
         > 
    
         <Canvas>
               <ListBox Canvas.Left="10" Canvas.Top="10"
                     Width="180" Height="350"
                     Name="listbox" />
                   <TextBox Canvas.Left="200" Canvas.Top="10"
                     Width="180" Height="25"
                     Name="textbox" />
               <Button Canvas.Left="200" Canvas.Top="45"
                     Width="80" Height="25"
                     Name="addbutton">Add</Button>
         </Canvas>
    </Window>
    

    The XAML shown does exactly what you did with the procedural code earlier. For the control elements, you use the same names using the Name attribute as you use for the member variables in the procedural code. Next, you need to hook an event handler to the Button so that the text entered into the TextBox is inserted

    into the ListBox. For that, you’ll write a helper class, as shown in listing 7.6.

    Listing 7.6 WindowHelper class that implements the event handler

    using namespace System;
    
    using namespace System::Windows;
    
    using namespace System::Windows::Controls;
    
    using namespace System::Windows::Markup;
    
    using namespace System::IO;
    
    ref class WindowHelper
    {
    
         ListBox^ listbox;
    
         TextBox^ textbox;
    
         Button^ addbutton;
    
    
    
    public:
    WindowHelper(Window^ window)
    {
       addbutton = (Button^)window->FindName("addbutton");
    
       textbox = (TextBox^)window->FindName("textbox");
    
       listbox = (ListBox^)window->FindName("listbox");
    
       addbutton->Click += gcnew RoutedEventHandler(
    
       this,&WindowHelper::OnAddButtonClick);
    }
    
    void OnAddButtonClick(Object^ sender, RoutedEventArgs^ e)
    {
       listbox->Items->Add(textbox->Text);
    
       textbox->Text = "";
    
       textbox->Focus();
    }
    
    };
    

    The WindowHelper constructor accepts a Window argument and uses the FindName method ① to get the control with the specified identifier (which maps to the Name attributes you used in the XAML). You also hook an event handler to the addbutton control ②. Finally, you have the event handler③, which is identical to the one you used in the procedural code project. Listing 7.7 shows the code for the Application-derived class, where you override OnStartup as before, except that you create a window dynamically by loading the XAML file from the disk.

    Listing 7.7 The Application-derived class

    ref class FirstAppDynamic : Application
    
    {
    
    public:
    
         FirstAppDynamic(void)
         {
    
         }
    
    protected:
         virtual void OnStartup(StartupEventArgs^ e) override
         {
    
               Application::OnStartup(e);
    
               Stream^ st = File::OpenRead("MainWindow.xaml");
    
               Window^ mainwnd = (Window^)XamlReader::Load(st);
    
               st->Close();
    
               WindowHelper^ mainwndhelper = gcnew WindowHelper(mainwnd);
    
               mainwnd->Show();
    
         }
    
    };
    
    

    You open a file stream to the XAML using File::OpenRead ① and use the overload of XamlReader::Load ② that takes a Stream^ as parameter to create a Window object. This Load method works the magic, by reading and parsing the XAML and building a Window object out of it. You instantiate the WindowHelper object and pass

    this Window object as the argument, so that the event handler for the addbutton control is properly set up ③. You then show the window ④ with a call to Show().

    The main method is much the same as before, where you instantiate the Application object and call Run on it:

    [STAThread]
    int main(array<String^>^ args)
    {
    
          return (gcnew FirstAppDynamic())->Run();
    
    }
    

    The advantage of using this technique over using procedural code is that you get to design your UI in XAML, thereby achieving a level of UI/code separation. You can also use Cider or some other XAML designer to quickly design flexible user interfaces, which would involve a good bit of hand-coding in procedural code.

    The disadvantage is that you have to distribute the XAML file with your application, and if you have multiple windows, you then need that many XAML files.

    There’s always the risk of a loosely-distributed XAML file getting corrupted (accidentally or otherwise) or even being deleted. You can embed all the XAML files as resources in the C++/CLI assembly and load them at runtime, but even that involves a lot of extra work. To avoid distributing XAML files loosely with your

    application or embedding them as resources, you may want to use the technique we’ll discuss in the next section: putting the XAML into a C# project and accessing it via a derived class in a C++ project.

    7.2.4 Deriving from a class in a C# DLL

    You’ll write a third variation of the same application in this section. You’ll use a C# control library project for the XAML, and a C++ project that will utilize that XAML control by deriving a control from it. Using the instruction-book analogy again, this is essentially a picture-based, step-by-step guide with the textual

    instructions printed alongside each picture providing some meta-information for the step indicated by that picture. First, use the New Project Wizard to generate a new C# .NET 3.0 Custom Control Library project, and delete the default XAML file generated by the wizard. The default XAML is derived from User-

    Control and isn’t what you want. Add a new XAML file to the C# project that represents a Window, and either use Cider or hand-code the XAML from listing 7.8 into that file.

    Listing 7.8 The Window class definition using XAML

    <Window x:Class="CSXamlLibrary.BaseWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Title="First Avalon App (dynamically load XAML)"
         Height="400" Width="400"
         ResizeMode="NoResize"
         > 
    
         <Canvas>
               <ListBox Canvas.Left="10" Canvas.Top="10"
                     Width="180" Height="350"
                     Name="listbox" x:FieldModifier="protected" />
    
               <TextBox Canvas.Left="200" Canvas.Top="10"
                     Width="180" Height="25"
                     Name="textbox" x:FieldModifier="protected" />
    
               <Button Canvas.Left="200" Canvas.Top="45"
                     Width="80" Height="25"
                     Name="addbutton" x:FieldModifier="protected">Add</Button>
         </Canvas>
    
    </Window>
    

    The XAML is identical to that used in the previous project (where you dynamically loaded it) except for the x:Class attribute for the Window element, which specifies the name of the class that will be generated, and the x:FieldModifier attributes that are applied to the child control elements so they’re generated as protected members in the class (rather than as private which is the default). Build the C# project, and generate the control library. Once that’s done, create a new C++/CLI Avalon project (using the same steps as before), and then add a reference to this C# project. Now, you can write a new Window class that’s derived from the class in the C# DLL, as shown in listing 7.9.

    Listing 7.9 Deriving the main window from the XAML-defined Window class

    using namespace System;
    
    using namespace System::Windows;
    
    using namespace System::Windows::Controls;
    
    
    
    ref class AppMainWindow : CSXamlLibrary::BaseWindow
    {
         public:
               AppMainWindow(void)
               {
                     addbutton->Click += gcnew RoutedEventHandler(this, &AppMainWindow::OnAddButtonClick);
               }
    
               void OnAddButtonClick(Object^ sender, RoutedEventArgs^ e)
               {
    
                     listbox->Items->Add(textbox->Text);
    
                     textbox->Text = "";
    
                     textbox->Focus();
    
               }
    
    };
    

    The code is similar to what you’ve seen thus far, except that it’s a lot cleaner.

    Unlike the first example, you don’t have a lot of clogged procedural code to create the UI. Unlike the second example, you don’t need a helper class to map the XAML elements to the control variables and event handlers. It’s definitely an improvement over the previous two examples, but you have to bring in the C#

    project just for the XAML. The rest of the code needed for the application is more or less similar to what you saw earlier:

    ref class FirstAppDerived : Application
    {
          protected:
                virtual void OnStartup(StartupEventArgs^ e) override
                {
                      Application::OnStartup(e);
                      AppMainWindow^ mainwnd = gcnew AppMainWindow();
                      mainwnd->Show();
                }
    
    };
    
    [STAThread]
    
    int main(array<String^>^ args)
    {
          return (gcnew FirstAppDerived())->Run();
    }
    

    In some ways, the third technique is a sort of hybrid of the previous two techniques.

    A lot of the code is identical to that in the first technique – as with the declaration of a custom class derived from Window and an Application-derived class with the OnStartup method creating the custom window. But, like the second technique, the UI definition is in the XAML, except that in this case, it’s compiled into the C# DLL. You also reduce lines of code with each successive technique. You had the most lines of code with procedural code (as is to be expected) and improved on that considerably when you moved the UI definition to the XAML in the dynamically-loaded XAML example. In the last example, you saved even further on lines of code, such as the helper class from the second example that had to wire the XAML elements to the member variables. Of course, the total lines of code (LOC) isn’t always the single deciding factor that determines what technique you choose. Table 7.2 shows a comparison of the three techniques; for each factor, the cells with the bold text reflect the technique (or techniques) that offer maximum performance (or convenience).

    Table 7.2 Comparison of the three techniques

    Procedural code Dynamically load XAML XAML in C# DLL
    Cluttered code that generates the UI Yes No No
    Dependency on loose XAML files No Yes No
    Dependency on C#-based DLL No No Yes
    Lines of code Maximum In-between Minimum
    UI design convenience Poor Excellent Excellent
    UI/business logic separation Poor Good Excellent
    Level of Visual C++ project support Total Partial (Not applicable)

    It’s hard to pinpoint a specific technique and claim that it’s the best one, because depending on your requirements, each has advantages and disadvantages. Of course, in the future, if Visual C++ has direct support for XAML (as I believe it will), that will be your best option for the majority of scenarios.

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※教你寫出一流的銷售文案?

  • “你開廠門 我開方便之門” ——福建省市場監管系統“促產”側記

      中國消費者報報道(記者 張文章)最近是企業復工復產的高峰期,然而復工復產、疫情防控兩手抓,兩手都要硬。復工復產面臨許多困難和擔憂:員工食堂就餐怎麼才安全?商事辦理如何才簡便?企業趕工,設備運作如何跟進?別擔心,福建省市場監管局早幫企業想好了,及時推出6方面16條服務措施,全力支持推動生產企業復產、重點項目復工。並呼籲相關企業大膽開門復產,把失去的時間搶回來,補回來。

      復工怎麼吃飯 築防線

      隨着復工復產高峰期臨近,集體用餐需求顯著增加,為深入做好新冠肺炎疫情防控工作,防範群體性聚餐可能引發的風險,福建省市場監管部門牽頭整合美團、餓了么等網絡訂餐平台和餐飲企業搭建疫情期間集體用餐配送服務平台,在保供應、保質量、強信心方面起到了积極作用。

      福州市台江區對復工企業食堂衛生狀況進行檢查,嚴查食材進貨來源,要求分時段分餐制,避免扎堆就餐。同時嚴格環境消殺,下發《預防性消毒工作手冊》,督促農貿市場、超市、餐飲店、非星級酒店嚴格落實清潔消毒制度,每日開市前、收市后全面消毒,加大對重點區域、重點設施設備消毒頻次。規範網絡外賣平台經營,推行無接觸配送。

      廈門市集美區杏林市場監管所“嚴把三關”,做好“小餐飲”復工安全。復工前,申請報備關。全面摸排掌握轄區“小餐飲”數據庫,通過電話、微信等,向2571家餐飲經營者詳細告知復工標準,督促餐飲單位在恢復營業前,提前向市場監管部門報備。復工時,現場檢查關。收到經營者報備后,執法人員按照網格劃分及時到現場檢查,對從人員健康狀況、體溫檢測、場所消殺、庫存食材清理等各方面進行詳細指導和嚴格把關。復工后,日常監督關。通過網格員每日現場巡查、微信宣傳、發動社區群眾舉報等方式,做好已復工“小餐飲”的日常監督。

      泉州市市場監管部門加強外賣訂餐平台監管,在疫情防控期間全面實行“無接觸送餐”;鼓勵入網餐飲單位使用“食安封簽”,避免送餐過程二次污染;指導公司選擇證照齊全、供餐資質和能力符合要求的單位訂餐,並設立專門接收台,實行“不見面取餐”;鼓勵企業發動交通方便的員工回家用餐,或自帶餐食解決用餐問題,進一步減少辦公場所用餐時段的人員密度和出入頻次。

      莆田市荔城區已形成市場、超市、餐飲、藥店常態化監管模式,持續提示餐飲服務單位轉變經營思路,採取打包、外賣、分餐配送等非堂食堂聚的經營模式,避免人群聚集傳播風險;有效督促市場開辦者及檔口經營者自律經營,嚴格落實禁止野生動物交易要求,建立健全索證索票、進貨查驗等制度,切實做好食品快檢及公示工作,做到“早發現、早溯源、早處置”,有效保障群眾“舌尖上的安全”。

      備案申請怎麼審批 特事特辦

      為全面有效防控疫情,全力保障人民群眾的生命安全和身體健康,切實提供便捷優質的企業註銷及商事登記服務,福建省市場監管部門為企業提供足不出戶的“網上辦“服務。

      福州市高新區市場監管部門開啟企業復工復產網上辦,利用釘釘App在線受理企業復工申請,開展不見面服務。對企業數據進行實時分析,對於符合高新區復工要求的予以備案。全面推行自主年報制度,通過微信、電話、短信等方式指導企業依法履行信息公示義務,激活更多企業投入生產經營,避免信用受損。

      漳州市長泰縣市場監管局為有效減少人員聚集,暫停窗口現場服務,全面推行“網上辦、掌上辦、郵寄辦、預約辦”審批服務模式,並公示了窗口諮詢電話。對於保障疫情防控工作需要的緊急業務,立足職能,特事特辦、急事急辦,着力打通抗‘疫’審批最後一公里。

      莆田市荔城區市場監管部門充分依託“網上辦、掌上辦、寄遞辦、預約辦”等有效手段,為市場主體提供“零見面、零跑腿、零成本”的高效優質服務,進一步壓減登記註冊環節、時間和成本。對生產企業轉產生產口罩、防護服等應急物資的,簡化生產資質審批程序,實行非要件容缺後補,對可通過數據共享獲取的材料,不要求申請人重複提交。

      三明市大田縣市場監管局加碼提速簡化審批程序,推行“非接觸式”的电子辦照渠道,實行企業名稱自由申報、企業設立網上辦,同時积極引導群眾通過“網上預審+雙向快遞”的方式寄送申請材料並領取證照和相關文書。深化個體工商戶登記制度改革,針對需線下辦證的特殊人群實現“15分鐘辦證圈”。

      設備安全怎麼保障 提供專業服務

      為全面保障疫情期間和節后復工復產企業的特種設備安全,進一步落實特種設備使用單位安全主體責任,福建省市場監管部門對特種設備安全進行了專項檢查。

      廈門市集美區市場監管局第一時間採取微信監管工作群轉發的宣傳形式,督促相關責任單位嚴格落實責任制。聚焦公眾聚集場所使用的特種設備和盛裝極度或高度危害介質、易燃易爆介質的承壓特種設備,採取科所聯動的監管模式,圍繞轄區復工復產企業、已開業的大型商場、樓座較多的居民小區、醫院、地鐵等主要場所加大巡查力度,重點查看在用電梯、鍋爐、液氧儲氣罐等特種設備的檢驗報告、維保記錄、使用單位的安全管理制度、事故應急措施和救援預案等情況。

      泉州市市場監管局組織省特檢院泉州分院和石化中心等兩個特種設備檢驗單位,充分利用特種設備安全監察平台,全面排查受疫情影響需要檢驗的特種設備,主動電話逐家聯繫各使用單位,及時了解復產復工安排,為即將復產復工企業開闢綠色通道,確保企業順利開工。

    責任編輯:邊靜

    本站聲明:網站內容來源再生能源資訊網http://www.ccn.com.cn/,如有侵權請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※教你寫出一流的銷售文案?

  • 一秒看完,2020 最新各縣市電動機車補助總整理

    一秒看完,2020 最新各縣市電動機車補助總整理

    電動機車補助是所有想要購車的朋友最關心的議題,由於各縣市環保局的補助金額不同,常常看得一頭霧水,今年我們一樣整理了這張比較表讓你一眼就能看完,還可以幫你排序找出補助最多的縣市喔。

    電動機車補助分為中央與地方兩部分,2020 年的中央補助來自工業局與環保署,不分縣市都能獲得汰舊換新最高 1 萬 2 千元補助,新購電動機車則是 7 千元。

    比較麻煩的是,地方政府的補助配合施政方針而有所不同,我們幫各位全部整理在一張表內,這個金額包含了中央與地方政府的補助,讓大家可以快速看清楚,點擊欄位還能自動排序唷。

    金門的補助金額從去年 4 月公佈後就從最後一名變成冠軍,今年依然延續高額補助,成為各縣市補助最給力的地方政府。

    花蓮台東則是依靠花東基金的補助,而擁有不錯的額度,然而花東基金有名額限制,要獲得補助的朋友需要把握時間申請。

    在今年度的補助中,還有一些縣市佛心提供了中低收入戶補助,我們另外整理出列表如下,趕快分享給符合資格的朋友看看吧。

    以上是我們為各位整理 2020 年電動機車補助金額的資料,其中未包含交通部提供的 ABS 與 CBS 煞車系統補助(1,000 元),此外值得注意的是,各縣市對於新款七期燃油機車也都有提供相關補助,本表僅供參考,實際購車金額還是要與經銷商確認。

    如果想要了解各縣市政府補助金額的細節資料,也可以參考環保署提供的,裡面還有聯絡方式可供確認唷。

    (合作媒體:。首圖來源:攝)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※教你寫出一流的銷售文案?

  • 談反應式編程在服務端中的應用,數據庫操作優化,提速 Upsert

    談反應式編程在服務端中的應用,數據庫操作優化,提速 Upsert

    反應式編程在客戶端編程當中的應用相當廣泛,而當前在服務端中的應用相對被提及較少。本篇將介紹如何在服務端編程中應用響應時編程來改進數據庫操作的性能。

    開篇就是結論

    接續上一篇《談反應式編程在服務端中的應用,數據庫操作優化,從 20 秒到 0.5 秒》之後,這次,我們帶來了關於利用反應式編程進行 upsert 優化的案例說明。建議讀者可以先閱讀一下前一篇,這樣更容易理解本篇介紹的方法。

    同樣還是利用批量化的思路,將單個 upsert 操作批量進行合併。已達到減少數據庫鏈接消耗從而大幅提升性能的目的。

    業務場景

    在最近的一篇文章《十萬同時在線用戶,需要多少內存?——Newbe.Claptrap 框架水平擴展實驗》中。我們通過激活多個常駐於內存當中的 Claptrap 來實現快速驗證 JWT 正確性的目的。

    但,當時有一個技術問題沒有得到解決:

    Newbe.Claptrap 框架設計了一個特性:當 Claptrap Deactive 時,可以選擇將快照立即保存到數據庫。因此,當嘗試從集群中關閉一個節點時,如果節點上存在大量的 Claptrap ,那麼將產生大量的數據庫 upsert 操作。瞬間推高數據庫消耗,甚至導致部分錯誤而保存失敗。

    一點點代碼

    有了前篇的 IBatchOperator,那麼留給這篇的代碼內容就非常少了。

    首先,按照使用上一篇的 IBatchOperator 編寫一個支持操作的 Repository,形如以下代碼:

    public class BatchUpsert : IUpsertRepository
    {
    private readonly IDatabase _database;
    private readonly IBatchOperator<(int, int), int> _batchOperator;

    public BatchUpsert(IDatabase database)
    {
    _database = database;
    var options = new BatchOperatorOptions<(int, int), int>
    {
    BufferCount = 100,
    BufferTime = TimeSpan.FromMilliseconds(50),
    DoManyFunc = DoManyFunc
    };
    _batchOperator = new BatchOperator<(int, int), int>(options);
    }

    private Task<int> DoManyFunc(IEnumerable<(int, int)> arg)
    {
    return _database.UpsertMany(arg.ToDictionary(x => x.Item1, x => x.Item2));
    }

    public Task UpsertAsync(int key, int value)
    {
    return _batchOperator.CreateTask((key, value));
    }
    }

    然後,只要實現對應數據庫的 UpsertMany 方法,便可以很好地完成這項優化。

    各種數據庫的操作

    結合 Newbe.Claptrap 現在項目的實際。目前,被支持的數據庫分別有 SQLite、PostgreSQL、MySql 和 MongoDB。以下,分別對不同類型的數據庫的批量 Upsert 操作進行說明。

    由於在 Newbe.Claptrap 項目中的 Upsert 需求都是以主鍵作為對比鍵,因此以下也只討論這種情況。

    SQLite

    根據官方文檔,使用 INSERT OR REPLACE INTO 便可以實現主鍵衝突時替換數據的需求。

    具體的語句格式形如以下:

    INSERT OR REPLACE INTO TestTable (id, value)
    VALUES
    (@id0,@value0),
    ...
    (@idn,@valuen);

    因此只要直接拼接語句和參數調用即可。需要注意的是,SQLite 的可傳入參數默認為 999,因此拼接的變量也不應大於該數量。

    官方文檔:INSERT

    PostgreSQL

    眾所周知,PostgreSQL 在進行批量寫入時,可以使用高效的 COPY 語句來完成數據的高速導入,這遠遠快於 INSERT 語句。但可惜的是 COPY 並不能支持 ON CONFLICT DO UPDATE 子句。因此,無法使用 COPY 來完成 upsert 需求。

    因此,我們還是回歸使用 INSERT 配合 ON CONFLICT DO UPDATE 子句,以及 unnest 函數來完成批量 upsert 的需求。

    具體的語句格式形如以下:

    INSERT INTO TestTable (id, value)
    VALUES (unnest(@ids), unnest(@values))
    ON CONFLICT ON CONSTRAINT TestTable_pkey
    DO UPDATE SET value=excluded.value;

    其中的 ids 和 values 分別為兩個等長的數組對象,unnest 函數可以將數組對象轉換為行數據的形式。

    注意,可能會出現 ON CONFLICT DO UPDATE command cannot affect row a second time 錯誤。

    因此如果嘗試使用上述方案,需要在傳入數據庫之前,先在程序中去重一遍。而且,通常來說,在程序中進行一次去重可以減少向數據庫中傳入的數據,這本身也很有意義。

    官方文檔:unnest 函數
    官方文檔:Insert 語句

    MySql

    MySql 與 SQLite 類似,支持 REPLACE 語法。具體語句形式如下:

    REPLACE INTO TestTable (id, value)
    VALUES
    (@id0,@value0),
    ...
    (@idn,@valuen);

    官方文檔:REPLACE 語句

    MongoDB

    MongoDB 原生支持 bulkWrite 的批量傳輸模式,也支持 replace 的 upsert 語法。因此操作非常簡單。

    那麼這裏展示一下 C# 操作方法:

    private async Task SaveManyCoreMany(
    IDbFactory dbFactory,
    IEnumerable<StateEntity> entities)
    {
    var array = entities as StateEntity[] ?? entities.ToArray();
    var items = array
    .Select(x => new MongoStateEntity
    {
    claptrap_id = x.ClaptrapId,
    claptrap_type_code = x.ClaptrapTypeCode,
    version = x.Version,
    state_data = x.StateData,
    updated_time = x.UpdatedTime,
    })
    .ToArray();

    var client = dbFactory.GetConnection(_connectionName);
    var db = client.GetDatabase(_databaseName);
    var collection = db.GetCollection<MongoStateEntity>(_stateCollectionName);

    var upsertModels = items.Select(x =>
    {
    var filter = new ExpressionFilterDefinition<MongoStateEntity>(entity =>
    entity.claptrap_id == x.claptrap_id && entity.claptrap_type_code == x.claptrap_type_code);
    return new ReplaceOneModel<MongoStateEntity>(filter, x)
    {
    IsUpsert = true
    };
    });
    await collection.BulkWriteAsync(upsertModels);
    }

    這是從 Newbe.Claptrap 項目業務場景中給出的代碼,讀者可以結合自身需求進行修改。

    官方文檔:db.collection.bulkWrite ()

    通用型解法

    優化的本質是減少數據庫鏈接的使用,盡可能在一個鏈接內完成更多的工作。因此如果特定的數據庫不支持以上數據庫類似的操作。那麼還是存在一種通用型的解法:

    1. 以盡可能快地方式將數據寫入一臨時表
    2. 將臨時表的數據已連表 update 的方式更新的目標表
    3. 刪除臨時表

    UPDATE with a join

    性能測試

    以 SQLite 為例,嘗試對 12345 條數據進行 2 次 upsert 操作。

    單條併發:1 分 6 秒

    批量處理:2.9 秒

    可以在該鏈接找到測試的代碼。

    樣例中不包含有 MySql、PostgreSQL 和 MongoDB 的樣例,因為沒有優化之前,在不提高連接池的情況下,一併發基本就爆炸了。所有優化的結果是直接解決了可用性的問題。

    所有的示例代碼均可以在代碼庫中找到。如果 Github Clone 存在困難,也可以點擊此處從 Gitee 進行 Clone

    常見問題解答

    此處對一些常見的問題進行解答。

    客戶端是等待批量操作的結果嗎?

    這是一個很多網友提出的問題。答案是:是的。

    假設我們公開了一個 WebApi 作為接口,由瀏覽器調用。如果同時有 100 個瀏覽器同時發出請求。

    那麼這 100 個請求會被合併,然後寫入數據庫。而在寫入數據庫之前,這些客戶端都不會得到服務端的響應,會一直等待。

    這也是該合併方案區別於普通的 “寫隊列,后寫庫” 方案的地方。

    原理上講,這種和 bulkcopy 有啥不一樣?

    兩者是不相關,必須同時才有作用的功能。
    首先,代碼中的 database.InsertMany 就是你提到的 bulkcopy。

    這個代碼的關鍵不是 InsertMany ,而是如何將單次的插入請求合併。
    試想一下,你可以在 webapi 上公開一個 bulkcopy 的 API。
    但是,你無法將來自不同客戶端的請求合併在同一個 API 裏面來調用 bulkcopy。
    例如,有一萬個客戶端都在調用你的 API,那怎麼合併這些 API 請求呢?

    如果如果通過上面這種方式,雖然你只是對外公開了一個單次插入的 API。你卻實現了來自不同客戶端請求的合併,變得可以使用 bulkcopy 了。這在高併發下很有意義。

    另外,這符合開閉的原理,因為你沒有修改 Repository 的 InsertOne 接口,卻實現了 bulkcopy
    的效果。

    如果批量操作中一個操作異常失敗是否會導致被合併的其他操作全部失敗?

    如果業務場景是合併會有影響,那當然不應該合併。

    批量操作一個失敗,當然是一起失敗,因為底層的數據庫事務肯定也是一起失敗。

    除非批量接口也支持對每個傳入的 ID 做區別對待。典型的,比如 mongodb 的 bulkcopy 可以返回哪些成功哪些失敗,那麼我們就有能力設置不同的 Tcs 狀態。

    哪些該合併,哪些不該合併,完全取決於業務。樣例給出的是如果要合併,應該怎麼合併。不會要求所有都要合併。

    Insert 和 Upsert 都說了,那 Delete 和 Select 呢?

    筆者籠統地將該模式稱為 “反應式批量處理”。要確認業務場景是否應用該模式,需要具備以下這兩個基本的要求:

    • 業務下游的批量處理是否會比累積的單條處理要快,如果會,那可以用
    • 業務上游是否會出現短時間的突增頻率的請求,如果會,那可以用

    當然,還需要考量,比如:下游的批量操作能否卻分每個請求的結果等等問題。但以上兩點是一定需要考量的。

    那麼以 Delete 為例:

    • Delete Where In 的速度會比 Delete = 的速度快嗎?試一下
    • 會有突增的 Delete 需求嗎?想一下

    小小工具 Zeal

    筆者是一個完整存儲過程都寫不出來的人。能夠查閱到這些數據庫的文檔,全靠一款名為 Zeal 的離線文檔查看免費軟件。推薦給您,您也值得擁有。

    Zeal 官網地址:https://zealdocs.org/

    最後但是最重要!

    最近作者正在構建以反應式Actor模式事件溯源為理論基礎的一套服務端開發框架。希望為開發者提供能夠便於開發出 “分佈式”、“可水平擴展”、“可測試性高” 的應用系統 ——Newbe.Claptrap

    本篇文章是該框架的一篇技術選文,屬於技術構成的一部分。如果讀者對該內容感興趣,歡迎轉發、評論、收藏文章以及項目。您的支持是促進項目成功的關鍵。

    如果你對該項目感興趣,你可以通過 github issues 提交您的看法。

    如果您無法正常訪問 github issue,您也可以發送郵件到 newbe-claptrap@googlegroups.com 來參与我們的討論。

    點擊鏈接 QQ 交流【Newbe.Claptrap】:https://jq.qq.com/?_wv=1027&k=5uJGXf5。

    您還可以查閱本系列的其他選文:

    • Newbe.Claptrap – 一套以 “事件溯源” 和 “Actor 模式” 作為基本理論的服務端開發框架
    • 十萬同時在線用戶,需要多少內存?——Newbe.Claptrap 框架水平擴展實驗
    • 談反應式編程在服務端中的應用,數據庫操作優化,從 20 秒到 0.5 秒
    • 談反應式編程在服務端中的應用,數據庫操作優化,提速 Upsert
    • Newbe.Claptrap 項目周報 1 – 還沒輪影,先用輪跑

    GitHub 項目地址:https://github.com/newbe36524/Newbe.Claptrap

    Gitee 項目地址:https://gitee.com/yks/Newbe.Claptrap

     

    • 本文作者: newbe36524
    • 本文鏈接: https://www.newbe.pro/Newbe.Claptrap/Reactive-In-Server-2/
    • 版權聲明: 本博客所有文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※教你寫出一流的銷售文案?

  • 使用 Prometheus-Operator 監控 Calico

    使用 Prometheus-Operator 監控 Calico

    原文鏈接:https://fuckcloudnative.io/posts/monitoring-calico-with-prometheus-operator/

    Calico 中最核心的組件就是 Felix,它負責設置路由表和 ACL 規則等,以便為該主機上的 endpoints 資源正常運行提供所需的網絡連接。同時它還負責提供有關網絡健康狀況的數據(例如,報告配置其主機時發生的錯誤和問題),這些數據會被寫入 etcd,以使其對網絡中的其他組件和操作人員可見。

    由此可見,對於我們的監控來說,監控 Calico 的核心便是監控 FelixFelix 就相當於 Calico 的大腦。本文將學習如何使用 Prometheus-Operator 來監控 Calico。

    本文不會涉及到 CalicoPrometheus-Operator 的部署細節,如果不知道如何部署,請查閱官方文檔和相關博客。

    1. 配置 Calico 以啟用指標

    默認情況下 Felix 的指標是被禁用的,必須通過命令行管理工具 calicoctl 手動更改 Felix 配置才能開啟,需要提前配置好命令行管理工具。

    本文使用的 Calico 版本是 v3.15.0,其他版本類似。先下載管理工具:

    $ wget https://github.com/projectcalico/calicoctl/releases/download/v3.15.0/calicoctl -O /usr/local/bin/calicoctl
    $ chmod +x /usr/local/bin/calicoctl
    

    接下來需要設置 calicoctl 配置文件(默認是 /etc/calico/calicoctl.cfg)。如果你的 Calico 後端存儲使用的是 Kubernetes API,那麼配置文件內容如下:

    apiVersion: projectcalico.org/v3
    kind: CalicoAPIConfig
    metadata:
    spec:
      datastoreType: "kubernetes"
      kubeconfig: "/root/.kube/config"
    

    如果 Calico 後端存儲使用的是 etcd,那麼配置文件內容如下:

    apiVersion: projectcalico.org/v3
    kind: CalicoAPIConfig
    metadata:
    spec:
      datastoreType: "etcdv3"
      etcdEndpoints: https://192.168.57.51:2379,https://192.168.57.52:2379,https://192.168.57.53:2379
      etcdKeyFile: /opt/kubernetes/ssl/server-key.pem
      etcdCertFile: /opt/kubernetes/ssl/server.pem
      etcdCACertFile: /opt/kubernetes/ssl/ca.pem
    

    你需要將其中的證書路徑換成你的 etcd 證書路徑。

    配置好了 calicoctl 之後就可以查看或修改 Calico 的配置了,先來看一下默認的 Felix 配置:

    $ calicoctl get felixConfiguration default -o yaml
    
    apiVersion: projectcalico.org/v3
    kind: FelixConfiguration
    metadata:
      creationTimestamp: "2020-06-25T14:37:28Z"
      name: default
      resourceVersion: "269031"
      uid: 52146c95-ff97-40a9-9ba7-7c3b4dd3ba57
    spec:
      bpfLogLevel: ""
      ipipEnabled: true
      logSeverityScreen: Info
      reportingInterval: 0s
    

    可以看到默認的配置中沒有啟用指標,需要手動修改配置,命令如下:

    $ calicoctl patch felixConfiguration default  --patch '{"spec":{"prometheusMetricsEnabled": true}}'
    

    Felix 暴露指標的端口是 9091,可通過檢查監聽端口來驗證是否開啟指標:

    $ ss -tulnp|grep 9091
    tcp    LISTEN     0      4096   [::]:9091               [::]:*                   users:(("calico-node",pid=13761,fd=9))
    
    $ curl -s http://localhost:9091/metrics
    # HELP felix_active_local_endpoints Number of active endpoints on this host.
    # TYPE felix_active_local_endpoints gauge
    felix_active_local_endpoints 1
    # HELP felix_active_local_policies Number of active policies on this host.
    # TYPE felix_active_local_policies gauge
    felix_active_local_policies 0
    # HELP felix_active_local_selectors Number of active selectors on this host.
    # TYPE felix_active_local_selectors gauge
    felix_active_local_selectors 0
    ...
    

    2. Prometheus 採集 Felix 指標

    啟用了 Felix 的指標后,就可以通過 Prometheus-Operator 來採集指標數據了。Prometheus-Operator 在部署時會創建 PrometheusPodMonitorServiceMonitorAlertManagerPrometheusRule 這 5 個 CRD 資源對象,然後會一直監控並維持這 5 個資源對象的狀態。其中 Prometheus 這個資源對象就是對 Prometheus Server 的抽象。而 PodMonitorServiceMonitor 就是 exporter 的各種抽象,是用來提供專門提供指標數據接口的工具,Prometheus 就是通過 PodMonitorServiceMonitor 提供的指標數據接口去 pull 數據的。

    ServiceMonitor 要求被監控的服務必須有對應的 Service,而 PodMonitor 則不需要,本文選擇使用 PodMonitor 來採集 Felix 的指標。

    PodMonitor 雖然不需要應用創建相應的 Service,但必須在 Pod 中指定指標的端口和名稱,因此需要先修改 DaemonSet calico-node 的配置,指定端口和名稱。先用以下命令打開 DaemonSet calico-node 的配置:

    $ kubectl -n kube-system edit ds calico-node
    

    然後在線修改,在 spec.template.sepc.containers 中加入以下內容:

            ports:
            - containerPort: 9091
              name: http-metrics
              protocol: TCP
    

    創建 Pod 對應的 PodMonitor

    # prometheus-podMonitorCalico.yaml
    apiVersion: monitoring.coreos.com/v1
    kind: PodMonitor
    metadata:
      labels:
        k8s-app: calico-node
      name: felix
      namespace: monitoring
    spec:
      podMetricsEndpoints:
      - interval: 15s
        path: /metrics
        port: http-metrics
      namespaceSelector:
        matchNames:
        - kube-system
      selector:
        matchLabels:
          k8s-app: calico-node
    
    $ kubectl apply -f prometheus-podMonitorCalico.yaml
    

    有幾個參數需要注意:

    • PodMonitor 的 name 最終會反應到 Prometheus 的配置中,作為 job_name

    • podMetricsEndpoints.port 需要和被監控的 Pod 中的 ports.name 相同,此處為 http-metrics

    • namespaceSelector.matchNames 需要和被監控的 Pod 所在的 namespace 相同,此處為 kube-system

    • selector.matchLabels 的標籤必須和被監控的 Pod 中能唯一標明身份的標籤對應。

    最終 Prometheus-Operator 會根據 PodMonitor 來修改 Prometheus 的配置文件,以實現對相關的 Pod 進行監控。可以打開 Prometheus 的 UI 查看監控目標:

    注意 Labels 中有 pod="calico-node-xxx",表明監控的是 Pod。

    3. 可視化監控指標

    採集完指標之後,就可以通過 Grafana 的儀錶盤來展示監控指標了。Prometheus-Operator 中部署的 Grafana 無法實時修改儀錶盤的配置(必須提前將儀錶盤的 json 文件掛載到 Grafana Pod 中),而且也不是最新版(7.0 以上版本),所以我選擇刪除 Prometheus-Operator 自帶的 Grafana,自行部署 helm 倉庫中的 Grafana。先進入 kube-prometheus 項目的 manifests 目錄,然後將 Grafana 相關的部署清單都移到同一個目錄下,再刪除 Grafana:

    $ cd kube-prometheus/manifests
    $ mkdir grafana
    $ mv grafana-* grafana/
    $ kubectl delete -f grafana/
    

    然後通過 helm 部署最新的 Grafana:

    $ helm install grafana stable/grafana -n monitoring
    

    訪問 Grafana 的密碼保存在 Secret 中,可以通過以下命令查看:

    $ kubectl -n monitoring get secret grafana -o yaml
    
    apiVersion: v1
    data:
      admin-password: MnpoV3VaMGd1b3R3TDY5d3JwOXlIak4yZ3B2cTU1RFNKcVY0RWZsUw==
      admin-user: YWRtaW4=
      ldap-toml: ""
    kind: Secret
    metadata:
    ...
    

    對密碼進行解密:

    $ echo -n "MnpoV3VaMGd1b3R3TDY5d3JwOXlIak4yZ3B2cTU1RFNKcVY0RWZsUw=="|base64 -d
    

    解密出來的信息就是訪問密碼。用戶名是 admin。通過用戶名和密碼登錄 Grafana 的 UI:

    添加 Prometheus-Operator 的數據源:

    Calico 官方沒有單獨 dashboard json,而是將其放到了 ConfigMap 中,我們需要從中提取需要的 json,提取出 felix-dashboard.json 的內容,然後將其中的 datasource 值替換為 prometheus。你可以用 sed 替換,也可以用編輯器,大多數編輯器都有全局替換的功能。如果你實在不知道如何提取,可以使用我提取好的 json:

    修改完了之後,將 json 內容導入到 Grafana:

    最後得到的 Felix 儀錶盤如下圖所示:

    如果你對我截圖中 Grafana 的主題配色很感興趣,可以參考這篇文章:Grafana 自定義主題。

    Kubernetes 1.18.2 1.17.5 1.16.9 1.15.12離線安裝包發布地址http://store.lameleg.com ,歡迎體驗。 使用了最新的sealos v3.3.6版本。 作了主機名解析配置優化,lvscare 掛載/lib/module解決開機啟動ipvs加載問題, 修復lvscare社區netlink與3.10內核不兼容問題,sealos生成百年證書等特性。更多特性 https://github.com/fanux/sealos 。歡迎掃描下方的二維碼加入釘釘群 ,釘釘群已經集成sealos的機器人實時可以看到sealos的動態。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※教你寫出一流的銷售文案?

  • 東京奧運聖火傳遞福島起點 被查出輻射量異常

    摘錄自2019年12月4日自由時報報導

    日本東京奧運聖火明年3月底從福島縣的足球國練中心「J-VILLAGE」出發,但日本環境省今(4日)透露,「J-VILLAGE」相鄰的停車場有部分區域空間輻射量較高,當局已要求東京電力公司再次去污。

    J-VILLAGE位於福島縣濱通南部,2011年福島核災發生後,由於此處距離福島核一廠僅有20公里,被政府借用為核災事故處理的對應據點,該中心今年4月下旬才全面恢復營運,因具有災區重建的重大象徵意義,所以被選為聖火傳遞的起點。

    根據《共同社》報導,環保團體綠色和平組織10月對J-VILLAGE周圍展開調查,發現異常的輻射量,隨後將結果送交環境省。

    環境省表示,空間輻射量較高的是與J-VILLAGE相鄰的楢葉町營停車場部分區域,已要求東電對該地區未經鋪設的地面再次去污。東電3日去除了周圍約0.03立方米的土和草,調查放射性物質的種類等。

    根據東電的調查,在去污地區1公尺高的位置測得每小時1.79微西弗的輻射量,超過日本政府訂定的0.23微西弗的去污標準。地表輻射量為70.2微西弗。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※教你寫出一流的銷售文案?

  • 奧迪2018年量產首款純電動SUV汽車

    奧迪準備2018年在布魯塞爾量產首款純電動SUV汽車。布魯塞爾的奧迪工廠會同時製造汽車和電池,它還要向大眾其它汽車提供電池。

    在2015年舉行的法蘭克福汽車展上,奧迪展示了e-tron概念車,它預示著奧迪即將推出量產版本的SUV,汽車取名為“Q6 e-tron”。

    Q6 e-tron配有3個電動機,一個位於前軸,兩個放在後面。大型電池組安裝在前後軸之間,位於乘客座位的下方,這樣可以降低重心,提供更好的平衡性。

    Q6 e-tron安裝的電池來自韓國LG化學和三星SDI,充電一次可以行駛約500千米。資料是以歐洲測試週期作為標準的,如果用美國環境保護署(EPA)的標準測試里程會短一些。因此,Q6 e-tron充電一次的行駛距離估計為390千米,這個資料更為合理一些。

    目前布魯塞爾的奧迪工廠主要負責生產A1,奧迪會將A1生產線轉移到西班牙工廠,讓布魯塞爾負責生產Q6 e-tron。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※教你寫出一流的銷售文案?

  • FastDFS圖片服務器單機安裝步驟(修訂版)

    FastDFS圖片服務器單機安裝步驟(修訂版)

    前面已經講 ,通過此文章可以了解FastDFS組件中單機安裝流程。

    單機版架構圖

    以下為單機FastDFS安裝步驟

    一、環境準備

    CentOS 7.X

    使用的版本: libfastcommon-1.0.41.tar.gz

    使用的版本: fastdfs-6.01.tar.gz

    使用的版本:fastdfs-nginx-module-1.21.tar.gz

    使用的版本: nginx-1.16.1.tar.gz

    二、安裝過程

    1、安裝 libfastcommon-1.0.41.tar.gz

    tar -zxvf libfastcommon-1.0.41.tar.gz
    cd libfastcommon-1.0.41/
    ./make.sh
    ./make.sh install

    2、安裝 FastDFS

    tar -zxvf  fastdfs-6.01.tar.gz
    cd fastdfs-6.01/
    ./make.sh
    ./make.sh install

    準備配置文件

    cp /etc/fdfs/tracker.conf.sample /etc/fdfs/tracker.conf
    cp /etc/fdfs/storage.conf.sample /etc/fdfs/storage.conf
    cp /etc/fdfs/client.conf.sample /etc/fdfs/client.conf
    cd /opt/apps/fastdfs-6.01/conf
    cp http.conf mime.types /etc/fdfs/

    Tracker Server 配置

    vim /etc/fdfs/tracker.conf
    修改配置如下:
    #tracker server端口號
    port=22122
    #存儲日誌和數據的根目錄
    base_path=/opt/fastdfs/tracker
    #HTTP服務端口
    http.server_port=80
    開放防火牆端口

    1、打開跟蹤端口

    vim /etc/sysconfig/iptables

    2、添加以下端口行:

    -A INPUT -m state --state NEW -m tcp -p tcp --dport 22122 -j ACCEPT

    3、重啟防火牆

    service iptables restart
    啟動Tracker
    /etc/init.d/fdfs_trackerd start

    Storage Server 配置

    vim /etc/fdfs/storage.conf
    修改配置如下:
    #storage server端口號
    port=23000
    #數據和日誌文件存儲根目錄
    base_path=/opt/fastdfs/storage
    #第一個存儲目錄
    store_path0=/opt/fastdfs/storepath0
    #tracker服務器IP和端口
    tracker_server=192.168.0.1:22122
    #http訪問文件的端口(默認8888,看情況修改,和nginx中保持一致)
    http.server_port=8888
    開放防火牆端口

    1、打開跟蹤端口

    vim /etc/sysconfig/iptables

    2、添加以下端口行:

    -A INPUT -m state --state NEW -m tcp -p tcp --dport 23000 -j ACCEPT

    3、重啟防火牆

    service iptables restart
    啟動Storage
    /etc/init.d/fdfs_storaged start
    查看集群狀態
     fdfs_monitor /etc/fdfs/storage.conf list
    

    查看狀態是否正常

    Storage 1:
    id = 6.0.36.243
    ip_addr = 6.0.36.243 (anantes-651-1-49-net.w2-0.abo.wanadoo.fr) ACTIVE

    Client配置

    vim /etc/fdfs/client.conf
    
    修改配置如下:
    #
    base_path=/opt/apps/fastdfs/client
    #tracker服務器IP和端口
    tracker_server=192.168.0.1:22122 
    
    上傳一個圖片測試是否能上傳成功
     fdfs_upload_file /etc/fdfs/client.conf test.jpg
    

    test.jpg 是測試本地上傳的圖片,路徑請填寫正確

    3、安裝Nginx和 fastdfs-nginx-module

    #解壓fastdfs-nginx-module
    tar -zxvf fastdfs-nginx-module-1.21.tar.gz
    cd fastdfs-nginx-module-1.21/
    cp ./src/mod_fastdfs.conf /etc/fdfs
    #解壓nginx
    tar -zxvf nginx-1.16.1.tar.gz
    cd nginx-1.16.1/
    #安裝nginx_http_image_filter_module
    yum -y install gd-devel
    yum -y install zlib zlib-devel openssl openssl--devel pcre pcre-devel
    #添加模塊
    ./configure --add-module=../fastdfs-nginx-module-1.21/src --prefix=/usr/local/nginx --with-http_image_filter_module 
    #編譯nginx
    make
    #安裝nginx
    make install
    

    查看是否安裝成功

    /usr/local/nginx/sbin/nginx -V
    

    查看插件是否安裝成功

    [root@FastDFS nginx-1.16.1]# /usr/local/nginx/sbin/nginx -V
    nginx version: nginx/1.16.1
    built by gcc 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC) 
    configure arguments: --add-module=../fastdfs-nginx-module-1.21/src --prefix=/usr/local/nginx --with-http_image_filter_module
    [root@FastDFS nginx-1.16.1]# 
    

    修改Nginx訪問

    vim /etc/fdfs/mod_fastdfs.conf

    修改配置如下:

    #
    connect_timeout=10
    #tracker服務器IP和端口
    tracker_server=192.168.0.1:22122
    #是否啟用group組名
    url_have_group_name=true
    #
    store_path0=/opt/fastdfs/storepath0

    修改Nginx配置:

    vim /usr/local/nginx/conf/nginx.conf
    

    修改配置如下:

    server {
        listen       80;
        server_name  localhost;
    
        #charset koi8-r;
    
        #access_log  logs/host.access.log  main;
    
        location / {
            root   html;
            index  index.html index.htm;
        }
        #圖片帶壓縮訪問
        location ~ /group1/M00/(.*)\.(jpg|gif|png)!format=([0-9]+)_([0-9]+) {
            alias  /home/fastdfs/storage/data/;
            ngx_fastdfs_module;
            set $w $3;
            set $h $4;
    
            rewrite group1/M00(.+)\.(jpg|gif|png)!format=([0-9]+)_([0-9]+)$ group1/M00$1.$2 break;
    
            image_filter resize $w $h;
            image_filter_buffer 5M;
        }
        #主圖訪問
        location ~ /group([0-9])/M00/(.+)\.?(.+) {
            alias /home/fastdfs/storage/data/;
            ngx_fastdfs_module;
        }
    ...
    }
    

    啟動Nginx

    #啟動
    /usr/local/nginx/sbin/nginx
    #停止
    /usr/local/nginx/sbin/nginx -s stop
    #重啟
    /usr/local/nginx/sbin/nginx -s reload

    通過以上配置完成FastDFS的搭建。

    測試圖片訪問

    圖片訪問示例:

    主圖訪問

    http://218.2.204.124:30308/group1/M00/00/03/BgAk813IvTCAIxxxAAD44NFKFPc908.png

    壓縮圖片 (主圖后加 !format=寬度_高度)訪問

    http://218.2.204.124:30308/group1/M00/00/03/BgAk813IvTCAIxxxAAD44NFKFPc908.png!format=400_10

    未解決的問題

    壓縮圖片使用主圖后?format=寬度_高度

    本文由博客一文多發平台 發布!

    再次感謝!!! 您已看完全文,歡迎關注微信公眾號猿碼 ,你的支持是我持續更新文章的動力!

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※教你寫出一流的銷售文案?