잊지 않겠습니다.

전에 한번 정리한 소스를 한번 정리해보는 내용으로...

Marin과 Medic, FIrebet.. 이 3개의 unit가 존재를 하고, 이 unit은 Attack과 Move라는 기본 동작을 갖는다.
Move라는 동작은 모든 Unit이 동일한 동작을 할 수 있지만, Attack 방법은 각기 다르고, 기본적으로 Attack이라는 Method를
갖지만 내부 구현이 다른 동작이 되게 된다. 

따라서, 각기 다른 동작을 구현하는 Class를 따로 뽑아내서 구현하는 Strategy Pattern이 사용 가능하다. 

먼저, 각기 다른 Attack에 대한 동작을 구현하는 Rifle, Firebazuka, Heal Class를 구현한다.

class Rifle : IAttack
{
    #region IAttack Members

    public string Attack()
    {
        return "dddd...";
    }

    #endregion
}

public class Firebazuka : IAttack
{
    #region IAttack Members

    public string Attack()
    {
        return "Fire!!...............";
    }

    #endregion
}

public class Heal : IAttack
{
    #region IAttack Members

    public string Attack()
    {
        return "Heal... ";
    }

    #endregion
}
그리고, 이 Attack Method의 IAttack을 인자로 갖는 BaseUnit class를 만들어준다. 
BaseUnit은 각 Unit의 parent class가 된다. 

class Runner : IMove
{
    #region IMove Members

    public string MoveTo(string direction)
    {
        return String.Format("To :{0}, Move it!", direction);
    }

    #endregion
}

public abstract class BaseUnit
{
    protected IAttack attackMethod;
    protected IMove moveMethod;

    protected BaseUnit()
    {
        
    }

    protected BaseUnit(IAttack attackMethod, IMove moveMethod)
    {
        this.attackMethod = attackMethod;
        this.moveMethod = moveMethod;
    }

    public virtual String Attack()
    {
        return attackMethod.Attack();
    }

    public virtual String MoveTo(String direction)
    {
        return moveMethod.MoveTo(direction);
    }
}
이렇게 구성된 BaseUnit을 이용해서 Marin, Firebet, Medic을 구현해준다. 구현된 코드는 다음과 같다.


public class Marin : BaseUnit
{
    public Marin() : base(new Rifle(), new Runner())
    {
        
    }
}
public class Firebet : BaseUnit
{
    public Firebet() : base(new Firebazuka(), new Runner())
    {
        
    }
}
public class Medic : BaseUnit
{
    public Medic() : base(new Heal(), new Runner())
    {
        
    }
}
구현된 Class를 이용해서 Test Code를 작성하면 다음과 같다. 

//Marin, Medic, Firebet의 class 생성
BaseUnit unit1 = new Marin();
BaseUnit unit2 = new Marin();
BaseUnit unit3 = new Medic();
BaseUnit unit4 = new Firebet();

//BaseUnit으로 Attack, MoveTo를 모두 구현
Console.WriteLine(unit1.Attack());
Console.WriteLine(unit2.Attack());
Console.WriteLine(unit3.Attack());
Console.WriteLine(unit4.Attack());

Console.WriteLine(unit1.MoveTo("Direction"));
Console.WriteLine(unit2.MoveTo("Direction"));
Console.WriteLine(unit3.MoveTo("Direction"));
Console.WriteLine(unit4.MoveTo("Direction"));
Strategy Pattern은 같은 Interface에서 각각 다른 동작을 하는 class들을 구현하는 방법으로, 
Method의 주체가 되는 Rifle, Firebazuk, Heal class의 구성이 관건이다. 다른 것을 객체화하라. 라는 
Design pattern의 성경같은 구절이 생각난다. 
Posted by Y2K
,
네트워크 상태를 보다보면 port의 사용 정보를 알고 싶을 때가 많은데...
사용되는 Port의 정보를 알려주는 site. 

정말 별애별 사이트가 다 있다는 증거.;

http://www.seifried.org/security/ports/index.php


Posted by Y2K
,
Hyper-V 에서 Network Usage와 Process Usage를 얻어내기 위해서 WMI 뒤지기 삽질. -_-

이번에 WMI를 보면서 많은 생각이 든 것이, MS가 참 대단하다는 생각이 든다. 정말 여러 데이터들을 잘 모아뒀다는 그런 느낌이라고 해야지 될까. 
먼저 Performance Counter에 사용되는 WMI 들은 Win32_PerfFormattedData_, Win32_PerfRawData_ 두가지로 나뉘어진다. 이 두개의 데이터의 차이는 좀 더 알아보기 쉽게 변형된 데이터와 Raw Data의 차이를 가지고 있다. 예를 들어 Network Usage의 경우 FormattedData의 경우에는 Bytes/sec의 정보가 나온다. 그렇지만 Raw Data는 Bytes의 누적값으로 표현이 된다. 이렇게 약간약간 다른 값들이 있기 때문에, 좀 더 세밀하게 볼 필요성이 있다. 

뭐.. 바로 본론으로 들어가면, 필요한 WMI 정보와 WMI를 얻어내는데 필요한 Helper Class를 먼저 제작해줬다. 


public class WmiHelper
{
    private readonly ConnectionOptions _connectionOptions;
    public WmiHelper()
    {
        _connectionOptions = new ConnectionOptions()
                                {
                                    Impersonation = ImpersonationLevel.Impersonate,
                                    Username = Configure.UserName,
                                    Password = Configure.Password,
                                    Authentication = AuthenticationLevel.Default,
                                    EnablePrivileges = true

                                };
    }

    protected ManagementObject GetManagementSingleObject(string wmiQuery, string wmiNamespace)
    {
        ManagementScope scope = new ManagementScope(wmiNamespace, _connectionOptions);
        try
        {
            scope.Connect();
            ObjectQuery query = new ObjectQuery(wmiQuery);
            using(ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
            {
                ManagementObjectCollection queryCollection = searcher.Get();
                return GetFirsManagementObject(queryCollection);
            }
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
            return null;
        }
    }

    protected ManagementObjectCollection GetManagementCollection(string wmiQuery, string wmiNamespace)
    {
        ManagementScope scope = new ManagementScope(wmiNamespace, _connectionOptions);
        try
        {
            scope.Connect();
            ObjectQuery query = new ObjectQuery(wmiQuery);
            using(ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
            {
                ManagementObjectCollection queryCollection = searcher.Get();
                return queryCollection;
            }
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
            return null;
        }
    }

    protected ManagementObject GetFirsManagementObject(ManagementObjectCollection managementObjectCollection)
    {
        if(managementObjectCollection.Count == 0)
        {
            return null;
        }
        else
        {
            var enumerator = managementObjectCollection.GetEnumerator();
            enumerator.MoveNext();
            return (ManagementObject)enumerator.Current;
        }
    }
}
WmiHelper는 Connection과 WMI Query를 Execute, 얻어진 ManagementObject와 ObjectCollection 얻어오는 일을 담당한다.
이제 Hyper-V의 Network Usage와 CPU Usage를 얻어오는 PerformanceCounter Class의 내용은 다음과 같다. 

public class VirtualMachinePerformanceCounter : WmiHelper
{
    //public long NetworkReadBytes { get; private set; }
    //public long NetworkWriteBytes { get; private set; }
    //public double CpuUsage { get; private set; }

    private readonly string _vmName;
    private readonly string _hostName;

    public VirtualMachinePerformanceCounter(string vmName, string hostName)
    {
        _vmName = vmName;
        _hostName = hostName;
    }

    public NetworkBandwidth MonitorNetworkBandwidth()
    {
        string wmiNamespace = string.Format("\\\\{0}\\Root\\cimv2", _hostName);
        string vmComputerName = GetVirtualComputerSystemGuidName();
        string wmiQuery =
            string.Format(
                "SELECT * FROM Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter WHERE Name like \"%_{0}--%\"",
                vmComputerName);
 
        ManagementObject managementObject = GetManagementSingleObject(wmiQuery, wmiNamespace);
        if(managementObject != null)
        {
            string recevedBytesString = managementObject["BytesReceivedPersec"].ToString();
            string sentBytesString = managementObject["BytesSentPersec"].ToString();
            string totalBytesString = managementObject["BytesPersec"].ToString();

            NetworkBandwidth networkBandwidth = new NetworkBandwidth(long.Parse(totalBytesString),
                                                         long.Parse(recevedBytesString), long.Parse(sentBytesString));
            Console.WriteLine("{0}\t{1}\t{2}", totalBytesString, recevedBytesString, sentBytesString);
            return networkBandwidth;
        }
        else
        {
            return NetworkBandwidth.Empty;
        }
    }


    public CpuUsage MonitorCpuUsage()
    {
        /*
        Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor
        Frequency_PerfTime
        PercentGuestRunTime
        Timestamp_PerfTime
        */
        string wmiNamespace = string.Format("\\\\{0}\\Root\\cimv2", _hostName);
        string wmiQuery = string.Format("SELECT Frequency_PerfTime,PercentGuestRunTime, Timestamp_PerfTime " +
                                        "FROM Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor " +
                                        "WHERE Name like \"{0}:%\"", _vmName);

        ManagementObjectCollection preManagementObjects = GetManagementCollection(wmiQuery, wmiNamespace);
        
        int logicalProcessCount = preManagementObjects.Count;

        if(logicalProcessCount == 0)
        {
            return CpuUsage.Empty;
        }
        else
        {
            ManagementObject m1 = GetFirsManagementObject(preManagementObjects);
            long frequencyPerfTime = long.Parse(m1["Frequency_PerfTime"].ToString());

            long percentGuestRunTime1 = long.Parse(m1["PercentGuestRunTime"].ToString());
            long timestampPerfTime1 = long.Parse(m1["Timestamp_PerfTime"].ToString());

            System.Threading.Thread.Sleep(1000);

            ManagementObject m2 = GetManagementSingleObject(wmiQuery, wmiNamespace);
            long percentGuestRunTime2 = long.Parse(m2["PercentGuestRunTime"].ToString());
            long timestampPerfTime2 = long.Parse(m2["Timestamp_PerfTime"].ToString());

            CpuUsage usage = new CpuUsage()
                                 {
                                     LogicalProcessCount = logicalProcessCount,
                                     FrequencyPerfTime = frequencyPerfTime,
                                     GuestRunTime1 = percentGuestRunTime1,
                                     GuestRunTime2 = percentGuestRunTime2,
                                     TimeStampPerTime1 = timestampPerfTime1,
                                     TimeStampPerTime2 = timestampPerfTime2
                                 };

            return usage;
        }
    }

    private string GetVirtualComputerSystemGuidName()
    {
        string wmiNamespace = string.Format("\\\\{0}\\Root\\virtualization", _hostName);
        string wmiQuery = string.Format("SELECT * FROM Msvm_ComputerSystem WHERE elementname = \"{0}\"", _vmName);

        ManagementObject managementObject = GetManagementSingleObject(wmiQuery, wmiNamespace);
        return (string)managementObject["Name"];
    }
}
간단히 코드 설명을 한다면, 

Network Usage는 Win32_PerfRawData_NvspNicStats_HyperVVirtualNetworkAdapter에서 얻어지는 값을 이용하면 된다. 
VM과 연관을 찾기 위해서는 root\virtualization에서 VirtualComputerSystem의 Name 값을 이용해서 like 검색을 하면 된다.

CPU Usage의 경우에는 http://blogs.msdn.com/tvoellm/archive/2008/07/14/how-to-get-processor-utilization-for-hyper-v-via-wmi.aspx를
참고.

* WmiHelper를 상속받는 것이 아닌, 아무래도 생성해서 Instance를 private로 들고 있는 것이 더 나았을 것 같다. 아무리 봐도.;
Posted by Y2K
,
indows에서 System의 모든 Monitoring은 WMI를 통해서 가능하다.
WMI를 이용하는 경우, Remote에서 접근이 용의하다는 장점과 Server군의 경우 다양한 속성들을 모두 Monitoring할 수 있다는 큰 장점을 가지고 있다. 또한, 기본적인 WMI의 Query를 통해서 값을 얻는 것이 아닌, .NET에서는 WMI에 대한 Event Handling이 가능하다. 

지정될 수 있는 Event는 http://msdn.microsoft.com/en-us/library/aa394583(VS.85).aspx을 참조.

모니터링 소스는 다음과 같다. 

ConnectionOptions connectionOptions = new ConnectionOptions()
     {
            Authentication = AuthenticationLevel.Default,
            Username = @"UserName",
            Password = @"Password",
            EnablePrivileges = true,
            Impersonation = ImpersonationLevel.Impersonate
      };
            
ManagementScope scope = new ManagementScope(@"\\hyperv\root\cimv2", connectionOptions);
scope.Connect();

//__InstanceCreationEvent : Wmi instance create event
//__InstanceModificationEvent : Wmi instance value modified event
//__InstanceDeletionEvent : Wmi instance delete event
//__InstanceOperationEvent : Wmi instance method call event

WqlEventQuery wQuery = new WqlEventQuery("Select * From __InstanceModificationEvent Within 1 " + "Where TargetInstance ISA 'Win32_PerfFormattedData_Tcpip_NetworkInterface'");

ManagementEventWatcher watcher = new ManagementEventWatcher(scope, wQuery);
watcher.EventArrived += new EventArrivedEventHandler(DisplayWatcherEvent);
watcher.Start();

Console.ReadLine();
            
watcher.Stop();

일반적인 Monitoring Handling과 동일하다. 특징이 나타나는 곳은 오히려 Event 처리기쪽이 더 특징이 나타난다.

private static void DisplayWatcherEvent(object sender, EventArrivedEventArgs e)
{
    foreach(var property in e.NewEvent.Properties)
    {
        if(property.Name == "TargetInstance")
        {
            ManagementBaseObject managementObject = property.Value as ManagementBaseObject;
            if (managementObject == null)
            {
                Console.WriteLine("Data convert is null");
            }
            else
            {
                var bytesPerSec = managementObject.Properties["BytesTotalPersec"].Value;
                var bytesReceivedPersec = managementObject.Properties["BytesReceivedPersec"].Value;
                var bytesSentPersec = managementObject.Properties["BytesSentPersec"].Value;
                string name = managementObject.Properties["Name"].Value.ToString();

                Console.WriteLine("{0}\t{1}\t{2}\t{3}", 
                    name.Substring(0, 4), bytesPerSec, bytesReceivedPersec, bytesSentPersec);
            }
        }
    }
}
특징으로 보이는 것이 EventArrivedEventArgs에서 Property의 Value형태로 WMI Instance의 값이 전달된다는 점이다. 그리고, Performance Counter의 경우에는 이전값, 현재값이 Property의 Name으로 전달되기 때문에 Diff. Monitoring에도 용의하다. 


Posted by Y2K
,

MS SQL Query Script

.NET Framework 2009. 7. 13. 15:37

[System.Reflection.Assembly]::LoadWithPartialName("System")
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Reflection.Assembly]::LoadWithPartialName("System.Data")

$fileContexts = [System.IO.File]::ReadAllLines("c:\mailStore.txt")
$connection = New-Object System.Data.SqlClient.SqlConnection("==THIS IS CONNECTION STRING==");

foreach($fileContext in $fileContexts) {
    $samAccount = $fileContext.Replace("name: ", "").Replace("@mailpush.co.kr", "")
       
    $connection.Open()
    $command = New-Object System.Data.SqlClient.SqlCommand;
    $command.Connection = $connection
    $command.CommandText = "SELECT PhoneNumber, Email From Product WHERE LogonName = '" + $samAccount + "'" + " and ProductStateId = 1"
    $reader = $command.ExecuteReader()

    while($reader.Read())
    {
        $reader.GetSqlString(0).ToString() + "`t" + $reader.GetSqlString(1).ToString() >> c:\output1.txt
    }
    $reader.Close()
    $connection.Close()   
}
[System.Windows.Forms.MessageBox]::Show("Complete!")
notepad.exe "c:\output1.txt"


재미있는 것은 .NET쪽 코드랑 별 다를 것이 없는 코드를 내가 작성하고 있다는 것이다. -_-


Posted by Y2K
,
RSS Feed Script
([xml](new-object System.Net.WebClient).DownloadString("http://blogs.msdn.com/powershell/rss.aspx")).rss.channel.item | format-table title,link


FAST Windows Form
[void][reflection.assembly]::LoadWithPartialName("System.Windows.Forms")
$form = new-object Windows.Forms.Form
$form.Text = "My First Form"
$button = new-object Windows.Forms.Button $button.text="Push Me!"
$button.Dock="fill"
$button.add_click({$form.close()})
$form.controls.add($button)
$form.Add_Shown({$form.Activate()})
$form.ShowDialog()

:여기서 중요한 코드는 첫줄. Assembly의 동적 Loading이 저렇게 쉽게 가능하다는 것이 가장 멋진 일이다.

ERROR LOG FINDER
dir $env:windir\*.log | select-string -list error | format-table path,linenumber –autosize
Posted by Y2K
,

TMAX Windows

시끌벅적 2009. 7. 8. 01:38
예비군 훈련중에도 너무 궁금해서 친구에게 문자로 생중계를 부탁해서 현장 분위기를 계속해서 듣고 있었다. 
듣다가 너무나 황당해서.. -_-

개인적으로는 정말 경멸하는 회사가 TMAX이다. 
이 회사는 사람을 사람으로 보지를 않는다. 사람을 부품보다 못한 존재로 만들어버린다.
당당하게.. 이거 개발하다가 개발자중에서 두명이 이혼했어요. 여자친구랑 깨졌어요. 를 이야기하는 정신나간 기업인이 어디에 있는지 모르겠다. 아니.. 솔찍히 그 생각이 우리나라 기업인들의 마인드라면.. 우리나라는 이제 망한거다. 

자신의 회사의 구성원들의 사생활과 개인생활을 망가트리고나서 그게 자랑스럽다고 이야기하는 그 어투란..
증오스럽다. 

황우석때와 마찬가지로 월화수목금금금을 외치는 기업. 
취업되고 나면 친구 및 가족들하고 연락이 단절되는 기업.
모든 단가를 반으로 후려쳐버려서 우리나라 IT의 정당한 가격도 받지 못하게 해버린 기업.
배낀 프레임워크가지고 자신의 기술이라고 떠들어대고 있는 기업. 

소송에서도 밀렸고, 이번 TMAX Windows의 경우에도 Open Source 부분의 많은 저작권을 위반하고 있는 것이 눈에 보이고. 정말 반성과 자성이 조금은 필요한 기업이라고 생각된다. 하는 짓을 보면 지금 2MB랑 너무나 잘 어울려서 탈이지만. 

아. 그리고 TMAX Windows의 첫 고객이 2MB가 될거라고 하던데. 2MB는 일단 로그인을 못해요


Posted by Y2K
,
.NET 객체를 이용하는 PowerShell의 object들은 모두다 이용가능하지만, Powershell은 결정적으로 자신만의 .NET 객체를 만들지 못하는 단점을 가지고 있다.

그렇지만, 시스템 관리 및 MS에서 제공되는 대부분의 (SCVMM, Exchange, MS-SQL) 제품들은 Powershell에서 사용할 수 있는 방법 및 cmdlet을 제공하고 있고, 이를 이용하면 불편하게 시스템을 바닥까지 긁어가면서 개발을 하지 않아도 된다.

그리고, .NET 객체로 PowerShell을 이용해서 개발을 할 수 있는 방법을 역시 MS가 제공하고 있기 때문에.. PowerShell만 조금 알고, 약간의 개발을 한다면 손쉽게 PowerShell을 이용해서 시스템을 제어하는 프로그램을 만들어줄 수 도 있다.

PowerShell을 이용한 개발을 하기 위해서는 다음과 같은 절차가 이루어져야지 된다.

1. PowerShell Runspace를 정해준다.
2. 실행될 Script가 동작될 Pipeline을 만들어준다.
3. Command 생성
4. Pipeline을 통해서 Script를 invoke 시켜준다.


1. Runspace 생성
Runspace는 자신의 application이 동작할 system pool과 동일한 개념이다.
먼저 RunspaceConfiguration을 만들어준 후, 그 Configuration을 이용해서 Runspace를 만들어준다.

2. Pipeline 생성
Pipeline은 Powershell을 사용하면 쉽게 알 수 있는 하나의 cmdlet이 실행될 때, 그에 대한 output의 연결 통로이다. 예를 들어, 아래와 같은 script가 실행이 되었을때,
get-service에서 얻어지는 모든 객체를 ForEach-Object 구문으로 전달하게 되는 것이 get-service 명령어가 종료된 이후에 pipeline을 통해서 전달되게 된다. Pipeline의 생성 구문은 다음과 같다. IDispose Interface를 상속받고 있기 때문에 using을 사용하는 것이 code가 깔끔해진다.

3. Command 생성
이제 판을 벌인 상태이고, 여기에서 굿을 보던 떡을 팔던 할 차례이다. cmdlet을 Command로 만들어주고, 그 cmdlet의 parameter를 각각 넣어주면 된다. 여기에서 재미있는 점중 하나가.. 일반적으로 get-service "SMS" 라고 넣어주면 되었던 것들이 get-service -name "SMS" 라는 식으로 full name으로 들어가져야지 된다는 것이다. Name이 없이 넣는 방법은 못찾겠다. ;;

재미있는 것이 pipeline에 여러 command를 넣는 것이 가능하다는 것이다. 여러 command를 넣어서 여러 작업을 동시에 automation을 시킬때 편리할 듯 싶다.

4. Pipeline Invoke
Invoke를 통해서 실행을 하고 그 return 값을 받는데.. 이 받는 과정이 조금 재미있다. PowerShell은 .NET 을 이용한다. 따라서, 이 Invoke의 Return값도 .NET 객체 또는 Wmi Script의 결과가 나오게 되는데. .NET만이 나온다면 System.Object를 사용하면 될 것 같은데.. WMI Object 역시 지원하고 있기 때문에 PSObject라는 약간 생뚱 맞은 Object가 튀어나오게 된다. PSObject에서 ImmediateObject Property를 이용해서 .NET Object로 casting을 해줘서 .NET에서 사용해줘도 되고, 그냥 일반적으로 PSObject.ToString()을 호출해주면 PowerShell에서 나오는 결과와 동일한 결과를 나타나게된다.

casting을 시켜줄때가 가장 문제인것 같은데.;;


Posted by Y2K
,
LVS를 이용해서 Load Balancer를 구성할때 Direct Routing, NAT, Tunneling 방식으로 3가지 방식으로 사용될 수 있는데, 각 3가지 방법은 다음과 같은 차이를 가지고 있다.

1. Direct Routing
LVS에 VIP를 설정, VIP를 통해서 Node단에 Network Load 전송

* LVS
- eth0 에 자신의 private ip가 eth0:1에 VIP가 설정되는 식으로 VIP와 private ip를 모두 갖는다.
* Node
- loopback devicde(lo)에 LVS의 VIP가 설정되어야지 된다.
: IP Diagram에 자신이 처리해야지 되는 연결임을 알 수 있도록 설정되어야지 된다.

2. NAT
- 조금 특이한 형태. Input/output이 모두 LVS를 통해서 나가게 된다.
- 20대 이상의 대규모 네트워크에 매우 불리하다.

* LVS
- 반드시 2개 이상의 network adapter가 필요하다.
- 1개는 public ip로 연결, 나머지 1개는 private ip로 연결된다.
* Node
- private ip가 반드시 있어야지 된다. (public ip는 필요 없다.)
- private ip의 gateway에 LVS의 private ip가 설정된다.
: Network input/output이 모두 NAT를 통해서 나가게 되기 때문에 gateway를 모두 같이 맞춰줄 필요가 있다.
: IP class에 따라 제한이 될 수 있다.

3. Tunneling
- IP Diagram 변경을 통해 Network Load가 전송된다.

* LVS
- 특별하게 지정해줄 필요 없다. ipvsadm 명령어 옵션만 다를 뿐이다.
* Node
- tunl0 라는 network 가상 device를 추가해주고, LVS의 private ip로 연결되어야지 된다.
: LVS와 node간의 연결 통로를 미리 지정해주게 된다. 그리고, 이 곳에서 온 자신에 대한 네트워크 연결은 Tunneling으로 온 것으로 판단하고, 들어온 입력이 아닌, ip diagram에 있는 정보를 이용해서 return 시켜주게 된다.


결론
네트워크 시스템을 어떻게 구성할지를 고민해야지 될듯. 모든 Network에 대한 감시가 필요하고, LVS를 좋은 녀석으로 구성한다면 NAT가 가장 최선의 방법이 될 수도 있지만, 이는 LVS 에 엄청난 부하를 줄 수 있기 때문에 가장 많이 사용되는 것은 Direct Routing 방법. 그렇지만, Node에 따로 설정을 해줘야지 된다는 것은 부담으로 남는다.


Posted by Y2K
,
http://www.okjsp.pe.kr/seq/140133

jQuery의 경우 내가 이번년도에 본 내용중에서 가장 쇼킹한 녀석이였는데...
강의마저 나를 쇼킹하게 만들고 있다. -_-
Posted by Y2K
,